1 /* --------------------------------------------------------------------------------------------
\r
2 * Copyright (c) Microsoft Corporation. All rights reserved.
\r
3 * Licensed under the MIT License. See License.txt in the project root for license information.
\r
4 * ------------------------------------------------------------------------------------------ */
\r
6 Object.defineProperty(exports, "__esModule", { value: true });
\r
7 var path = require("path");
\r
8 var fs = require("fs");
\r
9 var toString = Object.prototype.toString;
\r
10 function isDefined(value) {
\r
11 return typeof value !== 'undefined';
\r
13 function isNumber(value) {
\r
14 return toString.call(value) === '[object Number]';
\r
16 function isString(value) {
\r
17 return toString.call(value) === '[object String]';
\r
19 function isBoolean(value) {
\r
20 return value === true || value === false;
\r
22 function readJsonFileSync(filename) {
\r
23 return JSON.parse(fs.readFileSync(filename, 'utf8'));
\r
26 (function (MessageFormat) {
\r
27 MessageFormat["file"] = "file";
\r
28 MessageFormat["bundle"] = "bundle";
\r
29 MessageFormat["both"] = "both";
\r
30 })(MessageFormat = exports.MessageFormat || (exports.MessageFormat = {}));
\r
32 (function (BundleFormat) {
\r
33 // the nls.bundle format
\r
34 BundleFormat["standalone"] = "standalone";
\r
35 BundleFormat["languagePack"] = "languagePack";
\r
36 })(BundleFormat = exports.BundleFormat || (exports.BundleFormat = {}));
\r
38 (function (LocalizeInfo) {
\r
39 function is(value) {
\r
40 var candidate = value;
\r
41 return candidate && isDefined(candidate.key) && isDefined(candidate.comment);
\r
43 LocalizeInfo.is = is;
\r
44 })(LocalizeInfo || (LocalizeInfo = {}));
\r
45 var resolvedLanguage;
\r
46 var resolvedBundles;
\r
49 function initializeSettings() {
\r
50 options = { locale: undefined, language: undefined, languagePackSupport: false, cacheLanguageResolution: true, messageFormat: MessageFormat.bundle };
\r
51 if (isString(process.env.VSCODE_NLS_CONFIG)) {
\r
53 var vscodeOptions_1 = JSON.parse(process.env.VSCODE_NLS_CONFIG);
\r
54 var language = void 0;
\r
55 var locale = void 0;
\r
56 if (vscodeOptions_1.availableLanguages) {
\r
57 var value = vscodeOptions_1.availableLanguages['*'];
\r
58 if (isString(value)) {
\r
62 if (isString(vscodeOptions_1.locale)) {
\r
63 options.locale = vscodeOptions_1.locale.toLowerCase();
\r
65 if (language === undefined) {
\r
66 options.language = options.locale;
\r
68 else if (language !== 'en') {
\r
69 options.language = language;
\r
71 if (isBoolean(vscodeOptions_1._languagePackSupport)) {
\r
72 options.languagePackSupport = vscodeOptions_1._languagePackSupport;
\r
74 if (isString(vscodeOptions_1._cacheRoot)) {
\r
75 options.cacheRoot = vscodeOptions_1._cacheRoot;
\r
77 if (isString(vscodeOptions_1._languagePackId)) {
\r
78 options.languagePackId = vscodeOptions_1._languagePackId;
\r
80 if (isString(vscodeOptions_1._translationsConfigFile)) {
\r
81 options.translationsConfigFile = vscodeOptions_1._translationsConfigFile;
\r
83 options.translationsConfig = readJsonFileSync(options.translationsConfigFile);
\r
86 // We can't read the translation config file. Mark the cache as corrupted.
\r
87 if (vscodeOptions_1._corruptedFile) {
\r
88 var dirname = path.dirname(vscodeOptions_1._corruptedFile);
\r
89 fs.exists(dirname, function (exists) {
\r
91 fs.writeFile(vscodeOptions_1._corruptedFile, 'corrupted', 'utf8', function (err) {
\r
104 isPseudo = options.locale === 'pseudo';
\r
105 resolvedLanguage = undefined;
\r
106 resolvedBundles = Object.create(null);
\r
108 initializeSettings();
\r
109 function supportsLanguagePack() {
\r
110 return options.languagePackSupport === true && options.cacheRoot !== undefined && options.languagePackId !== undefined && options.translationsConfigFile !== undefined
\r
111 && options.translationsConfig !== undefined;
\r
113 function format(message, args) {
\r
116 // FF3B and FF3D is the Unicode zenkaku representation for [ and ]
\r
117 message = '\uFF3B' + message.replace(/[aouei]/g, '$&$&') + '\uFF3D';
\r
119 if (args.length === 0) {
\r
123 result = message.replace(/\{(\d+)\}/g, function (match, rest) {
\r
124 var index = rest[0];
\r
125 var arg = args[index];
\r
126 var replacement = match;
\r
127 if (typeof arg === 'string') {
\r
130 else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) {
\r
131 replacement = String(arg);
\r
133 return replacement;
\r
138 function createScopedLocalizeFunction(messages) {
\r
139 return function (key, message) {
\r
141 for (var _i = 2; _i < arguments.length; _i++) {
\r
142 args[_i - 2] = arguments[_i];
\r
144 if (isNumber(key)) {
\r
145 if (key >= messages.length) {
\r
146 console.error("Broken localize call found. Index out of bounds. Stacktrace is\n: " + new Error('').stack);
\r
149 return format(messages[key], args);
\r
152 if (isString(message)) {
\r
153 console.warn("Message " + message + " didn't get externalized correctly.");
\r
154 return format(message, args);
\r
157 console.error("Broken localize call found. Stacktrace is\n: " + new Error('').stack);
\r
162 function localize(key, message) {
\r
164 for (var _i = 2; _i < arguments.length; _i++) {
\r
165 args[_i - 2] = arguments[_i];
\r
167 return format(message, args);
\r
169 function resolveLanguage(file) {
\r
170 var resolvedLanguage;
\r
171 if (options.cacheLanguageResolution && resolvedLanguage) {
\r
172 resolvedLanguage = resolvedLanguage;
\r
175 if (isPseudo || !options.language) {
\r
176 resolvedLanguage = '.nls.json';
\r
179 var locale = options.language;
\r
181 var candidate = '.nls.' + locale + '.json';
\r
182 if (fs.existsSync(file + candidate)) {
\r
183 resolvedLanguage = candidate;
\r
187 var index = locale.lastIndexOf('-');
\r
189 locale = locale.substring(0, index);
\r
192 resolvedLanguage = '.nls.json';
\r
198 if (options.cacheLanguageResolution) {
\r
199 resolvedLanguage = resolvedLanguage;
\r
202 return file + resolvedLanguage;
\r
204 function findInTheBoxBundle(root) {
\r
205 var language = options.language;
\r
207 var candidate = path.join(root, "nls.bundle." + language + ".json");
\r
208 if (fs.existsSync(candidate)) {
\r
212 var index = language.lastIndexOf('-');
\r
214 language = language.substring(0, index);
\r
217 language = undefined;
\r
221 // Test if we can reslove the default bundle.
\r
222 if (language === undefined) {
\r
223 var candidate = path.join(root, 'nls.bundle.json');
\r
224 if (fs.existsSync(candidate)) {
\r
230 function mkdir(directory) {
\r
232 fs.mkdirSync(directory);
\r
235 if (err.code === 'EEXIST') {
\r
238 else if (err.code === 'ENOENT') {
\r
239 var parent = path.dirname(directory);
\r
240 if (parent !== directory) {
\r
242 fs.mkdirSync(directory);
\r
250 function createDefaultNlsBundle(folder) {
\r
251 var metaData = readJsonFileSync(path.join(folder, 'nls.metadata.json'));
\r
252 var result = Object.create(null);
\r
253 for (var module_1 in metaData) {
\r
254 var entry = metaData[module_1];
\r
255 result[module_1] = entry.messages;
\r
259 function createNLSBundle(header, metaDataPath) {
\r
260 var languagePackLocation = options.translationsConfig[header.id];
\r
261 if (!languagePackLocation) {
\r
264 var languagePack = readJsonFileSync(languagePackLocation).contents;
\r
265 var metaData = readJsonFileSync(path.join(metaDataPath, 'nls.metadata.json'));
\r
266 var result = Object.create(null);
\r
267 for (var module_2 in metaData) {
\r
268 var entry = metaData[module_2];
\r
269 var translations = languagePack[header.outDir + "/" + module_2];
\r
270 if (translations) {
\r
271 var resultMessages = [];
\r
272 for (var i = 0; i < entry.keys.length; i++) {
\r
273 var messageKey = entry.keys[i];
\r
274 var key = isString(messageKey) ? messageKey : messageKey.key;
\r
275 var translatedMessage = translations[key];
\r
276 if (translatedMessage === undefined) {
\r
277 translatedMessage = entry.messages[i];
\r
279 resultMessages.push(translatedMessage);
\r
281 result[module_2] = resultMessages;
\r
284 result[module_2] = entry.messages;
\r
289 function touch(file) {
\r
290 var d = new Date();
\r
291 fs.utimes(file, d, d, function () {
\r
292 // Do nothing. Ignore
\r
295 function cacheBundle(key, bundle) {
\r
296 resolvedBundles[key] = bundle;
\r
299 function loadNlsBundleOrCreateFromI18n(header, bundlePath) {
\r
301 var bundle = path.join(options.cacheRoot, header.id + "-" + header.hash + ".json");
\r
302 var useMemoryOnly = false;
\r
303 var writeBundle = false;
\r
305 result = JSON.parse(fs.readFileSync(bundle, { encoding: 'utf8', flag: 'r' }));
\r
310 if (err.code === 'ENOENT') {
\r
311 writeBundle = true;
\r
313 else if (err instanceof SyntaxError) {
\r
314 // We have a syntax error. So no valid JSON. Use
\r
315 console.log("Syntax error parsing message bundle: " + err.message + ".");
\r
316 fs.unlink(bundle, function (err) {
\r
318 console.error("Deleting corrupted bundle " + bundle + " failed.");
\r
321 useMemoryOnly = true;
\r
327 result = createNLSBundle(header, bundlePath);
\r
328 if (!result || useMemoryOnly) {
\r
333 fs.writeFileSync(bundle, JSON.stringify(result), { encoding: 'utf8', flag: 'wx' });
\r
336 if (err.code === 'EEXIST') {
\r
344 function loadDefaultNlsBundle(bundlePath) {
\r
346 return createDefaultNlsBundle(bundlePath);
\r
349 console.log("Generating default bundle from meta data failed.", err);
\r
353 function loadNlsBundle(header, bundlePath) {
\r
355 // Core decided to use a language pack. Do the same in the extension
\r
356 if (supportsLanguagePack()) {
\r
358 result = loadNlsBundleOrCreateFromI18n(header, bundlePath);
\r
361 console.log("Load or create bundle failed ", err);
\r
365 // No language pack found, but core is running in language pack mode
\r
366 // Don't try to use old in the box bundles since the might be stale
\r
367 // Fall right back to the default bundle.
\r
368 if (options.languagePackSupport) {
\r
369 return loadDefaultNlsBundle(bundlePath);
\r
371 var candidate = findInTheBoxBundle(bundlePath);
\r
374 return readJsonFileSync(candidate);
\r
377 console.log("Loading in the box message bundle failed.", err);
\r
380 result = loadDefaultNlsBundle(bundlePath);
\r
384 function tryFindMetaDataHeaderFile(file) {
\r
386 var dirname = path.dirname(file);
\r
388 result = path.join(dirname, 'nls.metadata.header.json');
\r
389 if (fs.existsSync(result)) {
\r
392 var parent = path.dirname(dirname);
\r
393 if (parent === dirname) {
\r
394 result = undefined;
\r
403 function loadMessageBundle(file) {
\r
405 // No file. We are in dev mode. Return the default
\r
406 // localize function.
\r
409 // Remove extension since we load json files.
\r
410 var ext = path.extname(file);
\r
412 file = file.substr(0, file.length - ext.length);
\r
414 if (options.messageFormat === MessageFormat.both || options.messageFormat === MessageFormat.bundle) {
\r
415 var headerFile = tryFindMetaDataHeaderFile(file);
\r
417 var bundlePath = path.dirname(headerFile);
\r
418 var bundle = resolvedBundles[bundlePath];
\r
419 if (bundle === undefined) {
\r
421 var header = JSON.parse(fs.readFileSync(headerFile, 'utf8'));
\r
423 var nlsBundle = loadNlsBundle(header, bundlePath);
\r
424 bundle = cacheBundle(bundlePath, nlsBundle ? { header: header, nlsBundle: nlsBundle } : null);
\r
427 console.error('Failed to load nls bundle', err);
\r
428 bundle = cacheBundle(bundlePath, null);
\r
432 console.error('Failed to read header file', err);
\r
433 bundle = cacheBundle(bundlePath, null);
\r
437 var module_3 = file.substr(bundlePath.length + 1).replace(/\\/g, '/');
\r
438 var messages = bundle.nlsBundle[module_3];
\r
439 if (messages === undefined) {
\r
440 console.error("Messages for file " + file + " not found. See console for details.");
\r
441 return function () {
\r
442 return 'Messages not found.';
\r
445 return createScopedLocalizeFunction(messages);
\r
449 if (options.messageFormat === MessageFormat.both || options.messageFormat === MessageFormat.file) {
\r
450 // Try to load a single file bundle
\r
452 var json = readJsonFileSync(resolveLanguage(file));
\r
453 if (Array.isArray(json)) {
\r
454 return createScopedLocalizeFunction(json);
\r
457 if (isDefined(json.messages) && isDefined(json.keys)) {
\r
458 return createScopedLocalizeFunction(json.messages);
\r
461 console.error("String bundle '" + file + "' uses an unsupported format.");
\r
462 return function () {
\r
463 return 'File bundle has unsupported format. See console for details';
\r
469 if (err.code !== 'ENOENT') {
\r
470 console.error('Failed to load single file bundle', err);
\r
474 console.error("Failed to load message bundle for file " + file);
\r
475 return function () {
\r
476 return 'Failed to load message bundle. See console for details.';
\r
479 exports.loadMessageBundle = loadMessageBundle;
\r
480 function config(opts) {
\r
482 if (isString(opts.locale)) {
\r
483 options.locale = opts.locale.toLowerCase();
\r
484 options.language = options.locale;
\r
485 resolvedLanguage = undefined;
\r
486 resolvedBundles = Object.create(null);
\r
488 if (opts.messageFormat !== undefined) {
\r
489 options.messageFormat = opts.messageFormat;
\r
491 if (opts.bundleFormat === BundleFormat.standalone && options.languagePackSupport === true) {
\r
492 options.languagePackSupport = false;
\r
495 isPseudo = options.locale === 'pseudo';
\r
496 return loadMessageBundle;
\r
498 exports.config = config;
\r
499 //# sourceMappingURL=main.js.map