How VS Code Implements Multi‑Language Support: Deep Dive into NLS and Module Loading
This article explains how VS Code’s complex Electron‑Node architecture handles internationalization by using a custom NLS system, language‑pack plugins, compile‑time AST analysis, and a specialized AMD loader to map source‑code calls to localized strings at runtime.
NLS Overview
VS Code’s main process starts in
src/main.js. At line 63 it checks for a locale and creates a
nlsConfigurationPromiseusing
lp.getNLSConfiguration, which later sets the
VSCODE_NLS_CONFIGenvironment variable when the Electron
onReadyevent fires.
What is NLS?
NLS stands for Native Language Support . The promise returned by
lp.getNLSConfigurationreceives four arguments:
product.commit– the commit hash of the current VS Code build.
userDataPath– the directory where VS Code stores user data (different per OS).
metaDataFile– the generated
nls.metadata.jsonfile.
locale– the language selected by the user.
product.commit
The
product.jsonfile adds a
commitfield during the build. Language packs are released together with each VS Code version, so the commit hash links a specific language‑pack plugin (e.g.,
vscode‑loc) to the matching VS Code release.
userDataPath
Typical locations:
<code># MacOS
~/Library/Application Support/Code
# Linux
~/.config
# Windows
%USERPROFILE%/AppData/Roaming</code>metaDataFile
The file
nls.metadata.jsonis generated only after a full VS Code build. It contains three objects:
<code>{
"keys": { "vs/code/electron-browser/processExplorer/processExplorerMain": ["cpu","memory",...] },
"messages": { "vs/code/electron-browser/processExplorer/processExplorerMain": ["CPU %","Memory (MB)",...] },
"bundles": { "vs/code/electron-browser/processExplorer/processExplorerMain": ["vs/code/electron-browser/processExplorer/processExplorerMain"] }
}</code>The
keysmap source‑file identifiers to the keys used in
nls.localize, while
messageshold the default strings. The
bundleslist entry modules for the build process.
vs/nls Module
The module
vs/nlsis implemented as a plugin for the VS Code loader. It exports a
localizefunction that formats a message with optional arguments. During compilation, calls like
nls.localize('key', 'Default Message')are transformed to
nls.localize(index, args), where the index reflects the call order within the file.
<code>this.localize = (data, message, ...args) => localize(this._env, data, message, ...args);
function localize(env, data, message, ...args) {
if (args.length === 0) {
return message;
}
return message.replace(/\{(\d+)\}/g, (match, index) => {
const arg = args[index];
if (typeof arg === 'string') return arg;
if (typeof arg === 'number' || typeof arg === 'boolean' || arg == null) return String(arg);
return match;
});
}
</code>After compilation, the generated AMD module includes a special dependency syntax
vs/nls!<em>modulePath</em>. The loader parses the part after the exclamation mark as a
PluginDependency, loads the NLS plugin, and injects the appropriate language bundle.
<code>define(__m[34], __M([1, 36]), function (require, exports, electron_1, strings_1, os_1, product_1, nls_1, ...) {
// module body
});</code>The loader’s
_loadPluginDependencymethod registers the plugin and calls its
loadfunction, which ultimately defines a module containing the localized strings.
Extensions and vscode‑nls
Extension processes do not use
vs/nls. Instead they rely on the
vscode-nlspackage. Before any extension code runs,
initializeSettingsreads
VSCODE_NLS_CONFIG. Extensions call
nls.loadMessageBundle(__filename)(the filename is injected at compile time) and then use
nls.localize(index, args)to retrieve strings from the generated
nls.metadata.jsonfor that extension.
The entire i18n system hinges on compile‑time AST analysis, custom AMD loader plugins, and runtime environment variables to map source‑code calls to the correct localized text.
Understanding this workflow helps developers navigate VS Code’s source code and adapt similar i18n strategies for their own Electron‑based applications.
Taobao Frontend Technology
The frontend landscape is constantly evolving, with rapid innovations across familiar languages. Like us, your understanding of the frontend is continually refreshed. Join us on Taobao, a vibrant, all‑encompassing platform, to uncover limitless potential.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.