Path: blob/main/src/vs/workbench/api/common/extHostLocalizationService.ts
3296 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { LANGUAGE_DEFAULT } from '../../../base/common/platform.js';6import { format2 } from '../../../base/common/strings.js';7import { URI } from '../../../base/common/uri.js';8import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';9import { createDecorator } from '../../../platform/instantiation/common/instantiation.js';10import { ILogService } from '../../../platform/log/common/log.js';11import { ExtHostLocalizationShape, IStringDetails, MainContext, MainThreadLocalizationShape } from './extHost.protocol.js';12import { IExtHostInitDataService } from './extHostInitDataService.js';13import { IExtHostRpcService } from './extHostRpcService.js';1415export class ExtHostLocalizationService implements ExtHostLocalizationShape {16readonly _serviceBrand: undefined;1718private readonly _proxy: MainThreadLocalizationShape;19private readonly currentLanguage: string;20private readonly isDefaultLanguage: boolean;2122private readonly bundleCache: Map<string, { contents: { [key: string]: string }; uri: URI }> = new Map();2324constructor(25@IExtHostInitDataService initData: IExtHostInitDataService,26@IExtHostRpcService rpc: IExtHostRpcService,27@ILogService private readonly logService: ILogService28) {29this._proxy = rpc.getProxy(MainContext.MainThreadLocalization);30this.currentLanguage = initData.environment.appLanguage;31this.isDefaultLanguage = this.currentLanguage === LANGUAGE_DEFAULT;32}3334getMessage(extensionId: string, details: IStringDetails): string {35const { message, args, comment } = details;36if (this.isDefaultLanguage) {37return format2(message, (args ?? {}));38}3940let key = message;41if (comment && comment.length > 0) {42key += `/${Array.isArray(comment) ? comment.join('') : comment}`;43}44const str = this.bundleCache.get(extensionId)?.contents[key];45if (!str) {46this.logService.warn(`Using default string since no string found in i18n bundle that has the key: ${key}`);47}48return format2(str ?? message, (args ?? {}));49}5051getBundle(extensionId: string): { [key: string]: string } | undefined {52return this.bundleCache.get(extensionId)?.contents;53}5455getBundleUri(extensionId: string): URI | undefined {56return this.bundleCache.get(extensionId)?.uri;57}5859async initializeLocalizedMessages(extension: IExtensionDescription): Promise<void> {60if (this.isDefaultLanguage61|| (!extension.l10n && !extension.isBuiltin)62) {63return;64}6566if (this.bundleCache.has(extension.identifier.value)) {67return;68}6970let contents: { [key: string]: string } | undefined;71const bundleUri = await this.getBundleLocation(extension);72if (!bundleUri) {73this.logService.error(`No bundle location found for extension ${extension.identifier.value}`);74return;75}7677try {78const response = await this._proxy.$fetchBundleContents(bundleUri);79const result = JSON.parse(response);80// 'contents.bundle' is a well-known key in the language pack json file that contains the _code_ translations for the extension81contents = extension.isBuiltin ? result.contents?.bundle : result;82} catch (e) {83this.logService.error(`Failed to load translations for ${extension.identifier.value} from ${bundleUri}: ${e.message}`);84return;85}8687if (contents) {88this.bundleCache.set(extension.identifier.value, {89contents,90uri: bundleUri91});92}93}9495private async getBundleLocation(extension: IExtensionDescription): Promise<URI | undefined> {96if (extension.isBuiltin) {97const uri = await this._proxy.$fetchBuiltInBundleUri(extension.identifier.value, this.currentLanguage);98return URI.revive(uri);99}100101return extension.l10n102? URI.joinPath(extension.extensionLocation, extension.l10n, `bundle.l10n.${this.currentLanguage}.json`)103: undefined;104}105}106107export const IExtHostLocalizationService = createDecorator<IExtHostLocalizationService>('IExtHostLocalizationService');108export interface IExtHostLocalizationService extends ExtHostLocalizationService { }109110111