Skip to content

Commit 7002a63

Browse files
committed
Move language pack processing code to common
1 parent da83a7e commit 7002a63

5 files changed

Lines changed: 349 additions & 271 deletions

File tree

build/gulpfile.vscode.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ const vscodeResources = [
6464
'out-build/paths.js',
6565
'out-build/vs/**/*.{svg,png,cur,html}',
6666
'out-build/vs/base/common/performance.js',
67+
'out-build/vs/base/node/languagePacks.js',
6768
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}',
6869
'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
6970
'out-build/vs/workbench/browser/media/*-theme.css',

src/bootstrap.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,36 @@ exports.writeFile = function (file, content) {
118118
});
119119
});
120120
};
121+
122+
/**
123+
* @param {string} dir
124+
* @returns {Promise<string>}
125+
*/
126+
function mkdir(dir) {
127+
const fs = require('fs');
128+
129+
return new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir)));
130+
}
131+
132+
/**
133+
* @param {string} dir
134+
* @returns {Promise<string>}
135+
*/
136+
exports.mkdirp = function mkdirp(dir) {
137+
const path = require('path');
138+
139+
return mkdir(dir).then(null, err => {
140+
if (err && err.code === 'ENOENT') {
141+
const parent = path.dirname(dir);
142+
143+
if (parent !== dir) { // if not arrived at root
144+
return mkdirp(parent).then(() => mkdir(dir));
145+
}
146+
}
147+
148+
throw err;
149+
});
150+
};
121151
//#endregion
122152

123153
//#region NLS helpers

src/main.js

Lines changed: 9 additions & 271 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
'use strict';
88

99
const perf = require('./vs/base/common/performance');
10+
const lp = require('./vs/base/node/languagePacks');
11+
1012
perf.mark('main:started');
1113

1214
const fs = require('fs');
@@ -57,9 +59,11 @@ registerListeners();
5759
*/
5860
let nlsConfiguration = undefined;
5961
const userDefinedLocale = getUserDefinedLocale();
62+
const metaDataFile = path.join(__dirname, 'nls.metadata.json');
63+
6064
userDefinedLocale.then(locale => {
6165
if (locale && !nlsConfiguration) {
62-
nlsConfiguration = getNLSConfiguration(locale);
66+
nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale);
6367
}
6468
});
6569

