Skip to content

Commit c17a34c

Browse files
authored
Merge pull request #123 from aws-pangestu/1.5-display-language
Fix: Support changing display languages
2 parents 5c1a58b + d06bb3f commit c17a34c

File tree

14 files changed

+583
-84
lines changed

14 files changed

+583
-84
lines changed

patched-vscode/extensions/sagemaker-open-notebook-extension/src/extension.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,12 @@ function downloadFile(url: string): Promise<string> {
8989
response.on('data', (chunk) => {
9090
data += chunk;
9191
});
92+
response.on('end', () => {
93+
resolve(data);
94+
});
95+
}).on('error', (error) => {
96+
reject(error);
97+
});
98+
});
99+
}
100+
export function deactivate() {}

patched-vscode/src/vs/base/common/platform.ts

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5-
import * as nls from 'vs/nls';
6-
75
export const LANGUAGE_DEFAULT = 'en';
86

97
let _isWindows = false;
@@ -112,17 +110,21 @@ else if (typeof navigator === 'object' && !isElectronRenderer) {
112110
_isMobile = _userAgent?.indexOf('Mobi') >= 0;
113111
_isWeb = true;
114112

115-
const configuredLocale = nls.getConfiguredDefaultLocale(
116-
// This call _must_ be done in the file that calls `nls.getConfiguredDefaultLocale`
117-
// to ensure that the NLS AMD Loader plugin has been loaded and configured.
118-
// This is because the loader plugin decides what the default locale is based on
119-
// how it's able to resolve the strings.
120-
nls.localize({ key: 'ensureLoaderPluginIsLoaded', comment: ['{Locked}'] }, '_')
121-
);
122-
123-
_locale = configuredLocale || LANGUAGE_DEFAULT;
113+
_locale = LANGUAGE_DEFAULT;
124114
_language = _locale;
125115
_platformLocale = navigator.language;
116+
const el = typeof document !== 'undefined' && document.getElementById('vscode-remote-nls-configuration');
117+
const rawNlsConfig = el && el.getAttribute('data-settings');
118+
if (rawNlsConfig) {
119+
try {
120+
const nlsConfig: NLSConfig = JSON.parse(rawNlsConfig);
121+
const resolved = nlsConfig.availableLanguages['*'];
122+
_locale = nlsConfig.locale;
123+
_platformLocale = nlsConfig.osLocale;
124+
_language = resolved ? resolved : LANGUAGE_DEFAULT;
125+
_translationsConfigFile = nlsConfig._translationsConfigFile;
126+
} catch (error) { /* Oh well. */ }
127+
}
126128
}
127129

128130
// Unknown environment

patched-vscode/src/vs/code/browser/workbench/workbench.html

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@
1919
<!-- Workbench Configuration -->
2020
<meta id="vscode-workbench-web-configuration" data-settings="{{WORKBENCH_WEB_CONFIGURATION}}">
2121

22+
<!-- NLS Configuration -->
23+
<meta id="vscode-remote-nls-configuration" data-settings="{{NLS_CONFIGURATION}}">
24+
2225
<!-- Workbench Auth Session -->
2326
<meta id="vscode-workbench-auth-session" data-settings="{{WORKBENCH_AUTH_SESSION}}">
2427

