Skip to content

Commit 764d227

Browse files
authored
Merge pull request microsoft#154925 from microsoft/sandy081/extensions-set-display-lang
show set display language action for lang pack extensions
2 parents 052d5b0 + 725f83e commit 764d227

File tree

6 files changed

+114
-15
lines changed

6 files changed

+114
-15
lines changed

src/vs/platform/languagePacks/common/languagePacks.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export interface ILanguagePackService {
2222
readonly _serviceBrand: undefined;
2323
getAvailableLanguages(): Promise<Array<ILanguagePackItem>>;
2424
getInstalledLanguages(): Promise<Array<ILanguagePackItem>>;
25+
getLocale(extension: IGalleryExtension): string | undefined;
2526
}
2627

2728
export abstract class LanguagePackBaseService extends Disposable implements ILanguagePackService {
@@ -51,7 +52,7 @@ export abstract class LanguagePackBaseService extends Disposable implements ILan
5152
const languagePackExtensions = result.firstPage.filter(e => e.properties.localizedLanguages?.length && e.tags.some(t => t.startsWith('lp-')));
5253
const allFromMarketplace: ILanguagePackItem[] = languagePackExtensions.map(lp => {
5354
const languageName = lp.properties.localizedLanguages?.[0];
54-
const locale = lp.tags.find(t => t.startsWith('lp-'))!.split('lp-')[1];
55+
const locale = this.getLocale(lp)!;
5556
const baseQuickPick = this.createQuickPickItem({ locale, label: languageName });
5657
return {
5758
...baseQuickPick,
@@ -68,6 +69,10 @@ export abstract class LanguagePackBaseService extends Disposable implements ILan
6869
return allFromMarketplace;
6970
}
7071

72+
getLocale(extension: IGalleryExtension): string | undefined {
73+
return extension.tags.find(t => t.startsWith('lp-'))?.split('lp-')[1];
74+
}
75+
7176
protected createQuickPickItem(languageItem: { locale: string; label?: string | undefined }): IQuickPickItem {
7277
const label = languageItem.label ?? languageItem.locale;
7378
let description: string | undefined = languageItem.locale !== languageItem.label ? languageItem.locale : undefined;

src/vs/workbench/contrib/extensions/browser/extensionEditor.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import {
2929
UpdateAction, ReloadAction, EnableDropDownAction, DisableDropDownAction, ExtensionStatusLabelAction, SetFileIconThemeAction, SetColorThemeAction,
3030
RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ToggleSyncExtensionAction, SetProductIconThemeAction,
3131
ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, UninstallAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction,
32-
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction
32+
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction
3333
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
3434
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
3535
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
@@ -329,6 +329,7 @@ export class ExtensionEditor extends EditorPane {
329329

330330
this.instantiationService.createInstance(EnableDropDownAction),
331331
this.instantiationService.createInstance(DisableDropDownAction),
332+
this.instantiationService.createInstance(SetLanguageAction),
332333
this.instantiationService.createInstance(RemoteInstallAction, false),
333334
this.instantiationService.createInstance(LocalInstallAction),
334335
this.instantiationService.createInstance(WebInstallAction),

src/vs/workbench/contrib/extensions/browser/extensionsActions.ts

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
5656
import { ILogService } from 'vs/platform/log/common/log';
5757
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
5858
import { errorIcon, infoIcon, manageExtensionIcon, preReleaseIcon, syncEnabledIcon, syncIgnoredIcon, trustIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
59-
import { isIOS, isWeb } from 'vs/base/common/platform';
59+
import { isIOS, isWeb, language } from 'vs/base/common/platform';
6060
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
6161
import { IWorkspaceTrustEnablementService, IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
6262
import { isVirtualWorkspace } from 'vs/platform/workspace/common/virtualWorkspace';
@@ -66,6 +66,7 @@ import { ViewContainerLocation } from 'vs/workbench/common/views';
6666
import { flatten } from 'vs/base/common/arrays';
6767
import { fromNow } from 'vs/base/common/date';
6868
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
69+
import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks';
6970

7071
export class PromptExtensionInstallFailureAction extends Action {
7172

@@ -264,11 +265,18 @@ export abstract class AbstractInstallAction extends ExtensionAction {
264265

265266
protected async computeAndUpdateEnablement(): Promise<void> {
266267
this.enabled = false;
267-
if (this.extension && !this.extension.isBuiltin) {
268-
if (this.extension.state === ExtensionState.Uninstalled && await this.extensionsWorkbenchService.canInstall(this.extension)) {
269-
this.enabled = this.installPreReleaseVersion ? this.extension.hasPreReleaseVersion : this.extension.hasReleaseVersion;
270-
this.updateLabel();
271-
}
268+
if (!this.extension) {
269+
return;
270+
}
271+
if (this.extension.isBuiltin) {
272+
return;
273+
}
274+
if (this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
275+
return;
276+
}
277+
if (this.extension.state === ExtensionState.Uninstalled && await this.extensionsWorkbenchService.canInstall(this.extension)) {
278+
this.enabled = this.installPreReleaseVersion ? this.extension.hasPreReleaseVersion : this.extension.hasReleaseVersion;
279+
this.updateLabel();
272280
}
273281
}
274282

@@ -1781,6 +1789,43 @@ export class SetProductIconThemeAction extends ExtensionAction {
17811789
}
17821790
}
17831791

1792+
export class SetLanguageAction extends ExtensionAction {
1793+
1794+
static readonly ID = 'workbench.extensions.action.setLanguageTheme';
1795+
static readonly TITLE = { value: localize('workbench.extensions.action.setLanguageTheme', "Set Display Language"), original: 'Set Display Language' };
1796+
1797+
private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} theme`;
1798+
private static readonly DisabledClass = `${SetLanguageAction.EnabledClass} disabled`;
1799+
1800+
constructor(
1801+
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
1802+
@ILanguagePackService private readonly languagePackService: ILanguagePackService,
1803+
) {
1804+
super(SetLanguageAction.ID, SetLanguageAction.TITLE.value, SetLanguageAction.DisabledClass, false);
1805+
this.update();
1806+
}
1807+
1808+
update(): void {
1809+
this.enabled = false;
1810+
this.class = SetLanguageAction.DisabledClass;
1811+
if (!this.extension) {
1812+
return;
1813+
}
1814+
if (!this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
1815+
return;
1816+
}
1817+
if (this.extension.gallery && language === this.languagePackService.getLocale(this.extension.gallery)) {
1818+
return;
1819+
}
1820+
this.enabled = true;
1821+
this.class = SetLanguageAction.EnabledClass;
1822+
}
1823+
1824+
override async run(): Promise<any> {
1825+
return this.extension && this.extensionsWorkbenchService.setLanguage(this.extension);
1826+
}
1827+
}
1828+
17841829
export class ShowRecommendedExtensionAction extends Action {
17851830

17861831
static readonly ID = 'workbench.extensions.action.showRecommendedExtension';
@@ -2273,6 +2318,10 @@ export class ExtensionStatusAction extends ExtensionAction {
22732318
return;
22742319
}
22752320

2321+
if (this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
2322+
return;
2323+
}
2324+
22762325
if (this.extension.gallery && this.extension.state === ExtensionState.Uninstalled && !await this.extensionsWorkbenchService.canInstall(this.extension)) {
22772326
if (this.extensionManagementServerService.localExtensionManagementServer || this.extensionManagementServerService.remoteExtensionManagementServer) {
22782327
const targetPlatform = await (this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.localExtensionManagementServer!.extensionManagementService.getTargetPlatform() : this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.getTargetPlatform());

src/vs/workbench/contrib/extensions/browser/extensionsList.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
1313
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
1414
import { Event } from 'vs/base/common/event';
1515
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
16-
import { UpdateAction, ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
16+
import { UpdateAction, ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
1717
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
1818
import { RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, ExtensionPackCountWidget as ExtensionPackBadgeWidget, SyncIgnoredWidget, ExtensionHoverWidget, ExtensionActivationStatusWidget, PreReleaseBookmarkWidget, extensionVerifiedPublisherIconColor } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
1919
import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions';
@@ -123,6 +123,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
123123
reloadAction,
124124
this.instantiationService.createInstance(InstallDropdownAction),
125125
this.instantiationService.createInstance(InstallingLabelAction),
126+
this.instantiationService.createInstance(SetLanguageAction),
126127
this.instantiationService.createInstance(RemoteInstallAction, false),
127128
this.instantiationService.createInstance(LocalInstallAction),
128129
this.instantiationService.createInstance(WebInstallAction),
@@ -186,16 +187,25 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
186187

187188
data.extensionDisposables = dispose(data.extensionDisposables);
188189

189-
const updateEnablement = async () => {
190-
let disabled = false;
191-
const deprecated = !!extension.deprecationInfo;
190+
const computeEnablement = async () => {
192191
if (extension.state === ExtensionState.Uninstalled) {
193-
disabled = deprecated || !(await this.extensionsWorkbenchService.canInstall(extension));
192+
if (!!extension.deprecationInfo) {
193+
return true;
194+
}
195+
if (this.extensionsWorkbenchService.canSetLanguage(extension)) {
196+
return false;
197+
}
198+
return !(await this.extensionsWorkbenchService.canInstall(extension));
194199
} else if (extension.local && !isLanguagePackExtension(extension.local.manifest)) {
195200
const runningExtensions = await this.extensionService.getExtensions();
196201
const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, extension.identifier))[0];
197-
disabled = !(runningExtension && extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)));
202+
return !(runningExtension && extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)));
198203
}
204+
return false;
205+
};
206+
const updateEnablement = async () => {
207+
const disabled = await computeEnablement();
208+
const deprecated = !!extension.deprecationInfo;
199209
data.element.classList.toggle('deprecated', deprecated);
200210
data.root.classList.toggle('disabled', disabled);
201211
};

src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,10 @@ import { isBoolean, isUndefined } from 'vs/base/common/types';
4545
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
4646
import { IExtensionService, IExtensionsStatus } from 'vs/workbench/services/extensions/common/extensions';
4747
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
48-
import { isWeb } from 'vs/base/common/platform';
48+
import { isWeb, language } from 'vs/base/common/platform';
4949
import { GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
50+
import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks';
51+
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
5052

5153
interface IExtensionStateProvider<T> {
5254
(extension: Extension): T;
@@ -710,6 +712,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
710712
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
711713
@ILogService private readonly logService: ILogService,
712714
@IExtensionService private readonly extensionService: IExtensionService,
715+
@ILanguagePackService private readonly languagePackService: ILanguagePackService,
716+
@ILocaleService private readonly localeService: ILocaleService,
713717
) {
714718
super();
715719
const preferPreReleasesValue = configurationService.getValue('_extensions.preferPreReleases');
@@ -1248,6 +1252,34 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
12481252
return this.installWithProgress(() => this.installFromGallery(extension, gallery, installOptions), gallery.displayName, progressLocation);
12491253
}
12501254

1255+
canSetLanguage(extension: IExtension): boolean {
1256+
if (!isWeb) {
1257+
return false;
1258+
}
1259+
1260+
if (!extension.gallery) {
1261+
return false;
1262+
}
1263+
1264+
const locale = this.languagePackService.getLocale(extension.gallery);
1265+
if (!locale) {
1266+
return false;
1267+
}
1268+
1269+
return true;
1270+
}
1271+
1272+
async setLanguage(extension: IExtension): Promise<void> {
1273+
if (!this.canSetLanguage(extension)) {
1274+
throw new Error('Can not set language');
1275+
}
1276+
const locale = this.languagePackService.getLocale(extension.gallery!);
1277+
if (locale === language) {
1278+
return;
1279+
}
1280+
return this.localeService.setLocale({ id: locale, galleryExtension: extension.gallery, extensionId: extension.identifier.id, label: extension.displayName });
1281+
}
1282+
12511283
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void> {
12521284
extensions = Array.isArray(extensions) ? extensions : [extensions];
12531285
return this.promptAndSetEnablement(extensions, enablementState);

src/vs/workbench/contrib/extensions/common/extensions.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ export interface IExtensionsWorkbenchService {
107107
uninstall(extension: IExtension): Promise<void>;
108108
installVersion(extension: IExtension, version: string, installOptions?: InstallOptions): Promise<IExtension>;
109109
reinstall(extension: IExtension): Promise<IExtension>;
110+
canSetLanguage(extension: IExtension): boolean;
111+
setLanguage(extension: IExtension): Promise<void>;
110112
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void>;
111113
open(extension: IExtension, options?: IExtensionEditorOptions): Promise<void>;
112114
checkForUpdates(): Promise<void>;

0 commit comments

Comments
 (0)