Skip to content

Commit

Permalink
Merge branch 'master' into eclipse-theia#12401
Browse files Browse the repository at this point in the history
  • Loading branch information
vince-fugnitto committed Apr 20, 2023
2 parents c01f6ec + b206d89 commit 6d2e0ce
Show file tree
Hide file tree
Showing 25 changed files with 509 additions and 45 deletions.
2 changes: 1 addition & 1 deletion packages/core/src/browser/icon-theme-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,9 +168,9 @@ export class IconThemeService {
*/
setCurrent(newCurrent: IconTheme, persistSetting = true): void {
if (newCurrent !== this.getCurrent()) {
this.activeTheme = newCurrent;
this.toDeactivate.dispose();
this.toDeactivate.push(newCurrent.activate());
this.activeTheme = newCurrent;
this.onDidChangeCurrentEmitter.fire(newCurrent.id);
}
if (persistSetting) {
Expand Down
22 changes: 6 additions & 16 deletions packages/core/src/common/i18n/localization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,12 @@ export type FormatType = string | number | boolean | undefined;

export namespace Localization {

export function format(message: string, args: FormatType[]): string {
let result = message;
if (args.length > 0) {
result = message.replace(/\{(\d+)\}/g, (match, rest) => {
const index = rest[0];
const arg = args[index];
let replacement = match;
if (typeof arg === 'string') {
replacement = arg;
} else if (typeof arg === 'number' || typeof arg === 'boolean' || !arg) {
replacement = String(arg);
}
return replacement;
});
}
return result;
const formatRegexp = /{([^}]+)}/g;

export function format(message: string, args: FormatType[]): string;
export function format(message: string, args: Record<string | number, FormatType>): string;
export function format(message: string, args: Record<string | number, FormatType> | FormatType[]): string {
return message.replace(formatRegexp, (match, group) => (args[group] ?? match) as string);
}

export function localize(localization: Localization | undefined, key: string, defaultValue: string, ...args: FormatType[]): string {
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/common/nls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ export namespace nls {

export let localization: Localization | undefined;

export const defaultLocale = 'en';

export const localeId = 'localeId';

export const locale = typeof window === 'object' && window && window.localStorage.getItem(localeId) || undefined;
Expand Down Expand Up @@ -57,7 +59,7 @@ export namespace nls {
}

export function isSelectedLocale(id: string): boolean {
if (locale === undefined && id === 'en') {
if (locale === undefined && id === defaultLocale) {
return true;
}
return locale === id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

import * as express from 'express';
import { inject, injectable } from 'inversify';
import { nls } from '../../common/nls';
import { Deferred } from '../../common/promise-util';
import { BackendApplicationContribution } from '../backend-application';
import { LocalizationRegistry } from './localization-contribution';
Expand Down Expand Up @@ -44,7 +45,7 @@ export class LocalizationBackendContribution implements BackendApplicationContri
app.get('/i18n/:locale', async (req, res) => {
await this.waitForInitialization();
let locale = req.params.locale;
locale = this.localizationProvider.getAvailableLanguages().some(e => e.languageId === locale) ? locale : 'en';
locale = this.localizationProvider.getAvailableLanguages().some(e => e.languageId === locale) ? locale : nls.defaultLocale;
this.localizationProvider.setCurrentLanguage(locale);
res.send(this.localizationProvider.loadLocalization(locale));
});
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/node/i18n/localization-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@
// *****************************************************************************

import { injectable } from 'inversify';
import { nls } from '../../common/nls';
import { LanguageInfo, Localization } from '../../common/i18n/localization';

@injectable()
export class LocalizationProvider {

protected localizations: Localization[] = [];
protected currentLanguage = 'en';
protected currentLanguage = nls.defaultLocale;

addLocalizations(...localizations: Localization[]): void {
this.localizations.push(...localizations);
Expand Down
1 change: 1 addition & 0 deletions packages/plugin-ext-vscode/src/node/scanner-vscode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export class VsCodePluginScanner extends TheiaPluginScanner implements PluginSca
},
entryPoint,
iconUrl: plugin.icon && PluginPackage.toPluginUrl(plugin, plugin.icon),
l10n: plugin.l10n,
readmeUrl: PluginPackage.toPluginUrl(plugin, './README.md'),
licenseUrl: PluginPackage.toPluginUrl(plugin, './LICENSE')
};
Expand Down
34 changes: 34 additions & 0 deletions packages/plugin-ext/src/common/language-pack-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// *****************************************************************************
// Copyright (C) 2023 TypeFox and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// This Source Code may also be made available under the following Secondary
// Licenses when the conditions for such availability set forth in the Eclipse
// Public License v. 2.0 are satisfied: GNU General Public License, version 2
// with the GNU Classpath Exception which is available at
// https://www.gnu.org/software/classpath/license.html.
//
// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
// *****************************************************************************

/**
* Starting with vscode 1.73.0, language pack bundles have changed their shape to accomodate the new `l10n` API.
* They are now a record of { [englishValue]: translation }
*/
export interface LanguagePackBundle {
contents: Record<string, string>
uri: string
}

export const languagePackServicePath = '/services/languagePackService';

export const LanguagePackService = Symbol('LanguagePackService');

export interface LanguagePackService {
storeBundle(pluginId: string, locale: string, bundle: LanguagePackBundle): void;
deleteBundle(pluginId: string, locale?: string): void;
getBundle(pluginId: string, locale: string): Promise<LanguagePackBundle | undefined>;
}
21 changes: 20 additions & 1 deletion packages/plugin-ext/src/common/plugin-api-rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ import { Disposable } from '@theia/core/lib/common/disposable';
import { isString, isObject, PickOptions, QuickInputButtonHandle } from '@theia/core/lib/common';
import { Severity } from '@theia/core/lib/common/severity';
import { DebugConfiguration, DebugSessionOptions } from '@theia/debug/lib/common/debug-configuration';
import { LanguagePackBundle } from './language-pack-service';

export interface PreferenceData {
[scope: number]: any;
Expand Down Expand Up @@ -2110,7 +2111,8 @@ export const PLUGIN_RPC_CONTEXT = {
TIMELINE_MAIN: <ProxyIdentifier<TimelineMain>>createProxyIdentifier<TimelineMain>('TimelineMain'),
THEMING_MAIN: <ProxyIdentifier<ThemingMain>>createProxyIdentifier<ThemingMain>('ThemingMain'),
COMMENTS_MAIN: <ProxyIdentifier<CommentsMain>>createProxyIdentifier<CommentsMain>('CommentsMain'),
TABS_MAIN: <ProxyIdentifier<TabsMain>>createProxyIdentifier<TabsMain>('TabsMain')
TABS_MAIN: <ProxyIdentifier<TabsMain>>createProxyIdentifier<TabsMain>('TabsMain'),
LOCALIZATION_MAIN: <ProxyIdentifier<LocalizationMain>>createProxyIdentifier<LocalizationMain>('LocalizationMain'),
};

export const MAIN_RPC_CONTEXT = {
Expand Down Expand Up @@ -2217,3 +2219,20 @@ export interface IdentifiableInlineCompletions extends InlineCompletions<Identif
export interface IdentifiableInlineCompletion extends InlineCompletion {
idx: number;
}

export interface LocalizationExt {
translateMessage(pluginId: string, details: StringDetails): string;
getBundle(pluginId: string): Record<string, string> | undefined;
getBundleUri(pluginId: string): theia.Uri | undefined;
initializeLocalizedMessages(plugin: Plugin, currentLanguage: string): Promise<void>;
}

export interface StringDetails {
message: string;
args?: Record<string | number, any>;
comment?: string | string[];
}

export interface LocalizationMain {
$fetchBundle(id: string): Promise<LanguagePackBundle | undefined>;
}
2 changes: 2 additions & 0 deletions packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export interface PluginPackage {
activationEvents?: string[];
extensionDependencies?: string[];
extensionPack?: string[];
l10n?: string;
icon?: string;
extensionKind?: Array<'ui' | 'workspace'>
}
Expand Down Expand Up @@ -544,6 +545,7 @@ export interface PluginModel {
*/
packagePath: string;
iconUrl?: string;
l10n?: string;
readmeUrl?: string;
licenseUrl?: string;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ export class HostedPluginSupport {
workspaceState,
env: {
queryParams: getQueryParameters(),
language: nls.locale || 'en',
language: nls.locale || nls.defaultLocale,
shell: defaultShell,
uiKind: isElectron ? UIKind.Desktop : UIKind.Web,
appName: FrontendApplicationConfigProvider.get().applicationName,
Expand Down
7 changes: 5 additions & 2 deletions packages/plugin-ext/src/hosted/browser/worker/worker-main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import { WorkspaceExtImpl } from '../../../plugin/workspace';
import { createDebugExtStub } from './debug-stub';
import { loadManifest } from './plugin-manifest-loader';
import { WorkerEnvExtImpl } from './worker-env-ext';
import { LocalizationExtImpl } from '../../../plugin/localization-ext';

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const ctx = self as any;
Expand Down Expand Up @@ -77,6 +78,7 @@ const debugExt = createDebugExtStub(rpc);
const clipboardExt = new ClipboardExt(rpc);
const webviewExt = new WebviewsExtImpl(rpc, workspaceExt);
const secretsExt = new SecretsExtImpl(rpc);
const localizationExt = new LocalizationExtImpl(rpc);
const terminalService: TerminalServiceExt = new TerminalServiceExtImpl(rpc);

const pluginManager = new PluginManagerExtImpl({
Expand Down Expand Up @@ -171,7 +173,7 @@ const pluginManager = new PluginManagerExtImpl({
}
}
}
}, envExt, terminalService, storageProxy, secretsExt, preferenceRegistryExt, webviewExt, rpc);
}, envExt, terminalService, storageProxy, secretsExt, preferenceRegistryExt, webviewExt, localizationExt, rpc);

const apiFactory = createAPIFactory(
rpc,
Expand All @@ -183,7 +185,8 @@ const apiFactory = createAPIFactory(
workspaceExt,
messageRegistryExt,
clipboardExt,
webviewExt
webviewExt,
localizationExt
);
let defaultApi: typeof theia;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export class HostedPluginDeployerHandler implements PluginDeployerHandler {
if (await this.deployPlugin(plugin, 'backend')) { successes++; }
}
// rebuild translation config after deployment
this.localizationService.buildTranslationConfig([...this.deployedBackendPlugins.values()]);
await this.localizationService.buildTranslationConfig([...this.deployedBackendPlugins.values()]);
// resolve on first deploy
this.backendPluginsMetadataDeferred.resolve(undefined);
return successes;
Expand Down Expand Up @@ -174,7 +174,7 @@ export class HostedPluginDeployerHandler implements PluginDeployerHandler {
const { type } = entry;
const deployed: DeployedPlugin = { metadata, type };
deployed.contributes = this.reader.readContribution(manifest);
this.localizationService.deployLocalizations(deployed);
await this.localizationService.deployLocalizations(deployed);
deployedPlugins.set(id, deployed);
deployPlugin.debug(`Deployed ${entryPoint} plugin "${id}" from "${metadata.model.entryPoint[entryPoint] || pluginPath}"`);
} catch (e) {
Expand Down

0 comments on commit 6d2e0ce

Please sign in to comment.