@@ -89,7 +93,7 @@ function onReady() {
8993

9094
Promise.all([nodeCachedDataDir.ensureExists(), userDefinedLocale]).then(([cachedDataDir, locale]) => {
9195
if (locale && !nlsConfiguration) {
92-
nlsConfiguration = getNLSConfiguration(locale);
96+
nlsConfiguration = lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale);
9397
}
9498

9599
if (!nlsConfiguration) {
@@ -129,7 +133,7 @@ function onReady() {
129133
// See above the comment about the loader and case sensitiviness
130134
appLocale = appLocale.toLowerCase();
131135

132-
getNLSConfiguration(appLocale).then(nlsConfig => {
136+
lp.getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale).then(nlsConfig => {
133137
if (!nlsConfig) {
134138
nlsConfig = { locale: appLocale, availableLanguages: {} };
135139
}
@@ -275,7 +279,7 @@ function getNodeCachedDir() {
275279
}
276280

277281
ensureExists() {
278-
return mkdirp(this.value).then(() => this.value, () => { /*ignore*/ });
282+
return bootstrap.mkdirp(this.value).then(() => this.value, () => { /*ignore*/ });
279283
}
280284

281285
_compute() {
@@ -328,101 +332,6 @@ function stripComments(content) {
328332
});
329333
}
330334

331-
/**
332-
* @param {string} dir
333-
* @returns {Promise<string>}
334-
*/
335-
function mkdir(dir) {
336-
return new Promise((c, e) => fs.mkdir(dir, err => (err && err.code !== 'EEXIST') ? e(err) : c(dir)));
337-
}
338-
339-
/**
340-
* @param {string} file
341-
* @returns {Promise<boolean>}
342-
*/
343-
function exists(file) {
344-
return new Promise(c => fs.exists(file, c));
345-
}
346-
347-
/**
348-
* @param {string} file
349-
* @returns {Promise<void>}
350-
*/
351-
function touch(file) {
352-
return new Promise((c, e) => { const d = new Date(); fs.utimes(file, d, d, err => err ? e(err) : c()); });
353-
}
354-
355-
/**
356-
* @param {string} file
357-
* @returns {Promise<object>}
358-
*/
359-
function lstat(file) {
360-
return new Promise((c, e) => fs.lstat(file, (err, stats) => err ? e(err) : c(stats)));
361-
}
362-
363-
/**
364-
* @param {string} dir
365-
* @returns {Promise<string[]>}
366-
*/
367-
function readdir(dir) {
368-
return new Promise((c, e) => fs.readdir(dir, (err, files) => err ? e(err) : c(files)));
369-
}
370-
371-
/**
372-
* @param {string} dir
373-
* @returns {Promise<void>}
374-
*/
375-
function rmdir(dir) {
376-
return new Promise((c, e) => fs.rmdir(dir, err => err ? e(err) : c(undefined)));
377-
}
378-
379-
/**
380-
* @param {string} file
381-
* @returns {Promise<void>}
382-
*/
383-
function unlink(file) {
384-
return new Promise((c, e) => fs.unlink(file, err => err ? e(err) : c(undefined)));
385-
}
386-
387-
/**
388-
* @param {string} dir
389-
* @returns {Promise<string>}
390-
*/
391-
function mkdirp(dir) {
392-
return mkdir(dir).then(null, err => {
393-
if (err && err.code === 'ENOENT') {
394-
const parent = path.dirname(dir);
395-
396-
if (parent !== dir) { // if not arrived at root
397-
return mkdirp(parent).then(() => mkdir(dir));
398-
}
399-
}
400-
401-
throw err;
402-
});
403-
}
404-
405-
/**
406-
* @param {string} location
407-
* @returns {Promise<void>}
408-
*/
409-
function rimraf(location) {
410-
return lstat(location).then(stat => {
411-
if (stat.isDirectory() && !stat.isSymbolicLink()) {
412-
return readdir(location)
413-
.then(children => Promise.all(children.map(child => rimraf(path.join(location, child)))))
414-
.then(() => rmdir(location));
415-
} else {
416-
return unlink(location);
417-
}
418-
}, err => {
419-
if (err.code === 'ENOENT') {
420-
return undefined;
421-
}
422-
throw err;
423-
});
424-
}
425-
426335
// Language tags are case insensitive however an amd loader is case sensitive
427336
// To make this work on case preserving & insensitive FS we do the following:
428337
// the language bundles have lower case language tags and we always lower case
@@ -449,175 +358,4 @@ function getUserDefinedLocale() {
449358
return undefined;
450359
});
451360
}
452-
453-
/**
454-
* @returns {object}
455-
*/
456-
function getLanguagePackConfigurations() {
457-
const configFile = path.join(userDataPath, 'languagepacks.json');
458-
try {
459-
return require(configFile);
460-
} catch (err) {
461-
// Do nothing. If we can't read the file we have no
462-
// language pack config.
463-
}
464-
return undefined;
465-
}
466-
467-
/**
468-
* @param {object} config
469-
* @param {string} locale
470-
*/
471-
function resolveLanguagePackLocale(config, locale) {
472-
try {
473-
while (locale) {
474-
if (config[locale]) {
475-
return locale;
476-
} else {
477-
const index = locale.lastIndexOf('-');
478-
if (index > 0) {
479-
locale = locale.substring(0, index);
480-
} else {
481-
return undefined;
482-
}
483-
}
484-
}
485-
} catch (err) {
486-
console.error('Resolving language pack configuration failed.', err);
487-
}
488-
return undefined;
489-
}
490-
491-
/**
492-
* @param {string} locale
493-
*/
494-
function getNLSConfiguration(locale) {
495-
if (locale === 'pseudo') {
496-
return Promise.resolve({ locale: locale, availableLanguages: {}, pseudo: true });
497-
}
498-
499-
if (process.env['VSCODE_DEV']) {
500-
return Promise.resolve({ locale: locale, availableLanguages: {} });
501-
}
502-
503-
// We have a built version so we have extracted nls file. Try to find
504-
// the right file to use.
505-
506-
// Check if we have an English or English US locale. If so fall to default since that is our
507-
// English translation (we don't ship *.nls.en.json files)
508-
if (locale && (locale === 'en' || locale === 'en-us')) {
509-
return Promise.resolve({ locale: locale, availableLanguages: {} });
510-
}
511-
512-
const initialLocale = locale;
513-
514-
perf.mark('nlsGeneration:start');
515-
516-
const defaultResult = function (locale) {
517-
perf.mark('nlsGeneration:end');
518-
return Promise.resolve({ locale: locale, availableLanguages: {} });
519-
};
520-
try {
521-
const commit = product.commit;
522-
if (!commit) {
523-
return defaultResult(initialLocale);
524-
}
525-
const configs = getLanguagePackConfigurations();
526-
if (!configs) {
527-
return defaultResult(initialLocale);
528-
}
529-
locale = resolveLanguagePackLocale(configs, locale);
530-
if (!locale) {
531-
return defaultResult(initialLocale);
532-
}
533-
const packConfig = configs[locale];
534-
let mainPack;
535-
if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') {
536-
return defaultResult(initialLocale);
537-
}
538-
return exists(mainPack).then(fileExists => {
539-
if (!fileExists) {
540-
return defaultResult(initialLocale);
541-
}
542-
const packId = packConfig.hash + '.' + locale;
543-
const cacheRoot = path.join(userDataPath, 'clp', packId);
544-
const coreLocation = path.join(cacheRoot, commit);
545-
const translationsConfigFile = path.join(cacheRoot, 'tcf.json');
546-
const corruptedFile = path.join(cacheRoot, 'corrupted.info');
547-
const result = {
548-
locale: initialLocale,
549-
availableLanguages: { '*': locale },
550-
_languagePackId: packId,
551-
_translationsConfigFile: translationsConfigFile,
552-
_cacheRoot: cacheRoot,
553-
_resolvedLanguagePackCoreLocation: coreLocation,
554-
_corruptedFile: corruptedFile
555-
};
556-
return exists(corruptedFile).then(corrupted => {
557-
// The nls cache directory is corrupted.
558-
let toDelete;
559-
if (corrupted) {
560-
toDelete = rimraf(cacheRoot);
561-
} else {
562-
toDelete = Promise.resolve(undefined);
563-
}
564-
return toDelete.then(() => {
565-
return exists(coreLocation).then(fileExists => {
566-
if (fileExists) {
567-
// We don't wait for this. No big harm if we can't touch
568-
touch(coreLocation).catch(() => { });
569-
perf.mark('nlsGeneration:end');
570-
return result;
571-
}
572-
return mkdirp(coreLocation).then(() => {
573-
return Promise.all([bootstrap.readFile(path.join(__dirname, 'nls.metadata.json')), bootstrap.readFile(mainPack)]);
574-
}).then(values => {
575-
const metadata = JSON.parse(values[0]);
576-
const packData = JSON.parse(values[1]).contents;
577-
const bundles = Object.keys(metadata.bundles);
578-
const writes = [];
579-
for (let bundle of bundles) {
580-
const modules = metadata.bundles[bundle];
581-
const target = Object.create(null);
582-
for (let module of modules) {
583-
const keys = metadata.keys[module];
584-
const defaultMessages = metadata.messages[module];
585-
const translations = packData[module];
586-
let targetStrings;
587-
if (translations) {
588-
targetStrings = [];
589-
for (let i = 0; i < keys.length; i++) {
590-
const elem = keys[i];
591-
const key = typeof elem === 'string' ? elem : elem.key;
592-
let translatedMessage = translations[key];
593-
if (translatedMessage === undefined) {
594-
translatedMessage = defaultMessages[i];
595-
}
596-
targetStrings.push(translatedMessage);
597-
}
598-
} else {
599-
targetStrings = defaultMessages;
600-
}
601-
target[module] = targetStrings;
602-
}
603-
writes.push(bootstrap.writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target)));
604-
}
605-
writes.push(bootstrap.writeFile(translationsConfigFile, JSON.stringify(packConfig.translations)));
606-
return Promise.all(writes);
607-
}).then(() => {
608-
perf.mark('nlsGeneration:end');
609-
return result;
610-
}).catch(err => {
611-
console.error('Generating translation files failed.', err);
612-
return defaultResult(locale);
613-
});
614-
});
615-
});
616-
});
617-
});
618-
} catch (err) {
619-
console.error('Generating translation files failed.', err);
620-
return defaultResult(locale);
621-
}
622-
}
623-
//#endregion
361+
//#endregion
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
export interface NLSConfiguration {
7+
locale: string;
8+
availableLanguages: {
9+
[key: string]: string;
10+
};
11+
pseudo?: boolean;
12+
}
13+
14+
export function getNLSConfiguration(commit: string, userDataPath: string, metaDataFile: string, locale: string): Promise<NLSConfiguration>;

0 commit comments

Comments
 (0)