From 0e2dbdbccebde6d647280c4b7429369061a2f291 Mon Sep 17 00:00:00 2001 From: Tyler James Leonhardt Date: Mon, 8 Aug 2022 08:56:12 -0700 Subject: [PATCH] Enable a mechanism for something to inject data into vscode-nls (#42) * initial attempt * use file * add ts * also remove leading slash * try a different way to import a module * clean up imports * use a sync require instead * don't need this file anymore --- src/browser/main.ts | 67 ++++++++++++++++++++++++++++++++++++--- src/browser/tsconfig.json | 2 +- src/common/common.ts | 10 ++++++ src/node/main.ts | 12 +------ 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/src/browser/main.ts b/src/browser/main.ts index 647a2d2..aacc832 100644 --- a/src/browser/main.ts +++ b/src/browser/main.ts @@ -5,25 +5,82 @@ import RAL from '../common/ral'; -import { setPseudo, localize, Options, LocalizeInfo } from '../common/common'; - +import { setPseudo, localize, Options, LocalizeInfo, isString, MessageFormat, isNumber, format, LocalizeFunc } from '../common/common'; export { MessageFormat, BundleFormat, Options, LocalizeInfo, LocalizeFunc, LoadFunc, KeyInfo } from '../common/common'; -export function loadMessageBundle(_file?: string) { +let nlsData: { [key: string]: string[] }; +try { + // Requiring this file will be intercepted by VS Code and will contain actual NLS data. + // @ts-ignore + nlsData = require('vscode-nls-web-data'); +} catch(e) { + console.error('Loading vscode-nls-web-data failed. Are you running this outside of VS Code? If so, you may need to intercept the import call with your bundled NLS data.'); + nlsData = {}; +} + +interface InternalOptions { + locale: string | undefined; + language: string | undefined; + languagePackSupport: boolean; + cacheLanguageResolution: boolean; + messageFormat: MessageFormat; + languagePackId?: string; + cacheRoot?: string; +} + +let options: InternalOptions; + +export function loadMessageBundle(file?: string) { + if (!file) { + // No file. We are in dev mode. Return the default + // localize function. + return localize; + } + // Remove extension since we load json files. + if (file.endsWith('.js') || file.endsWith('.ts')) { + file = file.substring(0, file.length - 3); + } + if (file.startsWith('/')) { + file = file.substring(1); + } + if (nlsData && nlsData[file]) { + return createScopedLocalizeFunction(nlsData[file]); + } return function (key: string | number | LocalizeInfo, message: string, ...args: any[]): string { if (typeof key === 'number') { - throw new Error(`Browser implementation does currently not support externalized strings.`); + throw new Error('Externalized strings were not present in the environment.'); } else { return localize(key, message, ...args); } }; } -export function config(options?: Options) { +// This API doesn't really do anything in practice because the message bundle _has_ to be loaded +// ahead of time via 'vscode-nls-web-data'. +export function config(opts?: Options) { setPseudo(options?.locale?.toLowerCase() === 'pseudo'); return loadMessageBundle; } +function createScopedLocalizeFunction(messages: string[]): LocalizeFunc { + return function (key: any, message: string, ...args: any[]): string { + if (isNumber(key)) { + if (key >= messages.length) { + console.error(`Broken localize call found. Index out of bounds. Stacktrace is\n: ${(new Error('')).stack}`); + return; + } + return format(messages[key], args); + } else { + if (isString(message)) { + console.warn(`Message ${message} didn't get externalized correctly.`); + return format(message, args); + } else { + console.error(`Broken localize call found. Stacktrace is\n: ${(new Error('')).stack}`); + } + } + }; +} + RAL.install(Object.freeze({ loadMessageBundle: loadMessageBundle, config: config diff --git a/src/browser/tsconfig.json b/src/browser/tsconfig.json index ce58932..e1cc8de 100644 --- a/src/browser/tsconfig.json +++ b/src/browser/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "lib": [ - "es5", + "es2015", "dom" ], "outDir": "../../lib/browser" diff --git a/src/common/common.ts b/src/common/common.ts index 111df72..912338a 100644 --- a/src/common/common.ts +++ b/src/common/common.ts @@ -91,6 +91,16 @@ export function isDefined(value: any): boolean { return typeof value !== 'undefined'; } +const toString = Object.prototype.toString; + +export function isNumber(value: any): value is number { + return toString.call(value) === '[object Number]'; +} + +export function isString(value: any): value is string { + return toString.call(value) === '[object String]'; +} + export let isPseudo = false; export function setPseudo(pseudo: boolean) { diff --git a/src/node/main.ts b/src/node/main.ts index 484409e..8ae0f85 100644 --- a/src/node/main.ts +++ b/src/node/main.ts @@ -10,21 +10,11 @@ import RAL from '../common/ral'; import { format, localize, isDefined, setPseudo, isPseudo, MessageFormat, BundleFormat, Options, TranslationConfig, LanguageBundle, LocalizeFunc, - NlsBundle, MetaDataFile, MetadataHeader, I18nBundle, SingleFileJsonFormat, LoadFunc + NlsBundle, MetaDataFile, MetadataHeader, I18nBundle, SingleFileJsonFormat, LoadFunc, isString, isNumber } from '../common/common'; export { MessageFormat, BundleFormat, Options, LocalizeInfo, LocalizeFunc, LoadFunc, KeyInfo } from '../common/common'; -const toString = Object.prototype.toString; - -function isNumber(value: any): value is number { - return toString.call(value) === '[object Number]'; -} - -function isString(value: any): value is string { - return toString.call(value) === '[object String]'; -} - function isBoolean(value: any): value is boolean { return value === true || value === false; }