Change:
// namespace: l10n const l10n: typeof vscode.l10n = { <del> t(...params: [message: string, ...args: Array<string | number>] | [message: string, args: Record<string, any>] | [{ message: string; args?: Array<string | number> | Record<string, any>; comment: string[] }]): string { checkProposedApiEnabled(extension, 'localization'); </del> <ins> t(...params: [message: string, ...args: Array<string | number | boolean>] | [message: string, args: Record<string, any>] | [{ message: string; args?: Array<string | number | boolean> | Record<string, any>; comment: string | string[] }]): string { </ins> if (typeof params[0] === 'string') { const key = params.shift() as string; <del> // We have either rest args which are Array<string | number> or an array with a single Record<string, any>. This ensures we get a // Record<string | number> which will be formatted correctly. </del> <ins> // We have either rest args which are Array<string | number | boolean> or an array with a single Record<string, any>. // This ensures we get a Record<string | number, any> which will be formatted correctly. </ins> const argsFormatted = !params || typeof params[0] !== 'object' ? params : params[0]; return extHostLocalization.getMessage(extension.identifier.value, { message: key, args: argsFormatted as Record<string | number, any> | undefined }); }

Discussion:
<!-- Do Not Delete This! featurerequesttemplate --<!-- Please read our Rules of Conduct: --<!-- Please search existing issues to avoid creating duplicates. --<!-- Describe the feature you'd like. -- has existed for quite a while now... and in its original design it was very filepath driven. We felt this pain when bundling extensions became the norm and introduced a webpack loader and bundler that baked filepaths into source code... That mitigation of rewriting JS code worked... but this all became more complicated when talking about the web because the web has no "nice" way of loading strings synchronously. And even if there was such a nice thing, we wouldn't want synchronous loading from the internet... so instead we are moving in a direction where Core is responsible for loading the bundle of strings for an extension, asynchronously, before an extension is loaded and then those strings are provided to the extension via an API. In addition to this, we will have an additional field in the which is at the root next to and . This is useful for: being explicit in an extension that supports localized strings allows VS Code to not have to "guess" where the localized strings are in the extension (this is especially important in web where we don't have a filesystem that we can crawl) Important definitions: : the parameter is the English string. This is used for a few things: It's the string used when VS Code is in the default (English) language It's the fallback string when a bundle doesn't contain a translation for a particular string It's the key in the bundle (which is essentially just a big dictionary) who's value will be the translated version of itself in whatever language is chosen : This follows the same format we have when you wanna add a comment in a The array will be an array of comments that will be included in the exported XLF files (the files sent to translators). The is the same as defined above. : This will contain the key-value pairs of the strings that VS Code loaded. This is useful if you want to pass a subprocess, a web worker, or a webview the contents of the bundle so that that environment can have all the translations that are currently being used : This will contain the to the bundle that was loaded.

This is useful if you want to pass a subprocess, a web worker, or a webview the Uri of the bundle so that that environment can load the translations that are currently being used. Along side of this work, we will ship a very small helper package called or something like that that can be given the or value and load the bundle and handle string interpolation. This library will really only be used for subprocesses/workers/webviews that can't depend on the API directly. Current API proposal: This is a CLI & library for managing the usages of . It has two main usecases: Export: export the English strings out of the code and put them in a familiar JSON or XLF format Import: imports XLF files and turns them into the respective and files It currently has three commands: Export Generate XLF Import XLF
Is it possible to see which language is currently being used via the API? Does anything need to be changed in an extension based on Left to Right languages (e.g. English) verses Right to Left languages (e.g. Arabic)? The main case I tend to see is layout, for example if there is a custom rendered view.
VS Code doesn't support RTL: and I suspect that idea of LTR vs RTL would come in as an API separate to this proposal.
I see: Will the sync up with language translation the API returns? How does this work if the language is changed? Does the entire editor and the extension reload? Is there a way to account for formatted strings like ` (Including the interpolated piece matters for translation, simply concatenating doesn't translate well). With it should be simple enough for a developer to create their own function to map the provided language code to a direction if the feature is needed for the extension.
Yes. will return the string in whatever is set to so long as there was a translation available for that string in that language. And fallback to English if not. Yes. This is what happens today and will continue to happen. Not at this time. We are aligning to what  already does but in theory something like that could be in the future.

Yes but I think there's enough value here: String interpolation - the Automatic loading of your strings before your extension activates (so that any top level calls still work) - this is especially important in the web where we must load strings via an async fetch call Tooling around exporting strings out of your source code into a familiar format (keeping the same XLF format that uses) but additional formats could be
Updates from UX sync: isn't better than ... maybe ? use a function on instead of this half function/half object thing either take in or
Ok I have been playing with this a lot today… and here’s what I’d like to run: The API for translating strings in your extension’s code The tooling used for extracting l10n strings from vscode extensions and working with XLF files The library used for loading the translations into subprocesses of your extension The file used for translating static contributions in your extension’s This contains the following definition: The new namespace keeps the that we will see all over code short and sweet. Tooling used for extracting l10n strings from vscode extensions and working with XLF files. Here's what the CLI looks like: There is also a programatic way to interact with the tooling via JS. Library used for loading the translations into subprocesses of your extension. It has an API of: the same function a function that looks like this that will receive: ~NOTE: for backwards compatibility, is also supported.~ ~This file is used for translating static contributions in your extension's .~ deferred The api being pairs nicely with because you either do this in your extension code: or in a subprocess you do and the API becomes the same:
Moving to Oct and marking finalization. This has 2 TPIs associated with it:
api-notes document when/why is align bundle and uri value document sub-logic for , eg syntax for the function support document for params, namespace
This isn't so simple. What does the change to the API proposal look like to support this? Some scenarios: I think that: looks nicer than but I do want to support the object syntax
I agree with that. Could we be more strict and spec the var-args to not be but or ?

That would allow you to disambiguate them and IMO it won't hurt any user of the var-args variant
I adopted this in GHPRI, ran into an issue, and discussed with Posting here for API discussion: I ended up with the following compile error: I assumed this was just a breaking API change so updated my loc API usage to this: saw this and commented that it's not the usual pattern for templates with a variable number of arguments.
Either extension the overload to accept or don't allow undefined to surface in messages support