Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,21 @@

## String Localization

* [vscode-nls](https://github.com/microsoft/vscode-nls) is used to localize strings in TypeScript code. To use [vscode-nls](https://github.com/microsoft/vscode-nls), the source file must contain:
* VS Code's built-in [l10n](https://code.visualstudio.com/api/references/vscode-api#l10n) support is used to localize strings in TypeScript code. The English string itself is the key, so no separate setup or import is required beyond `vscode`:
```typescript
import * as nls from 'vscode-nls';

nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
import * as vscode from 'vscode';
```
* For each user-facing string, wrap the string in a call to `vscode.l10n.t`:
```typescript
const readmeMessage: string = vscode.l10n.t("Please refer to {0} for troubleshooting information. Issues can be created at {1}", readmePath, "https://github.com/Microsoft/vscode-cpptools/issues");
```
* For each user-facing string, wrap the string in a call to localize:
* The first parameter is the string to localize, and it must be a string literal. Tokens such as {0} and {1} are supported in the localizable string, with replacement values passed as additional parameters (these may be strings, numbers, or booleans).
* When a translator needs a hint about how to translate a string, use the object form, which takes a required `comment` and an optional `args` array:
```typescript
const readmeMessage: string = localize("refer.read.me", "Please refer to {0} for troubleshooting information. Issues can be created at {1}", readmePath, "https://github.com/Microsoft/vscode-cpptools/issues");
const message: string = vscode.l10n.t({ message: "Add '{0}'", args: [code], comment: ["{0} is C++ code to add, such as '#include <string>'"] });
```
* The first parameter to localize should be a unique key for that string, not used by any other call to localize() in the file unless representing the same string. The second parameter is the string to localize. Both of these parameters must be string literals. Tokens such as {0} and {1} are supported in the localizable string, with replacement values passed as additional parameters to localize().
* At build time, [@vscode/l10n-dev](https://github.com/microsoft/vscode-l10n) scans the source for these calls and produces `./l10n/bundle.l10n.json` (and per-language `./l10n/bundle.l10n.<language>.json` files). The `"l10n": "./l10n"` field in [**package.json**](Extension/package.json) tells VS Code where to load them. VS Code loads the bundle for the active display language, so the strings are not read synchronously at extension startup.


## Contributor License Agreement

Expand Down
5 changes: 3 additions & 2 deletions Extension/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ install.lock
# ignore vscode test
.vscode-test/

# ignore generated localization file
**/nls.*.json
# ignore generated localization files
**/*.nls.*.json
l10n/bundle.l10n.json
l10n/bundle.l10n.*.json

# ignore generate native header
localized_string_ids.h
Expand Down
8 changes: 4 additions & 4 deletions Extension/.scripts/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export async function checkPrep() {
failing = !await assertAnyFolder('dist/walkthrough') && (quiet || warn(`The walkthrough files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/html') && (quiet || warn(`The html files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/schema') && (quiet || warn(`The schema files are not in place.`)) || failing;
failing = !await assertAnyFile('dist/nls.metadata.json') && (quiet || warn(`The extension translation file '${$root}/dist/nls.metadata.json is missing.`)) || failing;
failing = !await assertAnyFile('l10n/bundle.l10n.json') && (quiet || warn(`The extension localization bundle '${$root}/l10n/bundle.l10n.json' is missing.`)) || failing;
failing = await checkDTS() || failing;

if (!failing) {
Expand All @@ -317,7 +317,7 @@ export async function checkPrep() {
export async function checkCompiled() {
let failing = false;
failing = await checkDTS() || failing;
failing = !await assertAnyFile('dist/src/main.js') && (quiet || warn(`The extension entry point '${$root}/dist/src/main.js is missing.`)) || failing;
failing = !await assertAnyFile('dist/src/main.js') && (quiet || warn(`The extension entry point '${$root}/dist/src/main.js' is missing.`)) || failing;

if (!failing) {
verbose('Compiled files appear to be in place.');
Expand All @@ -327,8 +327,8 @@ export async function checkCompiled() {

export async function checkDTS() {
let failing = false;
failing = !await assertAnyFile('vscode.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.d.ts is missing.`)) || failing;
failing = !await assertAnyFile('vscode.proposed.terminalDataWriteEvent.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.proposed.terminalDataWriteEvent.d.ts is missing.`)) || failing;
failing = !await assertAnyFile('vscode.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.d.ts' is missing.`)) || failing;
failing = !await assertAnyFile('vscode.proposed.terminalDataWriteEvent.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.proposed.terminalDataWriteEvent.d.ts' is missing.`)) || failing;

if (!failing) {
verbose('VSCode d.ts files appear to be in place.');
Expand Down
22 changes: 9 additions & 13 deletions Extension/.scripts/generateNativeStrings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,23 +47,22 @@ export async function main() {
}
typeScriptSwitchContent += ` case ${stringIndex}:\n`;
if (numArgs !== 0) {
const stringArgsList: string[] = [];
for (let i = 0; i < numArgs; i++) {
stringArgsList.push(`stringArgs[${i}]`);
}
typeScriptSwitchContent += ` if (stringArgs) {\n`;
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
typeScriptSwitchContent += ` message = l10n.t({ message: ${JSON.stringify(stringValue)}, args: [${stringArgsList.join(", ")}], comment: [${JSON.stringify(hintValue)}] });\n break;\n }\n`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
typeScriptSwitchContent += ` message = l10n.t(${JSON.stringify(stringValue)}, ${stringArgsList.join(", ")});\n break;\n }\n`;
}
for (let i = 0; i < numArgs; i++) {
typeScriptSwitchContent += `, stringArgs[${i}]`;
}
typeScriptSwitchContent += `);\n break;\n }\n`;
}
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
typeScriptSwitchContent += ` message = l10n.t({ message: ${JSON.stringify(stringValue)}, comment: [${JSON.stringify(hintValue)}] });\n break;\n`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
typeScriptSwitchContent += ` message = l10n.t(${JSON.stringify(stringValue)});\n break;\n`;
}
typeScriptSwitchContent += `);\n break;\n`;
}
++stringIndex;
}
Expand All @@ -81,10 +80,7 @@ export async function main() {

'use strict';

import * as nls from 'vscode-nls';

nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
import { l10n } from 'vscode';

export const localizedStringCount: number = ${stringIndex};

Expand Down
Loading
Loading