@@ -46,14 +49,26 @@
4649
// Normalize locale to lowercase because translationServiceUrl is case-sensitive.
4750
// ref: https://github.com/microsoft/vscode/issues/187795
4851
const locale = localStorage.getItem('vscode.nls.locale') || navigator.language.toLowerCase();
49-
if (!locale.startsWith('en')) {
50-
nlsConfig['vs/nls'] = {
51-
availableLanguages: {
52-
'*': locale
53-
},
54-
translationServiceUrl: '{{WORKBENCH_NLS_BASE_URL}}'
55-
};
56-
}
52+
try {
53+
nlsConfig['vs/nls'] = JSON.parse(document.getElementById("vscode-remote-nls-configuration").getAttribute("data-settings"))
54+
if (nlsConfig['vs/nls']._resolvedLanguagePackCoreLocation) {
55+
const bundles = Object.create(null)
56+
nlsConfig['vs/nls'].loadBundle = (bundle, _language, cb) => {
57+
const result = bundles[bundle]
58+
if (result) {
59+
return cb(undefined, result)
60+
}
61+
const path = nlsConfig['vs/nls']._resolvedLanguagePackCoreLocation + "/" + bundle.replace(/\//g, "!") + ".nls.json"
62+
fetch(`{{WORKBENCH_WEB_BASE_URL}}/../vscode-remote-resource?path=${encodeURIComponent(path)}`)
63+
.then((response) => response.json())
64+
.then((json) => {
65+
bundles[bundle] = json
66+
cb(undefined, json)
67+
})
68+
.catch(cb)
69+
}
70+
}
71+
} catch (error) { /* Probably fine. */ }
5772

5873
require.config({
5974
baseUrl: `${baseUrl}/out`,

patched-vscode/src/vs/platform/environment/common/environmentService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export abstract class AbstractNativeEnvironmentService implements INativeEnviron
101101
return URI.file(join(vscodePortable, 'argv.json'));
102102
}
103103

104-
return joinPath(this.userHome, this.productService.dataFolderName, 'argv.json');
104+
return joinPath(this.appSettingsHome, 'argv.json');
105105
}
106106

107107
@memoize

patched-vscode/src/vs/platform/languagePacks/browser/languagePacks.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,24 @@
55

66
import { CancellationTokenSource } from 'vs/base/common/cancellation';
77
import { URI } from 'vs/base/common/uri';
8+
import { ProxyChannel } from 'vs/base/parts/ipc/common/ipc';
89
import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
910
import { IExtensionResourceLoaderService } from 'vs/platform/extensionResourceLoader/common/extensionResourceLoader';
10-
import { ILanguagePackItem, LanguagePackBaseService } from 'vs/platform/languagePacks/common/languagePacks';
11+
import { ILanguagePackItem, ILanguagePackService, LanguagePackBaseService } from 'vs/platform/languagePacks/common/languagePacks';
1112
import { ILogService } from 'vs/platform/log/common/log';
13+
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
1214

1315
export class WebLanguagePacksService extends LanguagePackBaseService {
16+
private readonly languagePackService: ILanguagePackService;
17+
1418
constructor(
19+
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
1520
@IExtensionResourceLoaderService private readonly extensionResourceLoaderService: IExtensionResourceLoaderService,
1621
@IExtensionGalleryService extensionGalleryService: IExtensionGalleryService,
1722
@ILogService private readonly logService: ILogService
1823
) {
1924
super(extensionGalleryService);
25+
this.languagePackService = ProxyChannel.toService<ILanguagePackService>(remoteAgentService.getConnection()!.getChannel('languagePacks'))
2026
}
2127

2228
async getBuiltInExtensionTranslationsUri(id: string, language: string): Promise<URI | undefined> {
@@ -72,6 +78,6 @@ export class WebLanguagePacksService extends LanguagePackBaseService {
7278

7379
// Web doesn't have a concept of language packs, so we just return an empty array
7480
getInstalledLanguages(): Promise<ILanguagePackItem[]> {
75-
return Promise.resolve([]);
81+
return this.languagePackService.getInstalledLanguages()
7682
}
7783
}

patched-vscode/src/vs/server/node/remoteLanguagePacks.ts

Lines changed: 59 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,36 +8,30 @@ import { FileAccess } from 'vs/base/common/network';
88
import * as path from 'vs/base/common/path';
99

1010
import * as lp from 'vs/base/node/languagePacks';
11-
import product from 'vs/platform/product/common/product';
1211

1312
const metaData = path.join(FileAccess.asFileUri('').fsPath, 'nls.metadata.json');
1413
const _cache: Map<string, Promise<lp.NLSConfiguration>> = new Map();
1514

16-
function exists(file: string) {
17-
return new Promise(c => fs.exists(file, c));
18-
}
19-
2015
export function getNLSConfiguration(language: string, userDataPath: string): Promise<lp.NLSConfiguration> {
21-
return exists(metaData).then((fileExists) => {
22-
if (!fileExists || !product.commit) {
23-
// console.log(`==> MetaData or commit unknown. Using default language.`);
24-
// The OS Locale on the remote side really doesn't matter, so we return the default locale
25-
return Promise.resolve({ locale: 'en', osLocale: 'en', availableLanguages: {} });
26-
}
27-
const key = `${language}||${userDataPath}`;
28-
let result = _cache.get(key);
29-
if (!result) {
30-
// The OS Locale on the remote side really doesn't matter, so we pass in the same language
31-
result = lp.getNLSConfiguration(product.commit, userDataPath, metaData, language, language).then(value => {
32-
if (InternalNLSConfiguration.is(value)) {
33-
value._languagePackSupport = true;
34-
}
35-
return value;
36-
});
37-
_cache.set(key, result);
38-
}
39-
return result;
40-
});
16+
const key = `${language}||${userDataPath}`;
17+
let result = _cache.get(key);
18+
if (!result) {
19+
// The OS Locale on the remote side really doesn't matter, so we pass in the same language
20+
result = lp.getNLSConfiguration("dummy_commit", userDataPath, metaData, language, language).then(value => {
21+
if (InternalNLSConfiguration.is(value)) {
22+
value._languagePackSupport = true;
23+
}
24+
// If the configuration has no results keep trying since code-server
25+
// doesn't restart when a language is installed so this result would
26+
// persist (the plugin might not be installed yet for example).
27+
if (value.locale !== 'en' && value.locale !== 'en-us' && Object.keys(value.availableLanguages).length === 0) {
28+
_cache.delete(key);
29+
}
30+
return value;
31+
});
32+
_cache.set(key, result);
33+
}
34+
return result;
4135
}
4236

4337
export namespace InternalNLSConfiguration {
@@ -46,3 +40,43 @@ export namespace InternalNLSConfiguration {
4640
return candidate && typeof candidate._languagePackId === 'string';
4741
}
4842
}
43+
44+
/**
45+
* The code below is copied from from src/main.js.
46+
*/
47+
48+
export const getLocaleFromConfig = async (argvResource: string): Promise<string> => {
49+
try {
50+
const content = stripComments(await fs.promises.readFile(argvResource, 'utf8'));
51+
return JSON.parse(content).locale;
52+
} catch (error) {
53+
if (error.code !== "ENOENT") {
54+
console.warn(error)
55+
}
56+
return 'en';
57+
}
58+
};
59+
60+
const stripComments = (content: string): string => {
61+
const regexp = /('(?:[^\\']*(?:\\.)?)*')|('(?:[^\\']*(?:\\.)?)*')|(\/\*(?:\r?\n|.)*?\*\/)|(\/{2,}.*?(?:(?:\r?\n)|$))/g;
62+
63+
return content.replace(regexp, (match, _m1, _m2, m3, m4) => {
64+
// Only one of m1, m2, m3, m4 matches
65+
if (m3) {
66+
// A block comment. Replace with nothing
67+
return '';
68+
} else if (m4) {
69+
// A line comment. If it ends in \r?\n then keep it.
70+
const length_1 = m4.length;
71+
if (length_1 > 2 && m4[length_1 - 1] === '\n') {
72+
return m4[length_1 - 2] === '\r' ? '\r\n' : '\n';
73+
}
74+
else {
75+
return '';
76+
}
77+
} else {
78+
// We match a string
79+
return match;
80+
}
81+
});
82+
};

patched-vscode/src/vs/server/node/serverEnvironmentService.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { URI } from 'vs/base/common/uri';
1414

1515
export const serverOptions: OptionDescriptions<Required<ServerParsedArgs>> = {
1616

17+
'locale': { type: 'string' },
18+
1719
/* ----- server setup ----- */
1820

1921
'host': { type: 'string', cat: 'o', args: 'ip-address', description: nls.localize('host', "The host name or IP address the server should listen to. If not set, defaults to 'localhost'.") },
@@ -97,6 +99,8 @@ export const serverOptions: OptionDescriptions<Required<ServerParsedArgs>> = {
9799

98100
export interface ServerParsedArgs {
99101

102+
'locale'?: string;
103+
100104
/* ----- server setup ----- */
101105

102106
host?: string;

patched-vscode/src/vs/server/node/serverServices.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import * as path from 'vs/base/common/path';
1111
import { IURITransformer } from 'vs/base/common/uriIpc';
1212
import { getMachineId, getSqmMachineId, getdevDeviceId } from 'vs/base/node/id';
1313
import { Promises } from 'vs/base/node/pfs';
14-
import { ClientConnectionEvent, IMessagePassingProtocol, IPCServer, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
14+
import { ClientConnectionEvent, IMessagePassingProtocol, IPCServer, ProxyChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc';
1515
import { ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net';
1616
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
1717
import { ConfigurationService } from 'vs/platform/configuration/common/configurationService';
@@ -225,6 +225,9 @@ export async function setupServerServices(connectionToken: ServerConnectionToken
225225
const channel = new ExtensionManagementChannel(extensionManagementService, (ctx: RemoteAgentConnectionContext) => getUriTransformer(ctx.remoteAuthority));
226226
socketServer.registerChannel('extensions', channel);
227227

228+
const languagePackChannel = ProxyChannel.fromService<RemoteAgentConnectionContext>(accessor.get(ILanguagePackService), disposables);
229+
socketServer.registerChannel('languagePacks', languagePackChannel);
230+
228231
// clean up extensions folder
229232
remoteExtensionsScanner.whenExtensionsReady().then(() => extensionManagementService.cleanUp());
230233

patched-vscode/src/vs/server/node/webClientServer.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { URI } from 'vs/base/common/uri';
3030
import { streamToBuffer } from 'vs/base/common/buffer';
3131
import { IProductConfiguration } from 'vs/base/common/product';
3232
import { isString } from 'vs/base/common/types';
33+
import { getLocaleFromConfig, getNLSConfiguration } from 'vs/server/node/remoteLanguagePacks';
3334
import { CharCode } from 'vs/base/common/charCode';
3435
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
3536

@@ -362,6 +363,8 @@ export class WebClientServer {
362363
callbackRoute: this._callbackRoute
363364
};
364365

366+
const locale = this._environmentService.args.locale || await getLocaleFromConfig(this._environmentService.argvResource.fsPath);
367+
const nlsConfiguration = await getNLSConfiguration(locale, this._environmentService.userDataPath)
365368
const nlsBaseUrl = this._productService.extensionsGallery?.nlsBaseUrl;
366369
const values: { [key: string]: string } = {
367370
WORKBENCH_WEB_CONFIGURATION: asJSON(workbenchWebConfiguration),
@@ -370,6 +373,7 @@ export class WebClientServer {
370373
WORKBENCH_NLS_BASE_URL: vscodeBase + (nlsBaseUrl ? `${nlsBaseUrl}${!nlsBaseUrl.endsWith('/') ? '/' : ''}${this._productService.commit}/${this._productService.version}/` : ''),
371374
BASE: base,
372375
VS_BASE: vscodeBase,
376+
NLS_CONFIGURATION: asJSON(nlsConfiguration),
373377
};
374378

375379
if (useTestResolver) {
@@ -401,7 +405,7 @@ export class WebClientServer {
401405
`frame-src 'self' https://*.vscode-cdn.net data:;`,
402406
'worker-src \'self\' data: blob:;',
403407
'style-src \'self\' \'unsafe-inline\';',
404-
'connect-src \'self\' ws: wss: https://main.vscode-cdn.net http://localhost:* https://localhost:* https://login.microsoftonline.com/ https://update.code.visualstudio.com https://*.vscode-unpkg.net/ https://default.exp-tas.com/vscode/ab https://vscode-sync.trafficmanager.net https://vscode-sync-insiders.trafficmanager.net https://*.gallerycdn.vsassets.io https://marketplace.visualstudio.com https://az764295.vo.msecnd.net https://code.visualstudio.com https://*.gallery.vsassets.io https://*.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com https://*.servicebus.windows.net/ https://vscode.blob.core.windows.net https://vscode.search.windows.net https://vsmarketplacebadges.dev https://vscode.download.prss.microsoft.com https://download.visualstudio.microsoft.com https://*.vscode-unpkg.net https://open-vsx.org;',
408+
'connect-src \'self\' ws: wss: https://main.vscode-cdn.net http://localhost:* https://localhost:* https://login.microsoftonline.com/ https://update.code.visualstudio.com https://*.vscode-unpkg.net/ https://default.exp-tas.com/vscode/ab https://vscode-sync.trafficmanager.net https://vscode-sync-insiders.trafficmanager.net https://*.gallerycdn.vsassets.io https://marketplace.visualstudio.com https://*.blob.core.windows.net https://az764295.vo.msecnd.net https://code.visualstudio.com https://*.gallery.vsassets.io https://*.rel.tunnels.api.visualstudio.com wss://*.rel.tunnels.api.visualstudio.com https://*.servicebus.windows.net/ https://vscode.blob.core.windows.net https://vscode.search.windows.net https://vsmarketplacebadges.dev https://vscode.download.prss.microsoft.com https://download.visualstudio.microsoft.com https://*.vscode-unpkg.net https://open-vsx.org;',
405409
'font-src \'self\' blob:;',
406410
'manifest-src \'self\';'
407411
].join(' ');

patched-vscode/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -341,9 +341,6 @@ export class InstallAction extends ExtensionAction {
341341
if (this.extension.isBuiltin) {
342342
return;
343343
}
344-
if (this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
345-
return;
346-
}
347344
if (this.extension.state === ExtensionState.Uninstalled && await this.extensionsWorkbenchService.canInstall(this.extension)) {
348345
this.enabled = this.options.installPreReleaseVersion ? this.extension.hasPreReleaseVersion : this.extension.hasReleaseVersion;
349346
this.updateLabel();
@@ -614,7 +611,7 @@ export abstract class InstallInOtherServerAction extends ExtensionAction {
614611
}
615612

616613
if (isLanguagePackExtension(this.extension.local.manifest)) {
617-
return true;
614+
return false;
618615
}
619616

620617
// Prefers to run on UI
@@ -1848,17 +1845,6 @@ export class SetLanguageAction extends ExtensionAction {
18481845
update(): void {
18491846
this.enabled = false;
18501847
this.class = SetLanguageAction.DisabledClass;
1851-
if (!this.extension) {
1852-
return;
1853-
}
1854-
if (!this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
1855-
return;
1856-
}
1857-
if (this.extension.gallery && language === getLocale(this.extension.gallery)) {
1858-
return;
1859-
}
1860-
this.enabled = true;
1861-
this.class = SetLanguageAction.EnabledClass;
18621848
}
18631849

18641850
override async run(): Promise<any> {
@@ -1875,7 +1861,6 @@ export class ClearLanguageAction extends ExtensionAction {
18751861
private static readonly DisabledClass = `${ClearLanguageAction.EnabledClass} disabled`;
18761862

18771863
constructor(
1878-
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
18791864
@ILocaleService private readonly localeService: ILocaleService,
18801865
) {
18811866
super(ClearLanguageAction.ID, ClearLanguageAction.TITLE.value, ClearLanguageAction.DisabledClass, false);
@@ -1885,17 +1870,6 @@ export class ClearLanguageAction extends ExtensionAction {
18851870
update(): void {
18861871
this.enabled = false;
18871872
this.class = ClearLanguageAction.DisabledClass;
1888-
if (!this.extension) {
1889-
return;
1890-
}
1891-
if (!this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
1892-
return;
1893-
}
1894-
if (this.extension.gallery && language !== getLocale(this.extension.gallery)) {
1895-
return;
1896-
}
1897-
this.enabled = true;
1898-
this.class = ClearLanguageAction.EnabledClass;
18991873
}
19001874

19011875
override async run(): Promise<any> {

0 commit comments

Comments
 (0)