Add support to localize package.json

This commit is contained in:
Dirk Baeumer
2016-02-12 16:06:34 +01:00
parent 1e09b7d7ad
commit 90dce6abea
6 changed files with 125 additions and 9 deletions

View File

@@ -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;