Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/services/localization/electron-browser/localeService.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { Language, LANGUAGE_DEFAULT } from '../../../../base/common/platform.js';
7
import { IEnvironmentService } from '../../../../platform/environment/common/environment.js';
8
import { INotificationService, Severity } from '../../../../platform/notification/common/notification.js';
9
import { IJSONEditingService } from '../../configuration/common/jsonEditing.js';
10
import { IActiveLanguagePackService, ILocaleService } from '../common/locale.js';
11
import { ILanguagePackItem, ILanguagePackService } from '../../../../platform/languagePacks/common/languagePacks.js';
12
import { IPaneCompositePartService } from '../../panecomposite/browser/panecomposite.js';
13
import { IViewPaneContainer, ViewContainerLocation } from '../../../common/views.js';
14
import { IExtensionManagementService } from '../../../../platform/extensionManagement/common/extensionManagement.js';
15
import { IProgressService, ProgressLocation } from '../../../../platform/progress/common/progress.js';
16
import { localize } from '../../../../nls.js';
17
import { toAction } from '../../../../base/common/actions.js';
18
import { ITextFileService } from '../../textfile/common/textfiles.js';
19
import { parse } from '../../../../base/common/jsonc.js';
20
import { IEditorService } from '../../editor/common/editorService.js';
21
import { IHostService } from '../../host/browser/host.js';
22
import { IDialogService } from '../../../../platform/dialogs/common/dialogs.js';
23
import { IProductService } from '../../../../platform/product/common/productService.js';
24
import { InstantiationType, registerSingleton } from '../../../../platform/instantiation/common/extensions.js';
25
26
// duplicate of IExtensionsViewPaneContainer in contrib
27
interface IExtensionsViewPaneContainer extends IViewPaneContainer {
28
readonly searchValue: string | undefined;
29
search(text: string): void;
30
refresh(): Promise<void>;
31
}
32
33
// duplicate of VIEWLET_ID in contrib/extensions
34
const EXTENSIONS_VIEWLET_ID = 'workbench.view.extensions';
35
36
class NativeLocaleService implements ILocaleService {
37
_serviceBrand: undefined;
38
39
constructor(
40
@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
41
@IEnvironmentService private readonly environmentService: IEnvironmentService,
42
@INotificationService private readonly notificationService: INotificationService,
43
@ILanguagePackService private readonly languagePackService: ILanguagePackService,
44
@IPaneCompositePartService private readonly paneCompositePartService: IPaneCompositePartService,
45
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
46
@IProgressService private readonly progressService: IProgressService,
47
@ITextFileService private readonly textFileService: ITextFileService,
48
@IEditorService private readonly editorService: IEditorService,
49
@IDialogService private readonly dialogService: IDialogService,
50
@IHostService private readonly hostService: IHostService,
51
@IProductService private readonly productService: IProductService
52
) { }
53
54
private async validateLocaleFile(): Promise<boolean> {
55
try {
56
const content = await this.textFileService.read(this.environmentService.argvResource, { encoding: 'utf8' });
57
58
// This is the same logic that we do where argv.json is parsed so mirror that:
59
// https://github.com/microsoft/vscode/blob/32d40cf44e893e87ac33ac4f08de1e5f7fe077fc/src/main.js#L238-L246
60
parse(content.value);
61
} catch (error) {
62
this.notificationService.notify({
63
severity: Severity.Error,
64
message: localize('argvInvalid', 'Unable to write display language. Please open the runtime settings, correct errors/warnings in it and try again.'),
65
actions: {
66
primary: [
67
toAction({
68
id: 'openArgv',
69
label: localize('openArgv', "Open Runtime Settings"),
70
run: () => this.editorService.openEditor({ resource: this.environmentService.argvResource })
71
})
72
]
73
}
74
});
75
return false;
76
}
77
return true;
78
}
79
80
private async writeLocaleValue(locale: string | undefined): Promise<boolean> {
81
if (!(await this.validateLocaleFile())) {
82
return false;
83
}
84
await this.jsonEditingService.write(this.environmentService.argvResource, [{ path: ['locale'], value: locale }], true);
85
return true;
86
}
87
88
async setLocale(languagePackItem: ILanguagePackItem, skipDialog = false): Promise<void> {
89
const locale = languagePackItem.id;
90
if (locale === Language.value() || (!locale && Language.isDefaultVariant())) {
91
return;
92
}
93
const installedLanguages = await this.languagePackService.getInstalledLanguages();
94
try {
95
96
// Only Desktop has the concept of installing language packs so we only do this for Desktop
97
// and only if the language pack is not installed
98
if (!installedLanguages.some(installedLanguage => installedLanguage.id === languagePackItem.id)) {
99
100
// Only actually install a language pack from Microsoft
101
if (languagePackItem.galleryExtension?.publisher.toLowerCase() !== 'ms-ceintl') {
102
// Show the view so the user can see the language pack that they should install
103
// as of now, there are no 3rd party language packs available on the Marketplace.
104
const viewlet = await this.paneCompositePartService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar);
105
(viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer).search(`@id:${languagePackItem.extensionId}`);
106
return;
107
}
108
109
await this.progressService.withProgress(
110
{
111
location: ProgressLocation.Notification,
112
title: localize('installing', "Installing {0} language support...", languagePackItem.label),
113
},
114
progress => this.extensionManagementService.installFromGallery(languagePackItem.galleryExtension!, {
115
// Setting this to false is how you get the extension to be synced with Settings Sync (if enabled).
116
isMachineScoped: false,
117
})
118
);
119
}
120
121
if (!skipDialog && !await this.showRestartDialog(languagePackItem.label)) {
122
return;
123
}
124
await this.writeLocaleValue(locale);
125
await this.hostService.restart();
126
} catch (err) {
127
this.notificationService.error(err);
128
}
129
}
130
131
async clearLocalePreference(): Promise<void> {
132
try {
133
await this.writeLocaleValue(undefined);
134
if (!Language.isDefaultVariant()) {
135
await this.showRestartDialog('English');
136
}
137
} catch (err) {
138
this.notificationService.error(err);
139
}
140
}
141
142
private async showRestartDialog(languageName: string): Promise<boolean> {
143
const { confirmed } = await this.dialogService.confirm({
144
message: localize('restartDisplayLanguageMessage1', "Restart {0} to switch to {1}?", this.productService.nameLong, languageName),
145
detail: localize(
146
'restartDisplayLanguageDetail1',
147
"To change the display language to {0}, {1} needs to restart.",
148
languageName,
149
this.productService.nameLong
150
),
151
primaryButton: localize({ key: 'restart', comment: ['&& denotes a mnemonic character'] }, "&&Restart"),
152
});
153
154
return confirmed;
155
}
156
}
157
158
// This is its own service because the localeService depends on IJSONEditingService which causes a circular dependency
159
// Once that's ironed out, we can fold this into the localeService.
160
class NativeActiveLanguagePackService implements IActiveLanguagePackService {
161
_serviceBrand: undefined;
162
163
constructor(
164
@ILanguagePackService private readonly languagePackService: ILanguagePackService
165
) { }
166
167
async getExtensionIdProvidingCurrentLocale(): Promise<string | undefined> {
168
const language = Language.value();
169
if (language === LANGUAGE_DEFAULT) {
170
return undefined;
171
}
172
const languages = await this.languagePackService.getInstalledLanguages();
173
const languagePack = languages.find(l => l.id === language);
174
return languagePack?.extensionId;
175
}
176
}
177
178
registerSingleton(ILocaleService, NativeLocaleService, InstantiationType.Delayed);
179
registerSingleton(IActiveLanguagePackService, NativeActiveLanguagePackService, InstantiationType.Delayed);
180
181