Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Change localization in the extension to be async and use the VS Code …
…APIs
  • Loading branch information
Kartik Raj
Kartik Raj committed Oct 12, 2021
commit 74c76137932ae6f72ff27a3c4852a039d785805f
3 changes: 2 additions & 1 deletion src/client/browser/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { LanguageClientMiddlewareBase } from '../activation/languageClientMiddle
import { ILSExtensionApi } from '../activation/node/languageServerFolderService';
import { LanguageServerType } from '../activation/types';
import { AppinsightsKey, PVSC_EXTENSION_ID, PYLANCE_EXTENSION_ID } from '../common/constants';
import { loadLocalizedStrings } from '../common/utils/localize';
import { EventName } from '../telemetry/constants';

interface BrowserConfig {
Expand All @@ -17,7 +18,7 @@ interface BrowserConfig {

export async function activate(context: vscode.ExtensionContext): Promise<void> {
// Run in a promise and return early so that VS Code can go activate Pylance.

await loadLocalizedStrings();
const pylanceExtension = vscode.extensions.getExtension<ILSExtensionApi>(PYLANCE_EXTENSION_ID);
if (pylanceExtension) {
runPylance(context, pylanceExtension);
Expand Down
71 changes: 30 additions & 41 deletions src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

'use strict';

import * as path from 'path';
// IMPORTANT: Do not import any node fs related modules here, as they do not work in browser.
import * as vscode from 'vscode';
import { EXTENSION_ROOT_DIR } from '../../constants';
import { FileSystem } from '../platform/fileSystem';

/* eslint-disable @typescript-eslint/no-namespace, no-shadow */

Expand Down Expand Up @@ -568,36 +568,27 @@ export function _getAskedForCollection(): Record<string, string> {
return askedForCollection;
}

// Return the effective set of all localization strings, by key.
//
// This should not be used for direct lookup.
export function getCollectionJSON(): string {
// Load the current collection
if (!loadedCollection || parseLocale() !== loadedLocale) {
load();
}

// Combine the default and loaded collections
return JSON.stringify({ ...defaultCollection, ...loadedCollection });
}

export function localize(key: string, defValue?: string) {
// Return a pointer to function so that we refetch it on each call.
return (): string => getString(key, defValue);
}

declare let navigator: { language: string } | undefined;

function parseLocale(): string {
try {
if (navigator?.language) {
return navigator.language.toLowerCase();
}
} catch {
// Fall through
}
// Attempt to load from the vscode locale. If not there, use english
const vscodeConfigString = process.env.VSCODE_NLS_CONFIG;
return vscodeConfigString ? JSON.parse(vscodeConfigString).locale : 'en-us';
}

function getString(key: string, defValue?: string) {
// Load the current collection
if (!loadedCollection || parseLocale() !== loadedLocale) {
load();
}

// The default collection (package.nls.json) is the fallback.
// Note that we are guaranteed the following (during shipping)
// 1. defaultCollection was initialized by the load() call above
Expand All @@ -619,33 +610,31 @@ function getString(key: string, defValue?: string) {
return result;
}

function load() {
const fs = new FileSystem();

/**
* Only uses the VSCode APIs to query filesystem and not the node fs APIs, as
* they're not available in browser. Must be called before any use of the locale.
*/
export async function loadLocalizedStrings(): Promise<void> {
// Figure out our current locale.
loadedLocale = parseLocale();

// Find the nls file that matches (if there is one)
const nlsFile = path.join(EXTENSION_ROOT_DIR, `package.nls.${loadedLocale}.json`);
if (fs.fileExistsSync(nlsFile)) {
const contents = fs.readFileSync(nlsFile);
loadedCollection = JSON.parse(contents);
} else {
// If there isn't one, at least remember that we looked so we don't try to load a second time
loadedCollection = {};
}
loadedCollection = await parseNLS(loadedLocale);

// Get the default collection if necessary. Strings may be in the default or the locale json
if (!defaultCollection) {
const defaultNlsFile = path.join(EXTENSION_ROOT_DIR, 'package.nls.json');
if (fs.fileExistsSync(defaultNlsFile)) {
const contents = fs.readFileSync(defaultNlsFile);
defaultCollection = JSON.parse(contents);
} else {
defaultCollection = {};
}
defaultCollection = await parseNLS();
}
}

// Default to loading the current locale
load();
async function parseNLS(locale?: string) {
try {
const filename = locale ? `package.nls.${locale}.json` : `package.nls.json`;
const nlsFile = vscode.Uri.joinPath(vscode.Uri.file(EXTENSION_ROOT_DIR), filename);
const buffer = await vscode.workspace.fs.readFile(nlsFile);
const contents = new TextDecoder().decode(buffer);
return JSON.parse(contents);
} catch {
// If there isn't one, at least remember that we looked so we don't try to load a second time.
return {};
}
}
3 changes: 2 additions & 1 deletion src/client/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { IApplicationShell, IWorkspaceService } from './common/application/types
import { traceError } from './common/logger';
import { IAsyncDisposableRegistry, IExperimentService, IExtensionContext } from './common/types';
import { createDeferred } from './common/utils/async';
import { Common } from './common/utils/localize';
import { Common, loadLocalizedStrings } from './common/utils/localize';
import { activateComponents } from './extensionActivation';
import { initializeStandard, initializeComponents, initializeGlobals } from './extensionInit';
import { IServiceContainer } from './ioc/types';
Expand Down Expand Up @@ -99,6 +99,7 @@ async function activateUnsafe(
//===============================================
// activation starts here

await loadLocalizedStrings();
// First we initialize.
const ext = initializeGlobals(context);
activatedServiceContainer = ext.legacyIOC.serviceContainer;
Expand Down