Merge pull request #154925 from microsoft/sandy081/extensions-set-display-lang

show set display language action for lang pack extensions
This commit is contained in:
Sandeep Somavarapu 2022-07-13 07:29:25 +02:00 committed by GitHub
commit 764d22738f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 114 additions and 15 deletions

View file

@ -22,6 +22,7 @@ export interface ILanguagePackService {
readonly _serviceBrand: undefined;
getAvailableLanguages(): Promise<Array<ILanguagePackItem>>;
getInstalledLanguages(): Promise<Array<ILanguagePackItem>>;
getLocale(extension: IGalleryExtension): string | undefined;
}
export abstract class LanguagePackBaseService extends Disposable implements ILanguagePackService {
@ -51,7 +52,7 @@ export abstract class LanguagePackBaseService extends Disposable implements ILan
const languagePackExtensions = result.firstPage.filter(e => e.properties.localizedLanguages?.length && e.tags.some(t => t.startsWith('lp-')));
const allFromMarketplace: ILanguagePackItem[] = languagePackExtensions.map(lp => {
const languageName = lp.properties.localizedLanguages?.[0];
const locale = lp.tags.find(t => t.startsWith('lp-'))!.split('lp-')[1];
const locale = this.getLocale(lp)!;
const baseQuickPick = this.createQuickPickItem({ locale, label: languageName });
return {
...baseQuickPick,
@ -68,6 +69,10 @@ export abstract class LanguagePackBaseService extends Disposable implements ILan
return allFromMarketplace;
}
getLocale(extension: IGalleryExtension): string | undefined {
return extension.tags.find(t => t.startsWith('lp-'))?.split('lp-')[1];
}
protected createQuickPickItem(languageItem: { locale: string; label?: string | undefined }): IQuickPickItem {
const label = languageItem.label ?? languageItem.locale;
let description: string | undefined = languageItem.locale !== languageItem.label ? languageItem.locale : undefined;

View file

@ -29,7 +29,7 @@ import {
UpdateAction, ReloadAction, EnableDropDownAction, DisableDropDownAction, ExtensionStatusLabelAction, SetFileIconThemeAction, SetColorThemeAction,
RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ToggleSyncExtensionAction, SetProductIconThemeAction,
ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, UninstallAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction,
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction
InstallAnotherVersionAction, ExtensionEditorManageExtensionAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction, SetLanguageAction
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
@ -329,6 +329,7 @@ export class ExtensionEditor extends EditorPane {
this.instantiationService.createInstance(EnableDropDownAction),
this.instantiationService.createInstance(DisableDropDownAction),
this.instantiationService.createInstance(SetLanguageAction),
this.instantiationService.createInstance(RemoteInstallAction, false),
this.instantiationService.createInstance(LocalInstallAction),
this.instantiationService.createInstance(WebInstallAction),

View file

@ -56,7 +56,7 @@ import { IContextMenuProvider } from 'vs/base/browser/contextmenu';
import { ILogService } from 'vs/platform/log/common/log';
import * as Constants from 'vs/workbench/contrib/logs/common/logConstants';
import { errorIcon, infoIcon, manageExtensionIcon, preReleaseIcon, syncEnabledIcon, syncIgnoredIcon, trustIcon, warningIcon } from 'vs/workbench/contrib/extensions/browser/extensionsIcons';
import { isIOS, isWeb } from 'vs/base/common/platform';
import { isIOS, isWeb, language } from 'vs/base/common/platform';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { IWorkspaceTrustEnablementService, IWorkspaceTrustManagementService } from 'vs/platform/workspace/common/workspaceTrust';
import { isVirtualWorkspace } from 'vs/platform/workspace/common/virtualWorkspace';
@ -66,6 +66,7 @@ import { ViewContainerLocation } from 'vs/workbench/common/views';
import { flatten } from 'vs/base/common/arrays';
import { fromNow } from 'vs/base/common/date';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks';
export class PromptExtensionInstallFailureAction extends Action {
@ -264,11 +265,18 @@ export abstract class AbstractInstallAction extends ExtensionAction {
protected async computeAndUpdateEnablement(): Promise<void> {
this.enabled = false;
if (this.extension && !this.extension.isBuiltin) {
if (this.extension.state === ExtensionState.Uninstalled && await this.extensionsWorkbenchService.canInstall(this.extension)) {
this.enabled = this.installPreReleaseVersion ? this.extension.hasPreReleaseVersion : this.extension.hasReleaseVersion;
this.updateLabel();
}
if (!this.extension) {
return;
}
if (this.extension.isBuiltin) {
return;
}
if (this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
return;
}
if (this.extension.state === ExtensionState.Uninstalled && await this.extensionsWorkbenchService.canInstall(this.extension)) {
this.enabled = this.installPreReleaseVersion ? this.extension.hasPreReleaseVersion : this.extension.hasReleaseVersion;
this.updateLabel();
}
}
@ -1781,6 +1789,43 @@ export class SetProductIconThemeAction extends ExtensionAction {
}
}
export class SetLanguageAction extends ExtensionAction {
static readonly ID = 'workbench.extensions.action.setLanguageTheme';
static readonly TITLE = { value: localize('workbench.extensions.action.setLanguageTheme', "Set Display Language"), original: 'Set Display Language' };
private static readonly EnabledClass = `${ExtensionAction.LABEL_ACTION_CLASS} theme`;
private static readonly DisabledClass = `${SetLanguageAction.EnabledClass} disabled`;
constructor(
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@ILanguagePackService private readonly languagePackService: ILanguagePackService,
) {
super(SetLanguageAction.ID, SetLanguageAction.TITLE.value, SetLanguageAction.DisabledClass, false);
this.update();
}
update(): void {
this.enabled = false;
this.class = SetLanguageAction.DisabledClass;
if (!this.extension) {
return;
}
if (!this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
return;
}
if (this.extension.gallery && language === this.languagePackService.getLocale(this.extension.gallery)) {
return;
}
this.enabled = true;
this.class = SetLanguageAction.EnabledClass;
}
override async run(): Promise<any> {
return this.extension && this.extensionsWorkbenchService.setLanguage(this.extension);
}
}
export class ShowRecommendedExtensionAction extends Action {
static readonly ID = 'workbench.extensions.action.showRecommendedExtension';
@ -2273,6 +2318,10 @@ export class ExtensionStatusAction extends ExtensionAction {
return;
}
if (this.extensionsWorkbenchService.canSetLanguage(this.extension)) {
return;
}
if (this.extension.gallery && this.extension.state === ExtensionState.Uninstalled && !await this.extensionsWorkbenchService.canInstall(this.extension)) {
if (this.extensionManagementServerService.localExtensionManagementServer || this.extensionManagementServerService.remoteExtensionManagementServer) {
const targetPlatform = await (this.extensionManagementServerService.localExtensionManagementServer ? this.extensionManagementServerService.localExtensionManagementServer!.extensionManagementService.getTargetPlatform() : this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.getTargetPlatform());

View file

@ -13,7 +13,7 @@ import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { Event } from 'vs/base/common/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { UpdateAction, ManageExtensionAction, ReloadAction, ExtensionStatusLabelAction, RemoteInstallAction, ExtensionStatusAction, LocalInstallAction, ActionWithDropDownAction, InstallDropdownAction, InstallingLabelAction, ExtensionActionWithDropdownActionViewItem, ExtensionDropDownAction, WebInstallAction, SwitchToPreReleaseVersionAction, SwitchToReleasedVersionAction, MigrateDeprecatedExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
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';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, ExtensionPackCountWidget as ExtensionPackBadgeWidget, SyncIgnoredWidget, ExtensionHoverWidget, ExtensionActivationStatusWidget, PreReleaseBookmarkWidget, extensionVerifiedPublisherIconColor } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
import { IExtensionService, toExtension } from 'vs/workbench/services/extensions/common/extensions';
@ -123,6 +123,7 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
reloadAction,
this.instantiationService.createInstance(InstallDropdownAction),
this.instantiationService.createInstance(InstallingLabelAction),
this.instantiationService.createInstance(SetLanguageAction),
this.instantiationService.createInstance(RemoteInstallAction, false),
this.instantiationService.createInstance(LocalInstallAction),
this.instantiationService.createInstance(WebInstallAction),
@ -186,16 +187,25 @@ export class Renderer implements IPagedRenderer<IExtension, ITemplateData> {
data.extensionDisposables = dispose(data.extensionDisposables);
const updateEnablement = async () => {
let disabled = false;
const deprecated = !!extension.deprecationInfo;
const computeEnablement = async () => {
if (extension.state === ExtensionState.Uninstalled) {
disabled = deprecated || !(await this.extensionsWorkbenchService.canInstall(extension));
if (!!extension.deprecationInfo) {
return true;
}
if (this.extensionsWorkbenchService.canSetLanguage(extension)) {
return false;
}
return !(await this.extensionsWorkbenchService.canInstall(extension));
} else if (extension.local && !isLanguagePackExtension(extension.local.manifest)) {
const runningExtensions = await this.extensionService.getExtensions();
const runningExtension = runningExtensions.filter(e => areSameExtensions({ id: e.identifier.value, uuid: e.uuid }, extension.identifier))[0];
disabled = !(runningExtension && extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)));
return !(runningExtension && extension.server === this.extensionManagementServerService.getExtensionManagementServer(toExtension(runningExtension)));
}
return false;
};
const updateEnablement = async () => {
const disabled = await computeEnablement();
const deprecated = !!extension.deprecationInfo;
data.element.classList.toggle('deprecated', deprecated);
data.root.classList.toggle('disabled', disabled);
};

View file

@ -45,8 +45,10 @@ import { isBoolean, isUndefined } from 'vs/base/common/types';
import { IExtensionManifestPropertiesService } from 'vs/workbench/services/extensions/common/extensionManifestPropertiesService';
import { IExtensionService, IExtensionsStatus } from 'vs/workbench/services/extensions/common/extensions';
import { ExtensionEditor } from 'vs/workbench/contrib/extensions/browser/extensionEditor';
import { isWeb } from 'vs/base/common/platform';
import { isWeb, language } from 'vs/base/common/platform';
import { GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
import { ILanguagePackService } from 'vs/platform/languagePacks/common/languagePacks';
import { ILocaleService } from 'vs/workbench/contrib/localization/common/locale';
interface IExtensionStateProvider<T> {
(extension: Extension): T;
@ -710,6 +712,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
@IExtensionManifestPropertiesService private readonly extensionManifestPropertiesService: IExtensionManifestPropertiesService,
@ILogService private readonly logService: ILogService,
@IExtensionService private readonly extensionService: IExtensionService,
@ILanguagePackService private readonly languagePackService: ILanguagePackService,
@ILocaleService private readonly localeService: ILocaleService,
) {
super();
const preferPreReleasesValue = configurationService.getValue('_extensions.preferPreReleases');
@ -1248,6 +1252,34 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension
return this.installWithProgress(() => this.installFromGallery(extension, gallery, installOptions), gallery.displayName, progressLocation);
}
canSetLanguage(extension: IExtension): boolean {
if (!isWeb) {
return false;
}
if (!extension.gallery) {
return false;
}
const locale = this.languagePackService.getLocale(extension.gallery);
if (!locale) {
return false;
}
return true;
}
async setLanguage(extension: IExtension): Promise<void> {
if (!this.canSetLanguage(extension)) {
throw new Error('Can not set language');
}
const locale = this.languagePackService.getLocale(extension.gallery!);
if (locale === language) {
return;
}
return this.localeService.setLocale({ id: locale, galleryExtension: extension.gallery, extensionId: extension.identifier.id, label: extension.displayName });
}
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void> {
extensions = Array.isArray(extensions) ? extensions : [extensions];
return this.promptAndSetEnablement(extensions, enablementState);

View file

@ -107,6 +107,8 @@ export interface IExtensionsWorkbenchService {
uninstall(extension: IExtension): Promise<void>;
installVersion(extension: IExtension, version: string, installOptions?: InstallOptions): Promise<IExtension>;
reinstall(extension: IExtension): Promise<IExtension>;
canSetLanguage(extension: IExtension): boolean;
setLanguage(extension: IExtension): Promise<void>;
setEnablement(extensions: IExtension | IExtension[], enablementState: EnablementState): Promise<void>;
open(extension: IExtension, options?: IExtensionEditorOptions): Promise<void>;
checkForUpdates(): Promise<void>;