From 61f0d4c8546ce38fe2f7fd0759f90bbb139963f8 Mon Sep 17 00:00:00 2001 From: Tyler Leonhardt Date: Fri, 17 Feb 2023 16:39:56 -0800 Subject: [PATCH] Ensuring locale is set to the OS locale and language is set to the Application Language Ref #164397 --- src/main.js | 71 ++++++++++----------- src/vs/base/common/platform.ts | 7 +-- src/vs/base/node/languagePacks.d.ts | 2 +- src/vs/base/node/languagePacks.js | 77 +++++++---------------- src/vs/server/node/remoteLanguagePacks.ts | 4 +- 5 files changed, 63 insertions(+), 98 deletions(-) diff --git a/src/main.js b/src/main.js index 99f828167b5f5..d9305dfb168e9 100644 --- a/src/main.js +++ b/src/main.js @@ -93,10 +93,27 @@ registerListeners(); let nlsConfigurationPromise = undefined; const metaDataFile = path.join(__dirname, 'nls.metadata.json'); -const locale = getUserDefinedLocale(argvConfig); -if (locale) { +const language = getUserDefinedLocale(argvConfig); +/** + * @type {string | undefined} + **/ +let osLocale = undefined; +// This if statement can be simplified once +// VS Code moves to Electron 22. +// Ref https://github.com/microsoft/vscode/issues/159813 +// and https://github.com/electron/electron/pull/36035 +if ('getPreferredSystemLanguages' in app + && typeof app.getPreferredSystemLanguages === 'function' + && app.getPreferredSystemLanguages().length) { + // Use the most preferred OS language for language recommendation. + osLocale = app.getPreferredSystemLanguages()[0]; + if (osLocale) { + osLocale = processZhLocale(osLocale.toLowerCase()); + } +} +if (language && osLocale) { const { getNLSConfiguration } = require('./vs/base/node/languagePacks'); - nlsConfigurationPromise = getNLSConfiguration(product.commit, userDataPath, metaDataFile, locale); + nlsConfigurationPromise = getNLSConfiguration(product.commit, userDataPath, metaDataFile, osLocale, language); } // Pass in the locale to Electron so that the @@ -108,7 +125,7 @@ if (locale) { // In that case, use `en` as the Electron locale. if (process.platform === 'win32' || process.platform === 'linux') { - const electronLocale = (!locale || locale === 'qps-ploc') ? 'en' : locale; + const electronLocale = (!language || language === 'qps-ploc') ? 'en' : language; app.commandLine.appendSwitch('lang', electronLocale); } @@ -554,6 +571,10 @@ async function mkdirpIgnoreError(dir) { //#region NLS Support +/** + * @param {string} appLocale + * @returns string + */ function processZhLocale(appLocale) { if (appLocale.startsWith('zh')) { const region = appLocale.split('-')[1]; @@ -585,39 +606,15 @@ async function resolveNlsConfiguration() { // If that fails we fall back to English. let nlsConfiguration = nlsConfigurationPromise ? await nlsConfigurationPromise : undefined; if (!nlsConfiguration) { - - // Try to use the app locale. Please note that the app locale is only - // valid after we have received the app ready event. This is why the - // code is here. - - /** - * @type string - */ - let appLocale = app.getLocale(); - - // This if statement can be simplified once - // VS Code moves to Electron 22. - // Ref https://github.com/microsoft/vscode/issues/159813 - // and https://github.com/electron/electron/pull/36035 - if ((process.platform === 'win32' || process.platform === 'linux') - && 'getPreferredSystemLanguages' in app - && typeof app.getPreferredSystemLanguages === 'function' - && app.getPreferredSystemLanguages().length) { - // Use the most preferred OS language for language recommendation. - appLocale = app.getPreferredSystemLanguages()[0]; - } - - if (!appLocale) { - nlsConfiguration = { locale: 'en', availableLanguages: {} }; - } else { - // See above the comment about the loader and case sensitiveness - appLocale = processZhLocale(appLocale.toLowerCase()); - - const { getNLSConfiguration } = require('./vs/base/node/languagePacks'); - nlsConfiguration = await getNLSConfiguration(product.commit, userDataPath, metaDataFile, appLocale); - if (!nlsConfiguration) { - nlsConfiguration = { locale: appLocale, availableLanguages: {} }; - } + // fallback to using app.getLocale() so that we have something for the locale. + // This can be removed after the move to Electron 22. Please note that getLocale() is only + // valid after we have received the app ready event. This is why the code is here. + osLocale ??= processZhLocale(app.getLocale().toLowerCase()); + + const { getNLSConfiguration } = require('./vs/base/node/languagePacks'); + nlsConfiguration = await getNLSConfiguration(product.commit, userDataPath, metaDataFile, osLocale, language); + if (!nlsConfiguration) { + nlsConfiguration = { locale: osLocale, availableLanguages: {} }; } } else { // We received a valid nlsConfig from a user defined locale diff --git a/src/vs/base/common/platform.ts b/src/vs/base/common/platform.ts index d267b8a39a32a..23f3c647b3228 100644 --- a/src/vs/base/common/platform.ts +++ b/src/vs/base/common/platform.ts @@ -172,8 +172,8 @@ export const platform = _platform; export const userAgent = _userAgent; /** - * The language used for the user interface. The format of - * the string is all lower case (e.g. zh-tw for Traditional + * The language used for the user interface. or the locale specified by --locale + * The format of the string is all lower case (e.g. zh-tw for Traditional * Chinese) */ export const language = _language; @@ -200,8 +200,7 @@ export namespace Language { } /** - * The OS locale or the locale specified by --locale. The format of - * the string is all lower case (e.g. zh-tw for Traditional + * The OS locale. The format of the string is all lower case (e.g. zh-tw for Traditional * Chinese). The UI is not necessarily shown in the provided locale. */ export const locale = _locale; diff --git a/src/vs/base/node/languagePacks.d.ts b/src/vs/base/node/languagePacks.d.ts index 87bff5b75a430..734a999f84357 100644 --- a/src/vs/base/node/languagePacks.d.ts +++ b/src/vs/base/node/languagePacks.d.ts @@ -21,4 +21,4 @@ export interface InternalNLSConfiguration extends NLSConfiguration { _languagePackSupport?: boolean; } -export function getNLSConfiguration(commit: string | undefined, userDataPath: string, metaDataFile: string, locale: string): Promise; +export function getNLSConfiguration(commit: string | undefined, userDataPath: string, metaDataFile: string, locale: string, language: string | undefined): Promise; diff --git a/src/vs/base/node/languagePacks.js b/src/vs/base/node/languagePacks.js index 006cd42d7070a..0eaa4b025f0ac 100644 --- a/src/vs/base/node/languagePacks.js +++ b/src/vs/base/node/languagePacks.js @@ -80,43 +80,16 @@ return undefined; } - /** - * @param {object} config - * @param {string | undefined} locale - */ - function resolveLanguagePackLocale(config, locale) { - try { - while (locale) { - if (config[locale]) { - return locale; - } else { - const index = locale.lastIndexOf('-'); - if (index > 0) { - locale = locale.substring(0, index); - } else { - return undefined; - } - } - } - } catch (err) { - console.error('Resolving language pack configuration failed.', err); - } - return undefined; - } - /** * @param {string | undefined} commit * @param {string} userDataPath * @param {string} metaDataFile - * @param {string | undefined} locale + * @param {string} locale + * @param {string | undefined} language */ - function getNLSConfiguration(commit, userDataPath, metaDataFile, locale) { - if (locale === 'pseudo') { - return Promise.resolve({ locale: locale, availableLanguages: {}, pseudo: true }); - } - + function getNLSConfiguration(commit, userDataPath, metaDataFile, locale, language) { if (process.env['VSCODE_DEV']) { - return Promise.resolve({ locale: locale, availableLanguages: {} }); + return Promise.resolve({ locale, availableLanguages: {} }); } // We have a built version so we have extracted nls file. Try to find @@ -125,53 +98,47 @@ // Check if we have an English or English US locale. If so fall to default since that is our // English translation (we don't ship *.nls.en.json files) if (locale && (locale === 'en' || locale === 'en-us')) { - return Promise.resolve({ locale: locale, availableLanguages: {} }); + return Promise.resolve({ locale, availableLanguages: {} }); } - const initialLocale = locale; - perf.mark('code/willGenerateNls'); const defaultResult = function (locale) { perf.mark('code/didGenerateNls'); - return Promise.resolve({ locale: locale, availableLanguages: {} }); + return Promise.resolve({ locale, availableLanguages: {} }); }; try { if (!commit) { - return defaultResult(initialLocale); + return defaultResult(locale); } return getLanguagePackConfigurations(userDataPath).then(configs => { if (!configs) { - return defaultResult(initialLocale); - } - locale = resolveLanguagePackLocale(configs, locale); - if (!locale) { - return defaultResult(initialLocale); + return defaultResult(locale); } const packConfig = configs[locale]; let mainPack; if (!packConfig || typeof packConfig.hash !== 'string' || !packConfig.translations || typeof (mainPack = packConfig.translations['vscode']) !== 'string') { - return defaultResult(initialLocale); + return defaultResult(locale); } return exists(mainPack).then(fileExists => { if (!fileExists) { - return defaultResult(initialLocale); + return defaultResult(locale); } - const packId = packConfig.hash + '.' + locale; - const cacheRoot = path.join(userDataPath, 'clp', packId); + const _languagePackId = packConfig.hash + '.' + locale; + const cacheRoot = path.join(userDataPath, 'clp', _languagePackId); const coreLocation = path.join(cacheRoot, commit); - const translationsConfigFile = path.join(cacheRoot, 'tcf.json'); - const corruptedFile = path.join(cacheRoot, 'corrupted.info'); + const _translationsConfigFile = path.join(cacheRoot, 'tcf.json'); + const _corruptedFile = path.join(cacheRoot, 'corrupted.info'); const result = { - locale: initialLocale, - availableLanguages: { '*': locale }, - _languagePackId: packId, - _translationsConfigFile: translationsConfigFile, + locale, + availableLanguages: { '*': language }, + _languagePackId, + _translationsConfigFile, _cacheRoot: cacheRoot, - _resolvedLanguagePackCoreLocation: coreLocation, - _corruptedFile: corruptedFile + _corruptedFile, + _resolvedLanguagePackCoreLocation: coreLocation }; - return exists(corruptedFile).then(corrupted => { + return exists(_corruptedFile).then(corrupted => { // The nls cache directory is corrupted. let toDelete; if (corrupted) { @@ -220,7 +187,7 @@ } writes.push(writeFile(path.join(coreLocation, bundle.replace(/\//g, '!') + '.nls.json'), JSON.stringify(target))); } - writes.push(writeFile(translationsConfigFile, JSON.stringify(packConfig.translations))); + writes.push(writeFile(_translationsConfigFile, JSON.stringify(packConfig.translations))); return Promise.all(writes); }).then(() => { perf.mark('code/didGenerateNls'); diff --git a/src/vs/server/node/remoteLanguagePacks.ts b/src/vs/server/node/remoteLanguagePacks.ts index e0218f836ab33..0e43ca9f45fa8 100644 --- a/src/vs/server/node/remoteLanguagePacks.ts +++ b/src/vs/server/node/remoteLanguagePacks.ts @@ -26,7 +26,9 @@ export function getNLSConfiguration(language: string, userDataPath: string): Pro const key = `${language}||${userDataPath}`; let result = _cache.get(key); if (!result) { - result = lp.getNLSConfiguration(product.commit, userDataPath, metaData, language).then(value => { + // For remote, we just use language for both locale and language since we don't have any use case for the locale + // on the server side. + result = lp.getNLSConfiguration(product.commit, userDataPath, metaData, language, language).then(value => { if (InternalNLSConfiguration.is(value)) { value._languagePackSupport = true; }