mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
Handle language pack uninstallation (#171891)
The most important part of this change is that we now listen for when extensions are uninstalled and if they uninstalled language currently set then a modal will show up prompting for restart (required to change the language back to English). This change also makes the LocaleService the thing that writes to the argv.json instead of a few places doing it and cleans up some of the wording. Fixes #82791
This commit is contained in:
parent
71a7c90c1e
commit
c321a36929
|
@ -1510,7 +1510,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
|
|||
if (locale === language) {
|
||||
return;
|
||||
}
|
||||
return this.localeService.setLocale({ id: locale, galleryExtension: extension.gallery, extensionId: extension.identifier.id, label: extension.displayName });
|
||||
const localizedLanguageName = extension.gallery?.properties?.localizedLanguages?.[0];
|
||||
return this.localeService.setLocale({ id: locale, galleryExtension: extension.gallery, extensionId: extension.identifier.id, label: localizedLanguageName ?? extension.displayName });
|
||||
}
|
||||
|
||||
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void> {
|
||||
|
|
|
@ -20,7 +20,7 @@ export class WebLocaleService implements ILocaleService {
|
|||
@IProductService private readonly productService: IProductService
|
||||
) { }
|
||||
|
||||
async setLocale(languagePackItem: ILanguagePackItem): Promise<void> {
|
||||
async setLocale(languagePackItem: ILanguagePackItem, _skipDialog = false): Promise<void> {
|
||||
const locale = languagePackItem.id;
|
||||
if (locale === Language.value() || (!locale && Language.value() === navigator.language)) {
|
||||
return;
|
||||
|
|
|
@ -10,6 +10,6 @@ export const ILocaleService = createDecorator<ILocaleService>('localizationServi
|
|||
|
||||
export interface ILocaleService {
|
||||
readonly _serviceBrand: undefined;
|
||||
setLocale(languagePackItem: ILanguagePackItem): Promise<void>;
|
||||
setLocale(languagePackItem: ILanguagePackItem, skipDialog?: boolean): Promise<void>;
|
||||
clearLocalePreference(): Promise<void>;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ export class NativeLocaleService implements ILocaleService {
|
|||
return true;
|
||||
}
|
||||
|
||||
async setLocale(languagePackItem: ILanguagePackItem): Promise<void> {
|
||||
async setLocale(languagePackItem: ILanguagePackItem, skipDialog = false): Promise<void> {
|
||||
const locale = languagePackItem.id;
|
||||
if (locale === Language.value() || (!locale && Language.isDefaultVariant())) {
|
||||
return;
|
||||
|
@ -108,7 +108,7 @@ export class NativeLocaleService implements ILocaleService {
|
|||
);
|
||||
}
|
||||
|
||||
if (await this.writeLocaleValue(locale)) {
|
||||
if (await this.writeLocaleValue(locale) && !skipDialog) {
|
||||
await this.showRestartDialog(languagePackItem.label);
|
||||
}
|
||||
} catch (err) {
|
||||
|
@ -127,15 +127,15 @@ export class NativeLocaleService implements ILocaleService {
|
|||
}
|
||||
}
|
||||
|
||||
private async showRestartDialog(languageName: string) {
|
||||
private async showRestartDialog(languageName: string): Promise<void> {
|
||||
const restartDialog = await this.dialogService.confirm({
|
||||
type: 'info',
|
||||
message: localize('restartDisplayLanguageMessage', "To change the display language, {0} needs to restart", this.productService.nameLong),
|
||||
message: localize('restartDisplayLanguageMessage1', "Restart {0} to switch to {1}?", this.productService.nameLong, languageName),
|
||||
detail: localize(
|
||||
'restartDisplayLanguageDetail',
|
||||
"Press the restart button to restart {0} and set the display language to {1}.",
|
||||
this.productService.nameLong,
|
||||
languageName
|
||||
'restartDisplayLanguageDetail1',
|
||||
"To change the display language to {0}, {1} needs to restart.",
|
||||
languageName,
|
||||
this.productService.nameLong
|
||||
),
|
||||
primaryButton: localize({ key: 'restart', comment: ['&& denotes a mnemonic character'] }, "&&Restart"),
|
||||
});
|
||||
|
|
|
@ -10,11 +10,9 @@ import { Disposable } from 'vs/base/common/lifecycle';
|
|||
import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry';
|
||||
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, InstallOperation, InstallExtensionResult } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IExtensionManagementService, IExtensionGalleryService, InstallOperation, ILocalExtension, InstallExtensionResult, DidUninstallExtensionEvent } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { INotificationService, NeverShowAgainScope } from 'vs/platform/notification/common/notification';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { IJSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditing';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { IHostService } from 'vs/workbench/services/host/browser/host';
|
||||
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
|
||||
import { VIEWLET_ID as EXTENSIONS_VIEWLET_ID, IExtensionsViewPaneContainer } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
|
@ -28,6 +26,7 @@ import { ClearDisplayLanguageAction, ConfigureDisplayLanguageAction } from 'vs/w
|
|||
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
|
||||
import { NativeLocaleService } from 'vs/workbench/contrib/localization/electron-sandbox/localeService';
|
||||
import { IProductService } from 'vs/platform/product/common/productService';
|
||||
|
||||
registerSingleton(ILocaleService, NativeLocaleService, InstantiationType.Delayed);
|
||||
|
||||
|
@ -40,8 +39,8 @@ const LANGUAGEPACK_SUGGESTION_IGNORE_STORAGE_KEY = 'extensionsAssistant/language
|
|||
export class LocalizationWorkbenchContribution extends Disposable implements IWorkbenchContribution {
|
||||
constructor(
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@IJSONEditingService private readonly jsonEditingService: IJSONEditingService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@ILocaleService private readonly localeService: ILocaleService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
@IHostService private readonly hostService: IHostService,
|
||||
@IStorageService private readonly storageService: IStorageService,
|
||||
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
|
||||
|
@ -53,30 +52,39 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
|
|||
|
||||
this.checkAndInstall();
|
||||
this._register(this.extensionManagementService.onDidInstallExtensions(e => this.onDidInstallExtensions(e)));
|
||||
this._register(this.extensionManagementService.onDidUninstallExtension(e => this.onDidUninstallExtension(e)));
|
||||
}
|
||||
|
||||
private onDidInstallExtensions(results: readonly InstallExtensionResult[]): void {
|
||||
for (const e of results) {
|
||||
if (e.operation !== InstallOperation.Install || !e.local?.manifest?.contributes?.localizations?.length) {
|
||||
continue;
|
||||
}
|
||||
const languageId = e.local.manifest.contributes.localizations[0].languageId;
|
||||
if (platform.language === languageId) {
|
||||
continue;
|
||||
private async onDidInstallExtensions(results: readonly InstallExtensionResult[]): Promise<void> {
|
||||
for (const result of results) {
|
||||
if (result.operation === InstallOperation.Install && result.local) {
|
||||
await this.onDidInstallExtension(result.local, !!result.context?.extensionsSync);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private async onDidInstallExtension(localExtension: ILocalExtension, fromSettingsSync: boolean): Promise<void> {
|
||||
const localization = localExtension.manifest.contributes?.localizations?.[0];
|
||||
if (!localization || platform.language === localization.languageId) {
|
||||
return;
|
||||
}
|
||||
const { languageId, languageName } = localization;
|
||||
|
||||
if (fromSettingsSync) {
|
||||
this.notificationService.prompt(
|
||||
Severity.Info,
|
||||
localize('updateLocale', "Would you like to change VS Code's UI language to {0} and restart?", e.local.manifest.contributes.localizations[0].languageName || e.local.manifest.contributes.localizations[0].languageId),
|
||||
localize('updateLocale', "Would you like to change {0}'s display language to {1} and restart?", this.productService.nameLong, languageName || languageId),
|
||||
[{
|
||||
label: localize('changeAndRestart', "Change Language and Restart"),
|
||||
run: async () => {
|
||||
try {
|
||||
await this.jsonEditingService.write(this.environmentService.argvResource, [{ path: ['locale'], value: languageId }], true);
|
||||
await this.hostService.restart();
|
||||
} catch (e) {
|
||||
this.notificationService.error(e);
|
||||
}
|
||||
await this.localeService.setLocale({
|
||||
id: languageId,
|
||||
label: languageName ?? languageId,
|
||||
extensionId: localExtension.identifier.id,
|
||||
// If settings sync installs the language pack, then we would have just shown the notification so no
|
||||
// need to show the dialog.
|
||||
}, true);
|
||||
}
|
||||
}],
|
||||
{
|
||||
|
@ -84,6 +92,22 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
|
|||
neverShowAgain: { id: 'langugage.update.donotask', isSecondary: true, scope: NeverShowAgainScope.APPLICATION }
|
||||
}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await this.localeService.setLocale({
|
||||
id: languageId,
|
||||
label: languageName ?? languageId,
|
||||
extensionId: localExtension.identifier.id,
|
||||
});
|
||||
}
|
||||
|
||||
private async onDidUninstallExtension(_event: DidUninstallExtensionEvent): Promise<void> {
|
||||
if (!await this.isLocaleInstalled(platform.language)) {
|
||||
this.localeService.setLocale({
|
||||
id: 'en',
|
||||
label: 'English'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,8 +196,12 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
|
|||
label: translations['installAndRestart'],
|
||||
run: async () => {
|
||||
logUserReaction('installAndRestart');
|
||||
await this.installExtension(extensionToInstall!);
|
||||
await this.jsonEditingService.write(this.environmentService.argvResource, [{ path: ['locale'], value: locale }], true);
|
||||
await this.localeService.setLocale({
|
||||
id: locale,
|
||||
label: languageName,
|
||||
extensionId: extensionToInstall?.identifier.id,
|
||||
// The user will be prompted if they want to install the language pack before this.
|
||||
}, true);
|
||||
await this.hostService.restart();
|
||||
}
|
||||
};
|
||||
|
@ -213,14 +241,6 @@ export class LocalizationWorkbenchContribution extends Disposable implements IWo
|
|||
return installed.some(i => !!i.manifest.contributes?.localizations?.length
|
||||
&& i.manifest.contributes.localizations.some(l => locale.startsWith(l.languageId.toLowerCase())));
|
||||
}
|
||||
|
||||
private installExtension(extension: IGalleryExtension): Promise<void> {
|
||||
return this.paneCompositeService.openPaneComposite(EXTENSIONS_VIEWLET_ID, ViewContainerLocation.Sidebar)
|
||||
.then(viewlet => viewlet?.getViewPaneContainer() as IExtensionsViewPaneContainer)
|
||||
.then(viewlet => viewlet.search(`@id:${extension.identifier.id}`))
|
||||
.then(() => this.extensionManagementService.installFromGallery(extension))
|
||||
.then(() => undefined, err => this.notificationService.error(err));
|
||||
}
|
||||
}
|
||||
|
||||
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
|
||||
|
|
Loading…
Reference in a new issue