mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 03:54:24 +01:00
Add support to localize package.json
This commit is contained in:
@@ -11,14 +11,96 @@ import {TPromise} from 'vs/base/common/winjs.base';
|
||||
import {groupBy, values} from 'vs/base/common/collections';
|
||||
import paths = require('vs/base/common/paths');
|
||||
import json = require('vs/base/common/json');
|
||||
import Types = require('vs/base/common/types');
|
||||
import {IPluginsMessageCollector} from 'vs/platform/plugins/common/pluginsRegistry';
|
||||
import {isValidPluginDescription} from 'vs/platform/plugins/node/pluginVersionValidator';
|
||||
import * as semver from 'semver';
|
||||
|
||||
const MANIFEST_FILE = 'package.json';
|
||||
|
||||
const devMode = !!process.env['VSCODE_DEV'];
|
||||
interface NlsConfiguration {
|
||||
locale: string;
|
||||
pseudo: boolean;
|
||||
}
|
||||
const nlsConfig = function(): NlsConfiguration {
|
||||
if (process.env['VSCODE_NLS_CONFIG']) {
|
||||
try {
|
||||
return JSON.parse(process.env['VSCODE_NLS_CONFIG']);
|
||||
} catch (err) {
|
||||
return {
|
||||
locale: undefined,
|
||||
pseudo: true
|
||||
};
|
||||
}
|
||||
}
|
||||
}();
|
||||
|
||||
export class PluginScanner {
|
||||
|
||||
private static findMessageBundle(basename: string): TPromise<string> {
|
||||
return new TPromise<string>((c ,e, p) => {
|
||||
function loop(basename: string, locale: string): void {
|
||||
let toCheck = `${basename}.nls.${locale}.json`;
|
||||
pfs.fileExists(toCheck).then(exists => {
|
||||
if (exists) {
|
||||
c(toCheck);
|
||||
}
|
||||
let index = locale.lastIndexOf('-');
|
||||
if (index === -1) {
|
||||
c(`${basename}.nls.json`);
|
||||
} else {
|
||||
locale = locale.substring(0, index);
|
||||
loop(basename, locale);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (devMode || nlsConfig.pseudo || !nlsConfig.locale) {
|
||||
return c(basename + '.nls.json');
|
||||
}
|
||||
loop(basename, nlsConfig.locale);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine make the following assumptions:
|
||||
* The root element is a object literal
|
||||
* Strings to replace are one values of a key. So for example string[] are ignored.
|
||||
* This is done to speed things up.
|
||||
*/
|
||||
private static replaceStrings<T>(literal: T, messages: { [key: string]: string; }): void {
|
||||
Object.keys(literal).forEach(key => {
|
||||
if (literal.hasOwnProperty(key)) {
|
||||
let value = literal[key];
|
||||
if (Types.isString(value)) {
|
||||
let str = <string>value;
|
||||
let length = str.length;
|
||||
if (length > 1 && str[0] === '%' && str[length - 1] === '%') {
|
||||
let messageKey = str.substr(1, length - 2);
|
||||
let message = messages[messageKey];
|
||||
if (message) {
|
||||
if (nlsConfig.pseudo) {
|
||||
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
|
||||
message = '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
|
||||
}
|
||||
literal[key] = message;
|
||||
}
|
||||
}
|
||||
} else if (Types.isObject(value)) {
|
||||
PluginScanner.replaceStrings(value, messages);
|
||||
} else if (Types.isArray(value)) {
|
||||
(<any[]>value).forEach(element => {
|
||||
if (Types.isObject(element)) {
|
||||
PluginScanner.replaceStrings(element, messages);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scan the plugin defined in `absoluteFolderPath`
|
||||
*/
|
||||
@@ -53,7 +135,32 @@ export class PluginScanner {
|
||||
pluginDescFromFile.activationEvents.push('onLanguage:javascriptreact');
|
||||
}
|
||||
}
|
||||
return pluginDescFromFile;
|
||||
|
||||
let extension = paths.extname(absoluteManifestPath);
|
||||
let basename = absoluteManifestPath.substr(0, absoluteManifestPath.length - extension.length);
|
||||
return pfs.fileExists(basename + '.nls' + extension).then(exists => {
|
||||
if (!exists) {
|
||||
// To make the compiler happy. This is not necessary from a runtime perspective.
|
||||
return TPromise.as<IPluginDescription>(pluginDescFromFile);
|
||||
}
|
||||
return PluginScanner.findMessageBundle(basename).then(messageBundle => {
|
||||
if (!messageBundle) {
|
||||
return pluginDescFromFile;
|
||||
}
|
||||
return pfs.readFile(messageBundle).then(messageBundleContent => {
|
||||
let errors: string[] = [];
|
||||
let messages: { [key: string]: string; } = json.parse(messageBundleContent.toString(), errors);
|
||||
if (errors.length > 0) {
|
||||
errors.forEach((error) => {
|
||||
builder.error('Failed to parse ' + messageBundle + ': ' + error);
|
||||
});
|
||||
return pluginDescFromFile;
|
||||
}
|
||||
PluginScanner.replaceStrings(pluginDescFromFile, messages);
|
||||
return pluginDescFromFile;
|
||||
});
|
||||
});
|
||||
});
|
||||
}).then((pluginDescFromFile) => {
|
||||
if (pluginDescFromFile === null) {
|
||||
return null;
|
||||
|
||||
Reference in New Issue
Block a user