Bring the nls loader plugin into our sources (#152338)

This commit is contained in:
Alexandru Dima 2022-06-16 22:01:19 +02:00 committed by GitHub
parent 5d9717967d
commit 9db5a3674e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 339 additions and 430 deletions

View File

@ -26,7 +26,5 @@
**/src/vs/*/**/*.d.ts
**/src/vs/base/test/common/filters.perf.data.js
**/src/vs/loader.js
**/src/vs/nls.build.js
**/src/vs/nls.js
**/test/unit/assert.js
**/typings/**

View File

@ -576,7 +576,7 @@
"restrictions": []
},
{
"target": "src/vs/{loader.d.ts,css.ts,css.build.ts,monaco.d.ts,nls.d.ts,nls.mock.ts}",
"target": "src/vs/{loader.d.ts,css.ts,css.build.ts,monaco.d.ts,nls.ts,nls.build.ts,nls.mock.ts}",
"restrictions": []
},
{

View File

@ -66,8 +66,6 @@ module.exports.indentationFilter = [
'!**/LICENSE.{txt,rtf}',
'!LICENSES.chromium.html',
'!**/LICENSE',
'!src/vs/nls.js',
'!src/vs/nls.build.js',
'!src/vs/loader.js',
'!src/vs/base/browser/dompurify/*',
'!src/vs/base/common/marked/marked.js',

View File

@ -29,14 +29,17 @@ const editorEntryPoints = [
name: 'vs/editor/editor.main',
include: [],
exclude: ['vs/css', 'vs/nls'],
prepend: ['out-editor-build/vs/css.js', 'out-editor-build/vs/nls.js'],
prepend: [
{ path: 'out-editor-build/vs/css.js' },
{ path: 'out-editor-build/vs/nls.js', amdModuleId: 'vs/nls' }
],
},
{
name: 'vs/base/common/worker/simpleWorker',
include: ['vs/editor/common/services/editorSimpleWorker'],
exclude: ['vs/nls'],
prepend: ['vs/loader.js'],
append: ['vs/base/worker/workerMain'],
prepend: [{ path: 'vs/loader.js' }],
append: [{ path: 'vs/base/worker/workerMain' }],
dest: 'vs/base/worker/workerMain.js'
}
];
@ -110,9 +113,6 @@ const createESMSourcesAndResourcesTask = task.define('extract-editor-esm', () =>
'inlineEntryPoint:0.ts',
'inlineEntryPoint:1.ts',
'vs/loader.js',
'vs/nls.ts',
'vs/nls.build.js',
'vs/nls.d.ts',
'vs/base/worker/workerMain.ts',
],
renames: {

View File

@ -42,14 +42,17 @@ function bundle(entryPoints, config, callback) {
if (!config.paths['vs/css']) {
config.paths['vs/css'] = 'out-build/vs/css.build';
}
config.buildForceInvokeFactory = config.buildForceInvokeFactory || {};
config.buildForceInvokeFactory['vs/nls'] = true;
config.buildForceInvokeFactory['vs/css'] = true;
loader.config(config);
loader(['require'], (localRequire) => {
const resolvePath = (path) => {
const r = localRequire.toUrl(path);
const resolvePath = (entry) => {
const r = localRequire.toUrl(entry.path);
if (!/\.js/.test(r)) {
return r + '.js';
return { path: r + '.js', amdModuleId: entry.amdModuleId };
}
return r;
return { path: r, amdModuleId: entry.amdModuleId };
};
for (const moduleId in entryPointsMap) {
const entryPoint = entryPointsMap[moduleId];
@ -330,10 +333,13 @@ function emitEntryPoint(modulesMap, deps, entryPoint, includedModules, prepend,
plugin.writeFile(pluginName, entryPoint, req, write, {});
}
});
const toIFile = (path) => {
const contents = readFileAndRemoveBOM(path);
const toIFile = (entry) => {
let contents = readFileAndRemoveBOM(entry.path);
if (entry.amdModuleId) {
contents = contents.replace(/^define\(/m, `define("${entry.amdModuleId}",`);
}
return {
path: path,
path: entry.path,
contents: contents
};
};

View File

@ -42,12 +42,17 @@ interface ILoaderPluginReqFunc {
toUrl(something: string): string;
}
export interface IExtraFile {
path: string;
amdModuleId?: string;
}
export interface IEntryPoint {
name: string;
include?: string[];
exclude?: string[];
prepend?: string[];
append?: string[];
prepend?: IExtraFile[];
append?: IExtraFile[];
dest?: string;
}
@ -92,6 +97,13 @@ interface IPartialBundleResult {
export interface ILoaderConfig {
isBuild?: boolean;
paths?: { [path: string]: any };
/*
* Normally, during a build, no module factories are invoked. This can be used
* to forcefully execute a module's factory.
*/
buildForceInvokeFactory: {
[moduleId: string]: boolean;
};
}
/**
@ -132,15 +144,18 @@ export function bundle(entryPoints: IEntryPoint[], config: ILoaderConfig, callba
if (!config.paths['vs/css']) {
config.paths['vs/css'] = 'out-build/vs/css.build';
}
config.buildForceInvokeFactory = config.buildForceInvokeFactory || {};
config.buildForceInvokeFactory['vs/nls'] = true;
config.buildForceInvokeFactory['vs/css'] = true;
loader.config(config);
loader(['require'], (localRequire: any) => {
const resolvePath = (path: string) => {
const r = localRequire.toUrl(path);
const resolvePath = (entry: IExtraFile) => {
const r = localRequire.toUrl(entry.path);
if (!/\.js/.test(r)) {
return r + '.js';
return { path: r + '.js', amdModuleId: entry.amdModuleId };
}
return r;
return { path: r, amdModuleId: entry.amdModuleId };
};
for (const moduleId in entryPointsMap) {
const entryPoint = entryPointsMap[moduleId];
@ -403,8 +418,8 @@ function emitEntryPoint(
deps: IGraph,
entryPoint: string,
includedModules: string[],
prepend: string[],
append: string[],
prepend: IExtraFile[],
append: IExtraFile[],
dest: string | undefined
): IEmitEntryPointResult {
if (!dest) {
@ -478,10 +493,13 @@ function emitEntryPoint(
}
});
const toIFile = (path: string): IFile => {
const contents = readFileAndRemoveBOM(path);
const toIFile = (entry: IExtraFile): IFile => {
let contents = readFileAndRemoveBOM(entry.path);
if (entry.amdModuleId) {
contents = contents.replace(/^define\(/m, `define("${entry.amdModuleId}",`);
}
return {
path: path,
path: entry.path,
contents: contents
};
};

View File

@ -35,19 +35,25 @@ function loaderConfig() {
}
exports.loaderConfig = loaderConfig;
const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i;
function loaderPlugin(src, base, amdModuleId) {
return (gulp
.src(src, { base })
.pipe(es.through(function (data) {
if (amdModuleId) {
let contents = data.contents.toString('utf8');
contents = contents.replace(/^define\(/m, `define("${amdModuleId}",`);
data.contents = Buffer.from(contents);
}
this.emit('data', data);
})));
}
function loader(src, bundledFileHeader, bundleLoader, externalLoaderInfo) {
let sources = [
`${src}/vs/loader.js`
];
let loaderStream = gulp.src(`${src}/vs/loader.js`, { base: `${src}` });
if (bundleLoader) {
sources = sources.concat([
`${src}/vs/css.js`,
`${src}/vs/nls.js`
]);
loaderStream = es.merge(loaderStream, loaderPlugin(`${src}/vs/css.js`, `${src}`, 'vs/css'), loaderPlugin(`${src}/vs/nls.js`, `${src}`, 'vs/nls'));
}
let isFirst = true;
return (gulp
.src(sources, { base: `${src}` })
return (loaderStream
.pipe(es.through(function (data) {
if (isFirst) {
isFirst = false;

View File

@ -41,21 +41,34 @@ export function loaderConfig() {
const IS_OUR_COPYRIGHT_REGEXP = /Copyright \(C\) Microsoft Corporation/i;
function loaderPlugin(src: string, base: string, amdModuleId: string | undefined): NodeJS.ReadWriteStream {
return (
gulp
.src(src, { base })
.pipe(es.through(function (data: VinylFile) {
if (amdModuleId) {
let contents = data.contents.toString('utf8');
contents = contents.replace(/^define\(/m, `define("${amdModuleId}",`);
data.contents = Buffer.from(contents);
}
this.emit('data', data);
}))
);
}
function loader(src: string, bundledFileHeader: string, bundleLoader: boolean, externalLoaderInfo?: any): NodeJS.ReadWriteStream {
let sources = [
`${src}/vs/loader.js`
];
let loaderStream = gulp.src(`${src}/vs/loader.js`, { base: `${src}` });
if (bundleLoader) {
sources = sources.concat([
`${src}/vs/css.js`,
`${src}/vs/nls.js`
]);
loaderStream = es.merge(
loaderStream,
loaderPlugin(`${src}/vs/css.js`, `${src}`, 'vs/css'),
loaderPlugin(`${src}/vs/nls.js`, `${src}`, 'vs/nls'),
);
}
let isFirst = true;
return (
gulp
.src(sources, { base: `${src}` })
loaderStream
.pipe(es.through(function (data) {
if (isFirst) {
isFirst = false;

View File

@ -106,9 +106,8 @@ function extractEditor(options) {
'vs/css.ts',
'vs/loader.js',
'vs/loader.d.ts',
'vs/nls.build.js',
'vs/nls.d.ts',
'vs/nls.js',
'vs/nls.build.ts',
'vs/nls.ts',
'vs/nls.mock.ts',
].forEach(copyFile);
}

View File

@ -119,9 +119,8 @@ export function extractEditor(options: tss.ITreeShakingOptions & { destRoot: str
'vs/css.ts',
'vs/loader.js',
'vs/loader.d.ts',
'vs/nls.build.js',
'vs/nls.d.ts',
'vs/nls.js',
'vs/nls.build.ts',
'vs/nls.ts',
'vs/nls.mock.ts',
].forEach(copyFile);
}

View File

@ -33,8 +33,11 @@ exports.base = [
name: 'vs/editor/common/services/editorSimpleWorker',
include: ['vs/base/common/worker/simpleWorker'],
exclude: ['vs/nls'],
prepend: ['vs/loader.js', 'vs/nls.js'],
append: ['vs/base/worker/workerMain'],
prepend: [
{ path: 'vs/loader.js' },
{ path: 'vs/nls.js', amdModuleId: 'vs/nls' }
],
append: [{ path: 'vs/base/worker/workerMain' }],
dest: 'vs/base/worker/workerMain.js'
},
{

View File

@ -291,6 +291,9 @@ var AMDLoader;
if (typeof options.isBuild !== 'boolean') {
options.isBuild = false;
}
if (typeof options.buildForceInvokeFactory !== 'object') {
options.buildForceInvokeFactory = {};
}
if (typeof options.paths !== 'object') {
options.paths = {};
}
@ -536,6 +539,15 @@ var AMDLoader;
Configuration.prototype.isBuild = function () {
return this.options.isBuild;
};
Configuration.prototype.shouldInvokeFactory = function (strModuleId) {
if (!this.options.isBuild) {
// outside of a build, all factories should be invoked
return true;
}
// during a build, only explicitly marked or anonymous modules get their factories invoked
return (this.options.buildForceInvokeFactory[strModuleId]
|| AMDLoader.Utilities.isAnonymousModule(strModuleId));
};
/**
* Test if module `moduleId` is expected to be defined multiple times
*/
@ -1171,7 +1183,7 @@ var AMDLoader;
}
};
Module._invokeFactory = function (config, strModuleId, callback, dependenciesValues) {
if (config.isBuild() && !AMDLoader.Utilities.isAnonymousModule(strModuleId)) {
if (!config.shouldInvokeFactory(strModuleId)) {
return {
returnedValue: null,
producedError: null

View File

@ -1,182 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
* Please make sure to make edits in the .ts file at https://github.com/microsoft/vscode-loader/
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*--------------------------------------------------------------------------------------------*/
'use strict';
var _nlsPluginGlobal = this;
var NLSBuildLoaderPlugin;
(function (NLSBuildLoaderPlugin) {
var global = (_nlsPluginGlobal || {});
var Resources = global.Plugin && global.Plugin.Resources ? global.Plugin.Resources : undefined;
var IS_PSEUDO = (global && global.document && global.document.location && global.document.location.hash.indexOf('pseudo=true') >= 0);
function _format(message, args) {
var result;
if (args.length === 0) {
result = message;
}
else {
result = message.replace(/\{(\d+)\}/g, function (match, rest) {
var index = rest[0];
return typeof args[index] !== 'undefined' ? args[index] : match;
});
}
if (IS_PSEUDO) {
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D';
}
return result;
}
function findLanguageForModule(config, name) {
var result = config[name];
if (result)
return result;
result = config['*'];
if (result)
return result;
return null;
}
function localize(data, message) {
var args = [];
for (var _i = 0; _i < (arguments.length - 2); _i++) {
args[_i] = arguments[_i + 2];
}
return _format(message, args);
}
function createScopedLocalize(scope) {
return function (idx, defaultValue) {
var restArgs = Array.prototype.slice.call(arguments, 2);
return _format(scope[idx], restArgs);
};
}
var NLSPlugin = /** @class */ (function () {
function NLSPlugin() {
this.localize = localize;
}
NLSPlugin.prototype.setPseudoTranslation = function (value) {
IS_PSEUDO = value;
};
NLSPlugin.prototype.create = function (key, data) {
return {
localize: createScopedLocalize(data[key])
};
};
NLSPlugin.prototype.load = function (name, req, load, config) {
config = config || {};
if (!name || name.length === 0) {
load({
localize: localize
});
}
else {
var suffix = void 0;
if (Resources && Resources.getString) {
suffix = '.nls.keys';
req([name + suffix], function (keyMap) {
load({
localize: function (moduleKey, index) {
if (!keyMap[moduleKey])
return 'NLS error: unknown key ' + moduleKey;
var mk = keyMap[moduleKey].keys;
if (index >= mk.length)
return 'NLS error unknown index ' + index;
var subKey = mk[index];
var args = [];
args[0] = moduleKey + '_' + subKey;
for (var _i = 0; _i < (arguments.length - 2); _i++) {
args[_i + 1] = arguments[_i + 2];
}
return Resources.getString.apply(Resources, args);
}
});
});
}
else {
if (config.isBuild) {
req([name + '.nls', name + '.nls.keys'], function (messages, keys) {
NLSPlugin.BUILD_MAP[name] = messages;
NLSPlugin.BUILD_MAP_KEYS[name] = keys;
load(messages);
});
}
else {
var pluginConfig = config['vs/nls'] || {};
var language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null;
suffix = '.nls';
if (language !== null && language !== NLSPlugin.DEFAULT_TAG) {
suffix = suffix + '.' + language;
}
req([name + suffix], function (messages) {
if (Array.isArray(messages)) {
messages.localize = createScopedLocalize(messages);
}
else {
messages.localize = createScopedLocalize(messages[name]);
}
load(messages);
});
}
}
}
};
NLSPlugin.prototype._getEntryPointsMap = function () {
global.nlsPluginEntryPoints = global.nlsPluginEntryPoints || {};
return global.nlsPluginEntryPoints;
};
NLSPlugin.prototype.write = function (pluginName, moduleName, write) {
// getEntryPoint is a Monaco extension to r.js
var entryPoint = write.getEntryPoint();
// r.js destroys the context of this plugin between calling 'write' and 'writeFile'
// so the only option at this point is to leak the data to a global
var entryPointsMap = this._getEntryPointsMap();
entryPointsMap[entryPoint] = entryPointsMap[entryPoint] || [];
entryPointsMap[entryPoint].push(moduleName);
if (moduleName !== entryPoint) {
write.asModule(pluginName + '!' + moduleName, 'define([\'vs/nls\', \'vs/nls!' + entryPoint + '\'], function(nls, data) { return nls.create("' + moduleName + '", data); });');
}
};
NLSPlugin.prototype.writeFile = function (pluginName, moduleName, req, write, config) {
var entryPointsMap = this._getEntryPointsMap();
if (entryPointsMap.hasOwnProperty(moduleName)) {
var fileName = req.toUrl(moduleName + '.nls.js');
var contents = [
'/*---------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
], entries = entryPointsMap[moduleName];
var data = {};
for (var i = 0; i < entries.length; i++) {
data[entries[i]] = NLSPlugin.BUILD_MAP[entries[i]];
}
contents.push('define("' + moduleName + '.nls", ' + JSON.stringify(data, null, '\t') + ');');
write(fileName, contents.join('\r\n'));
}
};
NLSPlugin.prototype.finishBuild = function (write) {
write('nls.metadata.json', JSON.stringify({
keys: NLSPlugin.BUILD_MAP_KEYS,
messages: NLSPlugin.BUILD_MAP,
bundles: this._getEntryPointsMap()
}, null, '\t'));
};
;
NLSPlugin.DEFAULT_TAG = 'i-default';
NLSPlugin.BUILD_MAP = {};
NLSPlugin.BUILD_MAP_KEYS = {};
return NLSPlugin;
}());
NLSBuildLoaderPlugin.NLSPlugin = NLSPlugin;
(function () {
define('vs/nls', new NLSPlugin());
})();
})(NLSBuildLoaderPlugin || (NLSBuildLoaderPlugin = {}));

68
src/vs/nls.build.ts Normal file
View File

@ -0,0 +1,68 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const buildMap: { [name: string]: string[] } = {};
const buildMapKeys: { [name: string]: string[] } = {};
const entryPoints: { [entryPoint: string]: string[] } = {};
export interface ILocalizeInfo {
key: string;
comment: string[];
}
export function localize(data: ILocalizeInfo | string, message: string, ...args: (string | number | boolean | undefined | null)[]): string {
throw new Error(`Not supported at build time!`);
}
export function load(name: string, req: AMDLoader.IRelativeRequire, load: AMDLoader.IPluginLoadCallback, config: AMDLoader.IConfigurationOptions): void {
if (!name || name.length === 0) {
load({ localize });
} else {
req([name + '.nls', name + '.nls.keys'], function (messages: string[], keys: string[]) {
buildMap[name] = messages;
buildMapKeys[name] = keys;
load(messages);
});
}
}
export function write(pluginName: string, moduleName: string, write: AMDLoader.IPluginWriteCallback): void {
const entryPoint = write.getEntryPoint();
entryPoints[entryPoint] = entryPoints[entryPoint] || [];
entryPoints[entryPoint].push(moduleName);
if (moduleName !== entryPoint) {
write.asModule(pluginName + '!' + moduleName, 'define([\'vs/nls\', \'vs/nls!' + entryPoint + '\'], function(nls, data) { return nls.create("' + moduleName + '", data); });');
}
}
export function writeFile(pluginName: string, moduleName: string, req: AMDLoader.IRelativeRequire, write: AMDLoader.IPluginWriteFileCallback, config: AMDLoader.IConfigurationOptions): void {
if (entryPoints.hasOwnProperty(moduleName)) {
const fileName = req.toUrl(moduleName + '.nls.js');
const contents = [
'/*---------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
],
entries = entryPoints[moduleName];
const data: { [moduleName: string]: string[] } = {};
for (let i = 0; i < entries.length; i++) {
data[entries[i]] = buildMap[entries[i]];
}
contents.push('define("' + moduleName + '.nls", ' + JSON.stringify(data, null, '\t') + ');');
write(fileName, contents.join('\r\n'));
}
}
export function finishBuild(write: AMDLoader.IPluginWriteFileCallback): void {
write('nls.metadata.json', JSON.stringify({
keys: buildMapKeys,
messages: buildMap,
bundles: entryPoints
}, null, '\t'));
}

25
src/vs/nls.d.ts vendored
View File

@ -1,25 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
export interface ILocalizeInfo {
key: string;
comment: string[];
}
/**
* Localize a message.
*
* `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
* For example, `localize({ key: 'sayHello', comment: ['Welcomes user'] }, 'hello {0}', name)`
*/
export declare function localize(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
/**
* Localize a message.
*
* `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
* For example, `localize('sayHello', 'hello {0}', name)`
*/
export declare function localize(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string;

View File

@ -1,167 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
* Please make sure to make edits in the .ts file at https://github.com/microsoft/vscode-loader/
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*---------------------------------------------------------------------------------------------
*--------------------------------------------------------------------------------------------*/
'use strict';
var __spreadArrays = (this && this.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var NLSLoaderPlugin;
(function (NLSLoaderPlugin) {
var Environment = /** @class */ (function () {
function Environment() {
this._detected = false;
this._isPseudo = false;
}
Object.defineProperty(Environment.prototype, "isPseudo", {
get: function () {
this._detect();
return this._isPseudo;
},
enumerable: false,
configurable: true
});
Environment.prototype._detect = function () {
if (this._detected) {
return;
}
this._detected = true;
this._isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0);
};
return Environment;
}());
function _format(message, args, env) {
var result;
if (args.length === 0) {
result = message;
}
else {
result = message.replace(/\{(\d+)\}/g, function (match, rest) {
var index = rest[0];
var arg = args[index];
var result = match;
if (typeof arg === 'string') {
result = arg;
}
else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) {
result = String(arg);
}
return result;
});
}
if (env.isPseudo) {
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D';
}
return result;
}
function findLanguageForModule(config, name) {
var result = config[name];
if (result)
return result;
result = config['*'];
if (result)
return result;
return null;
}
function localize(env, data, message) {
var args = [];
for (var _i = 3; _i < arguments.length; _i++) {
args[_i - 3] = arguments[_i];
}
return _format(message, args, env);
}
function createScopedLocalize(scope, env) {
return function (idx, defaultValue) {
var restArgs = Array.prototype.slice.call(arguments, 2);
return _format(scope[idx], restArgs, env);
};
}
var NLSPlugin = /** @class */ (function () {
function NLSPlugin(env) {
var _this = this;
this._env = env;
this.localize = function (data, message) {
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
return localize.apply(void 0, __spreadArrays([_this._env, data, message], args));
};
}
NLSPlugin.prototype.setPseudoTranslation = function (value) {
this._env._isPseudo = value;
};
NLSPlugin.prototype.create = function (key, data) {
return {
localize: createScopedLocalize(data[key], this._env)
};
};
NLSPlugin.prototype.load = function (name, req, load, config) {
var _this = this;
var _a;
config = config || {};
if (!name || name.length === 0) {
load({
localize: this.localize
});
}
else {
var pluginConfig = config['vs/nls'] || {};
var language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null;
var suffix = '.nls';
if (language !== null && language !== NLSPlugin.DEFAULT_TAG) {
suffix = suffix + '.' + language;
}
var messagesLoaded_1 = function (messages) {
if (Array.isArray(messages)) {
messages.localize = createScopedLocalize(messages, _this._env);
}
else {
messages.localize = createScopedLocalize(messages[name], _this._env);
}
load(messages);
};
if (typeof pluginConfig.loadBundle === 'function') {
pluginConfig.loadBundle(name, language, function (err, messages) {
// We have an error. Load the English default strings to not fail
if (err) {
req([name + '.nls'], messagesLoaded_1);
}
else {
messagesLoaded_1(messages);
}
});
}
else {
var base = (_a = pluginConfig.baseUrl) !== null && _a !== void 0 ? _a : '';
req([base + name + suffix], messagesLoaded_1, function (err) {
var _a;
// We have an error. Load the English default strings instead.
console.warn("Falling back to default strings. Unable to load translations because of: " + ((_a = err.message) !== null && _a !== void 0 ? _a : err));
req([name + '.nls'], messagesLoaded_1);
});
}
}
};
NLSPlugin.DEFAULT_TAG = 'i-default';
return NLSPlugin;
}());
NLSLoaderPlugin.NLSPlugin = NLSPlugin;
define('vs/nls', new NLSPlugin(new Environment()));
})(NLSLoaderPlugin || (NLSLoaderPlugin = {}));

163
src/vs/nls.ts Normal file
View File

@ -0,0 +1,163 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
let isPseudo = (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0);
const DEFAULT_TAG = 'i-default';
interface INLSPluginConfig {
availableLanguages?: INLSPluginConfigAvailableLanguages;
loadBundle?: BundleLoader;
baseUrl?: string;
}
interface INLSPluginConfigAvailableLanguages {
'*'?: string;
[module: string]: string | undefined;
}
interface BundleLoader {
(bundle: string, locale: string | null, cb: (err: Error, messages: string[] | IBundledStrings) => void): void;
}
interface IBundledStrings {
[moduleId: string]: string[];
}
export interface ILocalizeInfo {
key: string;
comment: string[];
}
interface ILocalizeFunc {
(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
}
interface IBoundLocalizeFunc {
(idx: number, defaultValue: null): string;
}
interface IConsumerAPI {
localize: ILocalizeFunc | IBoundLocalizeFunc;
}
function _format(message: string, args: (string | number | boolean | undefined | null)[]): string {
let result: string;
if (args.length === 0) {
result = message;
} else {
result = message.replace(/\{(\d+)\}/g, (match, rest) => {
const index = rest[0];
const arg = args[index];
let result = match;
if (typeof arg === 'string') {
result = arg;
} else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) {
result = String(arg);
}
return result;
});
}
if (isPseudo) {
// FF3B and FF3D is the Unicode zenkaku representation for [ and ]
result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D';
}
return result;
}
function findLanguageForModule(config: INLSPluginConfigAvailableLanguages, name: string) {
let result = config[name];
if (result) {
return result;
}
result = config['*'];
if (result) {
return result;
}
return null;
}
function createScopedLocalize(scope: string[]): IBoundLocalizeFunc {
return function (idx: number, defaultValue: null) {
const restArgs = Array.prototype.slice.call(arguments, 2);
return _format(scope[idx], restArgs);
};
}
/**
* Localize a message.
*
* `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
* For example, `localize({ key: 'sayHello', comment: ['Welcomes user'] }, 'hello {0}', name)`
*/
export function localize(info: ILocalizeInfo, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
/**
* Localize a message.
*
* `message` can contain `{n}` notation where it is replaced by the nth value in `...args`
* For example, `localize('sayHello', 'hello {0}', name)`
*/
export function localize(key: string, message: string, ...args: (string | number | boolean | undefined | null)[]): string;
export function localize(data: ILocalizeInfo | string, message: string, ...args: (string | number | boolean | undefined | null)[]): string {
return _format(message, args);
}
export function setPseudoTranslation(value: boolean) {
isPseudo = value;
}
export function create(key: string, data: IBundledStrings): IConsumerAPI {
return {
localize: createScopedLocalize(data[key])
};
}
export function load(name: string, req: AMDLoader.IRelativeRequire, load: AMDLoader.IPluginLoadCallback, config: AMDLoader.IConfigurationOptions): void {
config = config || {};
if (!name || name.length === 0) {
load({
localize: localize
});
} else {
const pluginConfig = <INLSPluginConfig>(config['vs/nls'] || {});
const language = pluginConfig.availableLanguages ? findLanguageForModule(pluginConfig.availableLanguages, name) : null;
let suffix = '.nls';
if (language !== null && language !== DEFAULT_TAG) {
suffix = suffix + '.' + language;
}
const messagesLoaded = (messages: string[] | IBundledStrings) => {
if (Array.isArray(messages)) {
(messages as any as IConsumerAPI).localize = createScopedLocalize(messages);
} else {
(messages as any as IConsumerAPI).localize = createScopedLocalize(messages[name]);
}
load(messages);
};
if (typeof pluginConfig.loadBundle === 'function') {
(pluginConfig.loadBundle as BundleLoader)(name, language, (err: Error, messages) => {
// We have an error. Load the English default strings to not fail
if (err) {
req([name + '.nls'], messagesLoaded);
} else {
messagesLoaded(messages);
}
});
} else {
const base = pluginConfig.baseUrl ?? '';
req([base + name + suffix], messagesLoaded, (err: Error) => {
// We have an error. Load the English default strings instead.
console.warn(`Falling back to default strings. Unable to load translations because of: ${err.message ?? err}`);
req([name + '.nls'], messagesLoaded);
});
}
}
}