This commit is contained in:
Sandeep Somavarapu 2018-02-05 16:33:55 +01:00
parent 75cf5c46bd
commit 191596365d
13 changed files with 325 additions and 177 deletions

View file

@ -66,6 +66,10 @@
"name": "vs/workbench/parts/markers",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/localizations",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/parts/logs",
"project": "vscode-workbench"

View file

@ -28,9 +28,6 @@ export function activate(context: vscode.ExtensionContext): void {
//extensions suggestions
context.subscriptions.push(...registerExtensionsCompletions());
//locale suggestions
context.subscriptions.push(registerLocaleCompletionsInLanguageDocument());
// launch.json decorations
context.subscriptions.push(vscode.window.onDidChangeActiveTextEditor(editor => updateLaunchJsonDecorations(editor), null, context.subscriptions));
context.subscriptions.push(vscode.workspace.onDidChangeTextDocument(event => {
@ -109,20 +106,6 @@ function registerSettingsCompletions(): vscode.Disposable {
});
}
function registerLocaleCompletionsInLanguageDocument(): vscode.Disposable {
return vscode.languages.registerCompletionItemProvider({ pattern: '**/locale.json' }, {
provideCompletionItems(document, position, token) {
const location = getLocation(document.getText(), document.offsetAt(position));
const range = document.getWordRangeAtPosition(position) || new vscode.Range(position, position);
if (location.path[0] === 'locale') {
const extensionsContent = <IExtensionsContent>parse(document.getText());
return provideContributedLocalesProposals(range);
}
return [];
}
});
}
function provideContributedLocalesProposals(range: vscode.Range): vscode.ProviderResult<vscode.CompletionItem[] | vscode.CompletionList> {
const contributedLocales: string[] = [];
for (const extension of vscode.extensions.all) {

View file

@ -8,11 +8,9 @@
import { NodeCachedDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/nodeCachedDataCleaner';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { LanguagePacksCache } from 'vs/platform/localizations/node/localizations';
export function createSharedProcessContributions(service: IInstantiationService): IDisposable {
return combinedDisposable([
service.createInstance(NodeCachedDataCleaner),
service.createInstance(LanguagePacksCache)
]);
}

View file

@ -40,6 +40,9 @@ import { createSharedProcessContributions } from 'vs/code/electron-browser/share
import { createSpdLogService } from 'vs/platform/log/node/spdlogService';
import { ILogService, LogLevel } from 'vs/platform/log/common/log';
import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/common/logIpc';
import { LocalizationsService } from 'vs/platform/localizations/node/localizations';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
import { LocalizationsChannel } from 'vs/platform/localizations/common/localizationsIpc';
export interface ISharedProcessConfiguration {
readonly machineId: string;
@ -141,6 +144,7 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
services.set(ILocalizationsService, new SyncDescriptor(LocalizationsService));
const instantiationService2 = instantiationService.createChild(services);
@ -152,6 +156,10 @@ function main(server: Server, initData: ISharedProcessInitData, configuration: I
// clean up deprecated extensions
(extensionManagementService as ExtensionManagementService).removeDeprecatedExtensions();
const localizationsService = accessor.get(ILocalizationsService);
const localizationsChannel = new LocalizationsChannel(localizationsService);
server.registerChannel('localizations', localizationsChannel);
createSharedProcessContributions(instantiationService2);
});
});

View file

@ -4,9 +4,9 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import { localize } from 'vs/nls';
import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { TPromise } from 'vs/base/common/winjs.base';
import Event from 'vs/base/common/event';
export interface ILocalization {
languageId: string;
@ -23,6 +23,9 @@ export interface ITranslation {
export const ILocalizationsService = createDecorator<ILocalizationsService>('localizationsService');
export interface ILocalizationsService {
_serviceBrand: any;
readonly onDidLanguagesChange: Event<void>;
getLanguageIds(): TPromise<string[]>;
}
export function isValidLocalization(localization: ILocalization): boolean {
@ -47,51 +50,4 @@ export function isValidLocalization(localization: ILocalization): boolean {
return false;
}
return true;
}
ExtensionsRegistry.registerExtensionPoint('localizations', [], {
description: localize('vscode.extension.contributes.localizations', "Contributes localizations to the editor"),
type: 'array',
default: [],
items: {
type: 'object',
required: ['languageId', 'translations'],
defaultSnippets: [{ body: { languageId: '', languageName: '', languageNameLocalized: '', translations: [{ id: 'vscode', path: '' }] } }],
properties: {
languageId: {
description: localize('vscode.extension.contributes.localizations.languageId', 'Id of the language into which the display strings are translated.'),
type: 'string'
},
languageName: {
description: localize('vscode.extension.contributes.localizations.languageName', 'Name of the language in English.'),
type: 'string'
},
languageNameLocalized: {
description: localize('vscode.extension.contributes.localizations.languageNameLocalized', 'Name of the language in contributed language.'),
type: 'string'
},
translations: {
description: localize('vscode.extension.contributes.localizations.translations', 'List of translations associated to the language.'),
type: 'array',
default: [{ id: 'vscode', path: '' }],
items: {
type: 'object',
required: ['id', 'path'],
properties: {
id: {
type: 'string',
description: localize('vscode.extension.contributes.localizations.translations.id', "Id of VS Code or Extension for which this translation is contributed to. Id of VS Code is always `vscode` and of extension should be in format `publisherId.extensionName`."),
pattern: '^((vscode)|([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*))$',
patternErrorMessage: localize('vscode.extension.contributes.localizations.translations.id.pattern', "Id should be `vscode` or in format `publisherId.extensionName` for translating VS code or an extension respectively.")
},
path: {
type: 'string',
description: localize('vscode.extension.contributes.localizations.translations.path', "A relative path to a file containing translations for the language.")
}
},
defaultSnippets: [{ body: { id: '', path: '' } }],
},
}
}
}
});
}

View file

@ -0,0 +1,48 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
import { TPromise } from 'vs/base/common/winjs.base';
import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc';
import Event, { buffer } from 'vs/base/common/event';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
export interface ILocalizationsChannel extends IChannel {
call(command: 'event:onDidLanguagesChange'): TPromise<void>;
call(command: 'getLanguageIds'): TPromise<string[]>;
call(command: string, arg?: any): TPromise<any>;
}
export class LocalizationsChannel implements ILocalizationsChannel {
onDidLanguagesChange: Event<void>;
constructor(private service: ILocalizationsService) {
this.onDidLanguagesChange = buffer(service.onDidLanguagesChange, true);
}
call(command: string, arg?: any): TPromise<any> {
switch (command) {
case 'event:onDidLanguagesChange': return eventToCall(this.onDidLanguagesChange);
case 'getLanguageIds': return this.service.getLanguageIds();
}
return undefined;
}
}
export class LocalizationsChannelClient implements ILocalizationsService {
_serviceBrand: any;
constructor(private channel: ILocalizationsChannel) { }
private _onDidLanguagesChange = eventFromCall<void>(this.channel, 'event:onDidLanguagesChange');
get onDidLanguagesChange(): Event<void> { return this._onDidLanguagesChange; }
getLanguageIds(): TPromise<string[]> {
return this.channel.call('getLanguageIds');
}
}

View file

@ -11,9 +11,12 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { join } from 'vs/base/common/paths';
import { TPromise } from 'vs/base/common/winjs.base';
import { Limiter } from 'vs/base/common/async';
import { areSameExtensions, getGalleryExtensionIdFromLocal } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { areSameExtensions, getGalleryExtensionIdFromLocal, getIdFromLocalExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ILogService } from 'vs/platform/log/common/log';
import { isValidLocalization } from 'vs/platform/localizations/common/localizations';
import { isValidLocalization, ILocalizationsService } from 'vs/platform/localizations/common/localizations';
import product from 'vs/platform/node/product';
import { distinct, equals } from 'vs/base/common/arrays';
import Event, { Emitter } from 'vs/base/common/event';
interface ILanguagePack {
hash: string;
@ -24,10 +27,19 @@ interface ILanguagePack {
translations: { [id: string]: string };
}
export class LanguagePacksCache extends Disposable {
const systemLanguages: string[] = ['de', 'en', 'en-US', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-CN', 'zh-TW'];
if (product.quality !== 'stable') {
systemLanguages.push('hu');
}
private languagePacksFilePath: string;
private languagePacksFileLimiter: Limiter<void>;
export class LocalizationsService extends Disposable implements ILocalizationsService {
_serviceBrand: any;
private readonly cache: LanguagePacksCache;
private readonly _onDidLanguagesChange: Emitter<void> = this._register(new Emitter<void>());
readonly onDidLanguagesChange: Event<void> = this._onDidLanguagesChange.event;
constructor(
@IExtensionManagementService private extensionManagementService: IExtensionManagementService,
@ -35,37 +47,80 @@ export class LanguagePacksCache extends Disposable {
@ILogService private logService: ILogService
) {
super();
this.languagePacksFilePath = join(environmentService.userDataPath, 'languagepacks.json');
this.languagePacksFileLimiter = new Limiter(1);
this.cache = this._register(new LanguagePacksCache(environmentService, logService));
this._register(extensionManagementService.onDidInstallExtension(({ local }) => this.onDidInstallExtension(local)));
this._register(extensionManagementService.onDidUninstallExtension(({ identifier }) => this.onDidUninstallExtension(identifier)));
this.reset();
this.extensionManagementService.getInstalled().then(installed => this.cache.update(installed));
}
getLanguageIds(): TPromise<string[]> {
return this.cache.getLanguagePacks()
.then(languagePacks => {
const languages = [...systemLanguages, ...Object.keys(languagePacks)];
return TPromise.as(distinct(languages));
});
}
private onDidInstallExtension(extension: ILocalExtension): void {
if (extension && extension.manifest && extension.manifest.contributes && extension.manifest.contributes.localizations && extension.manifest.contributes.localizations.length) {
this.logService.debug('Adding language packs from the extension', extension.identifier.id);
this.reset();
this.update();
}
}
private onDidUninstallExtension(identifier: IExtensionIdentifier): void {
if (this.withLanguagePacks(languagePacks => Object.keys(languagePacks).some(language => languagePacks[language] && languagePacks[language].extensions.some(e => areSameExtensions(e.extensionIdentifier, identifier))))) {
this.logService.debug('Removing language packs from the extension', identifier.id);
this.reset();
}
this.cache.getLanguagePacks()
.then(languagePacks => {
identifier = { id: getIdFromLocalExtensionId(identifier.id), uuid: identifier.uuid };
if (Object.keys(languagePacks).some(language => languagePacks[language] && languagePacks[language].extensions.some(e => areSameExtensions(e.extensionIdentifier, identifier)))) {
this.logService.debug('Removing language packs from the extension', identifier.id);
this.update();
}
});
}
private reset(): void {
this.extensionManagementService.getInstalled()
.then(installed => {
this.withLanguagePacks(languagePacks => {
Object.keys(languagePacks).forEach(language => languagePacks[language] = undefined);
this.createLanguagePacksFromExtensions(languagePacks, ...installed);
});
});
private update(): void {
TPromise.join([this.cache.getLanguagePacks(), this.extensionManagementService.getInstalled()])
.then(([current, installed]) => this.cache.update(installed)
.then(updated => {
if (!equals(Object.keys(current), Object.keys(updated))) {
this._onDidLanguagesChange.fire();
}
}));
}
}
class LanguagePacksCache extends Disposable {
private languagePacks: { [language: string]: ILanguagePack } = {};
private languagePacksFilePath: string;
private languagePacksFileLimiter: Limiter<void>;
constructor(
@IEnvironmentService environmentService: IEnvironmentService,
@ILogService private logService: ILogService
) {
super();
this.languagePacksFilePath = join(environmentService.userDataPath, 'languagepacks.json');
this.languagePacksFileLimiter = new Limiter(1);
}
getLanguagePacks(): TPromise<{ [language: string]: ILanguagePack }> {
// if queue is not empty, fetch from disk
if (this.languagePacksFileLimiter.size) {
return this.withLanguagePacks()
.then(() => this.languagePacks);
}
return TPromise.as(this.languagePacks);
}
update(extensions: ILocalExtension[]): TPromise<{ [language: string]: ILanguagePack }> {
return this.withLanguagePacks(languagePacks => {
Object.keys(languagePacks).forEach(language => languagePacks[language] = undefined);
this.createLanguagePacksFromExtensions(languagePacks, ...extensions);
}).then(() => this.languagePacks);
}
private createLanguagePacksFromExtensions(languagePacks: { [language: string]: ILanguagePack }, ...extensions: ILocalExtension[]): void {
@ -109,7 +164,7 @@ export class LanguagePacksCache extends Disposable {
}
}
private withLanguagePacks<T>(fn: (languagePacks: { [language: string]: ILanguagePack }) => T): TPromise<T> {
private withLanguagePacks<T>(fn: (languagePacks: { [language: string]: ILanguagePack }) => T = () => null): TPromise<T> {
return this.languagePacksFileLimiter.queue(() => {
let result: T = null;
return pfs.readFile(this.languagePacksFilePath, 'utf8')
@ -122,7 +177,8 @@ export class LanguagePacksCache extends Disposable {
delete languagePacks[language];
}
}
const raw = JSON.stringify(languagePacks);
this.languagePacks = languagePacks;
const raw = JSON.stringify(this.languagePacks);
this.logService.debug('Writing language packs', raw);
return pfs.writeFile(this.languagePacksFilePath, raw);
})

View file

@ -23,7 +23,7 @@ import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configur
import { IExtensionManagementService, LocalExtensionType, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IWorkspaceConfigurationService } from 'vs/workbench/services/configuration/common/configuration';
import paths = require('vs/base/common/paths');
import { isMacintosh, isLinux, language } from 'vs/base/common/platform';
import { isMacintosh, isLinux } from 'vs/base/common/platform';
import { IQuickOpenService, IFilePickOpenEntry, ISeparator, IPickOpenAction, IPickOpenItem } from 'vs/platform/quickOpen/common/quickOpen';
import * as browser from 'vs/base/browser/browser';
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
@ -40,11 +40,10 @@ import { getPathLabel, getBaseLabel } from 'vs/base/common/labels';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IPanel } from 'vs/workbench/common/panel';
import { IWorkspaceIdentifier, getWorkspaceLabel, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
import { FileKind, IFileService } from 'vs/platform/files/common/files';
import { FileKind } from 'vs/platform/files/common/files';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IExtensionService, ActivationTimes } from 'vs/platform/extensions/common/extensions';
import { getEntries } from 'vs/base/common/performance';
import { IEditor } from 'vs/platform/editor/common/editor';
import { IIssueService, IssueReporterData, IssueType, IssueReporterStyles } from 'vs/platform/issue/common/issue';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { textLinkForeground, inputBackground, inputBorder, inputForeground, buttonBackground, buttonHoverBackground, buttonForeground, inputValidationErrorBorder, foreground, inputActiveOptionBorder } from 'vs/platform/theme/common/colorRegistry';
@ -1605,46 +1604,4 @@ export class ToggleWindowTabsBar extends Action {
public run(): TPromise<boolean> {
return this.windowsService.toggleWindowTabsBar().then(() => true);
}
}
export class ConfigureLocaleAction extends Action {
public static readonly ID = 'workbench.action.configureLocale';
public static readonly LABEL = nls.localize('configureLocale', "Configure Language");
private static DEFAULT_CONTENT: string = [
'{',
`\t// ${nls.localize('displayLanguage', 'Defines VSCode\'s display language.')}`,
`\t// ${nls.localize('doc', 'See {0} for a list of supported languages.', 'https://go.microsoft.com/fwlink/?LinkId=761051')}`,
`\t// ${nls.localize('restart', 'Changing the value requires restarting VSCode.')}`,
`\t"locale":"${language}"`,
'}'
].join('\n');
constructor(id: string, label: string,
@IFileService private fileService: IFileService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IEnvironmentService private environmentService: IEnvironmentService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
) {
super(id, label);
}
public run(event?: any): TPromise<IEditor> {
const file = URI.file(paths.join(this.environmentService.appSettingsHome, 'locale.json'));
return this.fileService.resolveFile(file).then(null, (error) => {
return this.fileService.createFile(file, ConfigureLocaleAction.DEFAULT_CONTENT);
}).then((stat) => {
if (!stat) {
return undefined;
}
return this.editorService.openEditor({
resource: stat.resource,
options: {
forceOpen: true
}
});
}, (error) => {
throw new Error(nls.localize('fail.createSettings', "Unable to create '{0}' ({1}).", getPathLabel(file, this.contextService), error));
});
}
}
}

View file

@ -14,15 +14,13 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenIssueReporterAction, ReportPerformanceIssueUsingReporterAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey, ConfigureLocaleAction } from 'vs/workbench/electron-browser/actions';
import { KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, OpenTipsAndTricksUrlAction, OpenIssueReporterAction, ReportPerformanceIssueUsingReporterAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseWorkspaceAction, CloseCurrentWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction, IncreaseViewSizeAction, DecreaseViewSizeAction, ShowStartupPerformance, ToggleSharedProcessAction, QuickSwitchWindow, QuickOpenRecentAction, inRecentFilesPickerContextKey } from 'vs/workbench/electron-browser/actions';
import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { registerCommands } from 'vs/workbench/electron-browser/commands';
import { AddRootFolderAction, GlobalRemoveRootFolderAction, OpenWorkspaceAction, SaveWorkspaceAsAction, OpenWorkspaceConfigFileAction, OpenFolderAsWorkspaceInNewWindowAction, OpenFileFolderAction, OpenFileAction, OpenFolderAction } from 'vs/workbench/browser/actions/workspaceActions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { inQuickOpenContext, getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen';
import { KeybindingsRegistry } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
// Contribute Commands
registerCommands();
@ -425,38 +423,4 @@ configurationRegistry.registerConfiguration({
'description': nls.localize('zenMode.restore', "Controls if a window should restore to zen mode if it was exited in zen mode.")
}
}
});
// Register action to configure locale and related settings
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLocaleAction, ConfigureLocaleAction.ID, ConfigureLocaleAction.LABEL), 'Configure Language');
let enumValues: string[] = ['de', 'en', 'en-US', 'es', 'fr', 'it', 'ja', 'ko', 'ru', 'zh-CN', 'zh-TW'];
if (product.quality !== 'stable') {
enumValues.push('hu');
}
const schemaId = 'vscode://schemas/locale';
// Keep en-US since we generated files with that content.
const schema: IJSONSchema =
{
id: schemaId,
allowComments: true,
description: 'Locale Definition file',
type: 'object',
default: {
'locale': 'en'
},
required: ['locale'],
properties: {
locale: {
type: 'string',
enum: enumValues,
description: nls.localize('JsonSchema.locale', 'The UI Language to use.')
}
}
};
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
jsonRegistry.registerSchema(schemaId, schema);
});

View file

@ -90,6 +90,8 @@ import { ILogService } from 'vs/platform/log/common/log';
import { WORKBENCH_BACKGROUND } from 'vs/workbench/common/theme';
import { stat } from 'fs';
import { join } from 'path';
import { ILocalizationsChannel, LocalizationsChannelClient } from 'vs/platform/localizations/common/localizationsIpc';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
/**
* Services that we require for the Shell
@ -447,6 +449,9 @@ export class WorkbenchShell {
serviceCollection.set(IIntegrityService, new SyncDescriptor(IntegrityServiceImpl));
const localizationsChannel = getDelayedChannel<ILocalizationsChannel>(sharedProcess.then(c => c.getChannel('localizations')));
serviceCollection.set(ILocalizationsService, new SyncDescriptor(LocalizationsChannelClient, localizationsChannel));
return [instantiationService, serviceCollection];
}

View file

@ -0,0 +1,110 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContribution, Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { IJSONContributionRegistry, Extensions as JSONExtensions } from 'vs/platform/jsonschemas/common/jsonContributionRegistry';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { Disposable } from 'vs/base/common/lifecycle';
import { ConfigureLocaleAction } from 'vs/workbench/parts/localizations/browser/localizationsActions';
import { ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry';
import { ILocalizationsService } from 'vs/platform/localizations/common/localizations';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { language } from 'vs/base/common/platform';
// Register action to configure locale and related settings
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ConfigureLocaleAction, ConfigureLocaleAction.ID, ConfigureLocaleAction.LABEL), 'Configure Language');
export class LocalesSchemaUpdater extends Disposable implements IWorkbenchContribution {
constructor(
@ILocalizationsService private localizationService: ILocalizationsService
) {
super();
this.update();
this._register(this.localizationService.onDidLanguagesChange(() => this.update()));
}
private update(): void {
this.localizationService.getLanguageIds()
.then(languageIds => registerLocaleDefinitionSchema(languageIds));
}
}
function registerLocaleDefinitionSchema(languages: string[]): void {
const localeDefinitionFileSchemaId = 'vscode://schemas/locale';
const jsonRegistry = Registry.as<IJSONContributionRegistry>(JSONExtensions.JSONContribution);
// Keep en-US since we generated files with that content.
jsonRegistry.registerSchema(localeDefinitionFileSchemaId, {
id: localeDefinitionFileSchemaId,
allowComments: true,
description: 'Locale Definition file',
type: 'object',
default: {
'locale': 'en'
},
required: ['locale'],
properties: {
locale: {
type: 'string',
enum: languages,
description: localize('JsonSchema.locale', 'The UI Language to use.')
}
}
});
}
registerLocaleDefinitionSchema([language]);
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(LocalesSchemaUpdater, LifecyclePhase.Eventually);
ExtensionsRegistry.registerExtensionPoint('localizations', [], {
description: localize('vscode.extension.contributes.localizations', "Contributes localizations to the editor"),
type: 'array',
default: [],
items: {
type: 'object',
required: ['languageId', 'translations'],
defaultSnippets: [{ body: { languageId: '', languageName: '', languageNameLocalized: '', translations: [{ id: 'vscode', path: '' }] } }],
properties: {
languageId: {
description: localize('vscode.extension.contributes.localizations.languageId', 'Id of the language into which the display strings are translated.'),
type: 'string'
},
languageName: {
description: localize('vscode.extension.contributes.localizations.languageName', 'Name of the language in English.'),
type: 'string'
},
languageNameLocalized: {
description: localize('vscode.extension.contributes.localizations.languageNameLocalized', 'Name of the language in contributed language.'),
type: 'string'
},
translations: {
description: localize('vscode.extension.contributes.localizations.translations', 'List of translations associated to the language.'),
type: 'array',
default: [{ id: 'vscode', path: '' }],
items: {
type: 'object',
required: ['id', 'path'],
properties: {
id: {
type: 'string',
description: localize('vscode.extension.contributes.localizations.translations.id', "Id of VS Code or Extension for which this translation is contributed to. Id of VS Code is always `vscode` and of extension should be in format `publisherId.extensionName`."),
pattern: '^((vscode)|([a-z0-9A-Z][a-z0-9\-A-Z]*)\\.([a-z0-9A-Z][a-z0-9\-A-Z]*))$',
patternErrorMessage: localize('vscode.extension.contributes.localizations.translations.id.pattern', "Id should be `vscode` or in format `publisherId.extensionName` for translating VS code or an extension respectively.")
},
path: {
type: 'string',
description: localize('vscode.extension.contributes.localizations.translations.path', "A relative path to a file containing translations for the language.")
}
},
defaultSnippets: [{ body: { id: '', path: '' } }],
},
}
}
}
});

View file

@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { IFileService } from 'vs/platform/files/common/files';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { TPromise } from 'vs/base/common/winjs.base';
import { IEditor } from 'vs/platform/editor/common/editor';
import { join } from 'vs/base/common/paths';
import URI from 'vs/base/common/uri';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { getPathLabel } from 'vs/base/common/labels';
import { language } from 'vs/base/common/platform';
export class ConfigureLocaleAction extends Action {
public static readonly ID = 'workbench.action.configureLocale';
public static readonly LABEL = localize('configureLocale', "Configure Language");
private static DEFAULT_CONTENT: string = [
'{',
`\t// ${localize('displayLanguage', 'Defines VSCode\'s display language.')}`,
`\t// ${localize('doc', 'See {0} for a list of supported languages.', 'https://go.microsoft.com/fwlink/?LinkId=761051')}`,
`\t// ${localize('restart', 'Changing the value requires restarting VSCode.')}`,
`\t"locale":"${language}"`,
'}'
].join('\n');
constructor(id: string, label: string,
@IFileService private fileService: IFileService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IEnvironmentService private environmentService: IEnvironmentService,
@IWorkbenchEditorService private editorService: IWorkbenchEditorService
) {
super(id, label);
}
public run(event?: any): TPromise<IEditor> {
const file = URI.file(join(this.environmentService.appSettingsHome, 'locale.json'));
return this.fileService.resolveFile(file).then(null, (error) => {
return this.fileService.createFile(file, ConfigureLocaleAction.DEFAULT_CONTENT);
}).then((stat) => {
if (!stat) {
return undefined;
}
return this.editorService.openEditor({
resource: stat.resource,
options: {
forceOpen: true
}
});
}, (error) => {
throw new Error(localize('fail.createSettings', "Unable to create '{0}' ({1}).", getPathLabel(file, this.contextService), error));
});
}
}

View file

@ -22,7 +22,7 @@ import 'vs/platform/actions/electron-browser/menusExtensionPoint';
import 'vs/workbench/api/browser/viewsExtensionPoint';
// Localizations
import 'vs/platform/localizations/common/localizations';
import 'vs/workbench/parts/localizations/browser/localizations.contribution';
// Workbench
import 'vs/workbench/browser/actions/toggleActivityBarVisibility';