From 413167b6d2a3fd238eef10565b5c5dd067f92f71 Mon Sep 17 00:00:00 2001 From: vince-fugnitto Date: Wed, 29 Jun 2022 10:22:43 -0400 Subject: [PATCH 1/3] nls: add additional localizations to dialogs Signed-off-by: vince-fugnitto --- .../file-dialog/file-dialog-service.ts | 6 ++--- .../src/browser/file-dialog/file-dialog.ts | 22 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/filesystem/src/browser/file-dialog/file-dialog-service.ts b/packages/filesystem/src/browser/file-dialog/file-dialog-service.ts index 686360348fbae..9626640c093d9 100644 --- a/packages/filesystem/src/browser/file-dialog/file-dialog-service.ts +++ b/packages/filesystem/src/browser/file-dialog/file-dialog-service.ts @@ -16,7 +16,7 @@ import { injectable, inject } from '@theia/core/shared/inversify'; import URI from '@theia/core/lib/common/uri'; -import { MaybeArray } from '@theia/core/lib/common'; +import { MaybeArray, nls } from '@theia/core/lib/common'; import { LabelProvider } from '@theia/core/lib/browser'; import { FileStat } from '../../common/files'; import { DirNode } from '../file-tree'; @@ -53,7 +53,7 @@ export class DefaultFileDialogService implements FileDialogService { async showOpenDialog(props: OpenFileDialogProps & { canSelectMany: true }, folder?: FileStat): Promise | undefined>; async showOpenDialog(props: OpenFileDialogProps, folder?: FileStat): Promise; async showOpenDialog(props: OpenFileDialogProps, folder?: FileStat): Promise | undefined> { - const title = props.title || 'Open'; + const title = props.title || nls.localizeByDefault('Open'); const rootNode = await this.getRootNode(folder); if (rootNode) { const dialog = this.openFileDialogFactory(Object.assign(props, { title })); @@ -70,7 +70,7 @@ export class DefaultFileDialogService implements FileDialogService { } async showSaveDialog(props: SaveFileDialogProps, folder?: FileStat): Promise { - const title = props.title || 'Save'; + const title = props.title || nls.localizeByDefault('Save'); const rootNode = await this.getRootNode(folder); if (rootNode) { const dialog = this.saveFileDialogFactory(Object.assign(props, { title })); diff --git a/packages/filesystem/src/browser/file-dialog/file-dialog.ts b/packages/filesystem/src/browser/file-dialog/file-dialog.ts index 61b9242ab932b..27c99ae48baef 100644 --- a/packages/filesystem/src/browser/file-dialog/file-dialog.ts +++ b/packages/filesystem/src/browser/file-dialog/file-dialog.ts @@ -25,6 +25,7 @@ import { FileDialogWidget } from './file-dialog-widget'; import { FileDialogTreeFiltersRenderer, FileDialogTreeFilters, FileDialogTreeFiltersRendererFactory } from './file-dialog-tree-filters-renderer'; import URI from '@theia/core/lib/common/uri'; import { Panel } from '@theia/core/shared/@phosphor/widgets'; +import * as DOMPurify from '@theia/core/shared/dompurify'; export const OpenFileDialogFactory = Symbol('OpenFileDialogFactory'); export interface OpenFileDialogFactory { @@ -153,16 +154,19 @@ export abstract class FileDialog extends AbstractDialog { navigationPanel.appendChild(this.back = createIconButton(...codiconArray('chevron-left', true))); this.back.classList.add(NAVIGATION_BACK_CLASS); - this.back.title = 'Navigate Back'; + this.back.title = nls.localize('theia/filesystem/dialog/navigateBack', 'Navigate Back'); + navigationPanel.appendChild(this.forward = createIconButton(...codiconArray('chevron-right', true))); this.forward.classList.add(NAVIGATION_FORWARD_CLASS); - this.forward.title = 'Navigate Forward'; + this.forward.title = nls.localize('theia/filesystem/dialog/navigateForward', 'Navigate Forward'); + navigationPanel.appendChild(this.home = createIconButton(...codiconArray('home', true))); this.home.classList.add(NAVIGATION_HOME_CLASS); - this.home.title = 'Go To Initial Location'; + this.home.title = nls.localize('theia/filesystem/dialog/initialLocation', 'Go To Initial Location'); + navigationPanel.appendChild(this.up = createIconButton(...codiconArray('arrow-up', true))); this.up.classList.add(NAVIGATION_UP_CLASS); - this.up.title = 'Navigate Up One Directory'; + this.up.title = nls.localize('theia/filesystem/dialog/navigateUp', 'Navigate Up One Directory'); const locationListRendererHost = document.createElement('div'); this.locationListRenderer = this.locationListFactory({ model: this.model, host: locationListRendererHost }); @@ -229,7 +233,7 @@ export abstract class FileDialog extends AbstractDialog { this.contentNode.appendChild(filtersPanel); const titlePanel = document.createElement('div'); - titlePanel.innerHTML = 'Format:'; + titlePanel.innerHTML = DOMPurify.sanitize(nls.localize('theia/filesystem/format', 'Format:')); titlePanel.classList.add(FILTERS_LABEL_CLASS); filtersPanel.appendChild(titlePanel); @@ -308,12 +312,12 @@ export class OpenFileDialog extends FileDialog> { } protected getAcceptButtonLabel(): string { - return this.props.openLabel ? this.props.openLabel : 'Open'; + return this.props.openLabel ? this.props.openLabel : nls.localizeByDefault('Open'); } protected override isValid(value: MaybeArray): string { if (value && !this.props.canSelectMany && value instanceof Array) { - return 'You can select only one item'; + return nls.localize('theia/filesystem/dialog/multipleItemMessage', 'You can select only one item'); } return ''; } @@ -358,7 +362,7 @@ export class SaveFileDialog extends FileDialog { } protected getAcceptButtonLabel(): string { - return this.props.saveLabel ? this.props.saveLabel : 'Save'; + return this.props.saveLabel ? this.props.saveLabel : nls.localizeByDefault('Save'); } protected override onUpdateRequest(msg: Message): void { @@ -407,7 +411,7 @@ export class SaveFileDialog extends FileDialog { this.contentNode.appendChild(fileNamePanel); const titlePanel = document.createElement('div'); - titlePanel.innerHTML = 'Name:'; + titlePanel.innerHTML = DOMPurify.sanitize(nls.localize('theia/filesystem/dialog/name', 'Name:')); titlePanel.classList.add(FILENAME_LABEL_CLASS); fileNamePanel.appendChild(titlePanel); From cbda95baa939a320538caa4d21ae53cdf398216d Mon Sep 17 00:00:00 2001 From: vince-fugnitto Date: Wed, 29 Jun 2022 10:54:09 -0400 Subject: [PATCH 2/3] keymaps: localize `keyboard shortcuts` Signed-off-by: vince-fugnitto --- .../src/browser/keybindings-widget.tsx | 28 ++++++++++--------- packages/keymaps/src/browser/style/index.css | 1 + 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/packages/keymaps/src/browser/keybindings-widget.tsx b/packages/keymaps/src/browser/keybindings-widget.tsx index 5edd8749ca85f..6df96a875047d 100644 --- a/packages/keymaps/src/browser/keybindings-widget.tsx +++ b/packages/keymaps/src/browser/keybindings-widget.tsx @@ -27,6 +27,7 @@ import { import { KeymapsService } from './keymaps-service'; import { AlertMessage } from '@theia/core/lib/browser/widgets/alert-message'; import { isOSX } from '@theia/core'; +import { nls } from '@theia/core/lib/common/nls'; /** * Representation of a keybinding item for the view. @@ -83,7 +84,7 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget { protected readonly keymapsService: KeymapsService; static readonly ID = 'keybindings.view.widget'; - static readonly LABEL = 'Keyboard Shortcuts'; + static readonly LABEL = nls.localizeByDefault('Keyboard Shortcuts'); /** * The list of all available keybindings. @@ -296,7 +297,7 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget { className={`theia-input${(this.items.length > 0) ? '' : ' no-kb'}`} type='text' spellCheck={false} - placeholder='Search keybindings' + placeholder={nls.localizeByDefault('Type to search in keybindings')} autoComplete='off' onKeyUp={this.searchKeybindings} /> @@ -324,10 +325,10 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget { - Command - Keybinding - Context / When - Source + {nls.localizeByDefault('Command')} + {nls.localizeByDefault('Keybinding')} + {nls.localizeByDefault('When')} + {nls.localizeByDefault('Source')} @@ -550,7 +551,7 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget { const command = item.command.id; const oldKeybinding = item.keybinding && item.keybinding.keybinding; const dialog = new EditKeybindingDialog({ - title: `Edit Keybinding for ${command}`, + title: nls.localize('theia/keymaps/editKeybindingTitle', 'Edit Keybinding for {0}', command), initialValue: oldKeybinding, validate: newKeybinding => this.validateKeybinding(command, oldKeybinding, newKeybinding), }, this.keymapsService, item); @@ -573,8 +574,8 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget { */ protected async confirmResetKeybinding(item: KeybindingItem): Promise { const dialog = new ConfirmDialog({ - title: `Reset keybinding for '${this.getCommandLabel(item.command)}'`, - msg: 'Do you really want to reset this keybinding to its default value?' + title: nls.localize('theia/keymaps/resetKeybindingTitle', 'Reset keybinding for {0}', this.getCommandLabel(item.command)), + msg: nls.localize('theia/keymaps/resetKeybindingConfirmation', 'Do you really want to reset this keybinding to its default value?') }); return !!await dialog.open(); } @@ -600,7 +601,7 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget { */ protected validateKeybinding(command: string, oldKeybinding: string | undefined, keybinding: string): string { if (!keybinding) { - return 'keybinding value is required'; + return nls.localize('theia/keymaps/requiredKeybindingValidation', 'keybinding value is required'); } try { const binding = { command, keybinding }; @@ -609,7 +610,7 @@ export class KeybindingWidget extends ReactWidget implements StatefulWidget { return ' '; // if old and new keybindings match, quietly reject update } if (this.keybindingRegistry.containsKeybindingInScope(binding)) { - return 'keybinding currently collides'; + return nls.localize('theia/keymaps/keybindingCollidesValidation', 'keybinding currently collides'); } return ''; } catch (error) { @@ -746,10 +747,11 @@ class EditKeybindingDialog extends SingleTextInputDialog { */ protected appendResetButton(): HTMLButtonElement { // Create the `Reset` button. - this.resetButton = this.createButton('Reset'); + const resetButtonTitle = nls.localizeByDefault('Reset'); + this.resetButton = this.createButton(resetButtonTitle); // Add the `Reset` button to the dialog control panel, before the `Accept` button. this.controlPanel.insertBefore(this.resetButton, this.acceptButton!); - this.resetButton.title = 'Reset Keybinding'; + this.resetButton.title = nls.localizeByDefault('Reset Keybinding'); this.resetButton.classList.add('secondary'); return this.resetButton; } diff --git a/packages/keymaps/src/browser/style/index.css b/packages/keymaps/src/browser/style/index.css index 606226d34b5ae..7cefcc39ae7d8 100644 --- a/packages/keymaps/src/browser/style/index.css +++ b/packages/keymaps/src/browser/style/index.css @@ -115,6 +115,7 @@ position: sticky; top: 0; background-color: var(--theia-editorWidget-background); + text-transform: capitalize; } .kb table .th-action { From 5a07a43523f1d8d590e8a905afc64c3a589fa6c6 Mon Sep 17 00:00:00 2001 From: vince-fugnitto Date: Wed, 29 Jun 2022 16:10:58 -0400 Subject: [PATCH 3/3] nls: add more localizations Signed-off-by: vince-fugnitto --- .../src/browser/connection-status-service.ts | 6 +++--- packages/core/src/browser/keybinding.ts | 3 ++- .../core/src/browser/shell/application-shell.ts | 8 +++++--- packages/core/src/browser/tree/search-box.ts | 9 +++++---- .../git/src/browser/diff/git-diff-widget.tsx | 3 ++- .../src/browser/hosted-plugin-informer.ts | 2 +- .../timeline/src/browser/timeline-widget.tsx | 3 ++- .../src/browser/vsx-extension-editor.tsx | 3 ++- .../src/browser/vsx-extensions-search-bar.tsx | 3 ++- .../src/browser/workspace-delete-handler.ts | 16 ++++++++-------- 10 files changed, 32 insertions(+), 24 deletions(-) diff --git a/packages/core/src/browser/connection-status-service.ts b/packages/core/src/browser/connection-status-service.ts index 8dda7fdfd8418..084bc66ee1a3d 100644 --- a/packages/core/src/browser/connection-status-service.ts +++ b/packages/core/src/browser/connection-status-service.ts @@ -20,7 +20,7 @@ import { Event, Emitter } from '../common/event'; import { DefaultFrontendApplicationContribution } from './frontend-application'; import { StatusBar, StatusBarAlignment } from './status-bar/status-bar'; import { WebSocketConnectionProvider } from './messaging/ws-connection-provider'; -import { Disposable, DisposableCollection } from '../common'; +import { Disposable, DisposableCollection, nls } from '../common'; /** * Service for listening on backend connection changes. @@ -205,8 +205,8 @@ export class ApplicationConnectionStatusContribution extends DefaultFrontendAppl protected handleOffline(): void { this.statusBar.setElement(this.statusbarId, { alignment: StatusBarAlignment.LEFT, - text: 'Offline', - tooltip: 'Cannot connect to backend.', + text: nls.localize('theia/core/offline', 'Offline'), + tooltip: nls.localize('theia/localize/offlineTooltip', 'Cannot connect to backend.'), priority: 5000 }); this.toDisposeOnOnline.push(Disposable.create(() => this.statusBar.removeElement(this.statusbarId))); diff --git a/packages/core/src/browser/keybinding.ts b/packages/core/src/browser/keybinding.ts index 8f943924996f1..1ec047727c1a0 100644 --- a/packages/core/src/browser/keybinding.ts +++ b/packages/core/src/browser/keybinding.ts @@ -27,6 +27,7 @@ import { StatusBarAlignment, StatusBar } from './status-bar/status-bar'; import { ContextKeyService } from './context-key-service'; import { CorePreferences } from './core-preferences'; import * as common from '../common/keybinding'; +import { nls } from '../common/nls'; export enum KeybindingScope { DEFAULT, @@ -559,7 +560,7 @@ export class KeybindingRegistry { event.stopPropagation(); this.statusBar.setElement('keybinding-status', { - text: `(${this.acceleratorForSequence(this.keySequence, '+')}) was pressed, waiting for more keys`, + text: nls.localize('theia/core/keybindingStatus', '{0} was pressed, waiting for more keys', `(${this.acceleratorForSequence(this.keySequence, '+')})`), alignment: StatusBarAlignment.LEFT, priority: 2 }); diff --git a/packages/core/src/browser/shell/application-shell.ts b/packages/core/src/browser/shell/application-shell.ts index 583e6576e4622..94d36e3dd28f6 100644 --- a/packages/core/src/browser/shell/application-shell.ts +++ b/packages/core/src/browser/shell/application-shell.ts @@ -39,6 +39,7 @@ import { CorePreferences } from '../core-preferences'; import { BreadcrumbsRendererFactory } from '../breadcrumbs/breadcrumbs-renderer'; import { Deferred } from '../../common/promise-util'; import { SaveResourceService } from '../save-resource-service'; +import { nls } from '../../common/nls'; /** The class name added to ApplicationShell instances. */ const APPLICATION_SHELL_CLASS = 'theia-ApplicationShell'; @@ -1428,14 +1429,15 @@ export class ApplicationShell extends Widget { if (this.bottomPanel.isEmpty) { this.statusBar.removeElement(BOTTOM_PANEL_TOGGLE_ID); } else { + const label = nls.localize('theia/core/common/collapseBottomPanel', 'Toggle Bottom Panel'); const element: StatusBarEntry = { - name: 'Toggle Bottom Panel', + name: label, text: '$(codicon-window)', alignment: StatusBarAlignment.RIGHT, - tooltip: 'Toggle Bottom Panel', + tooltip: label, command: 'core.toggle.bottom.panel', accessibilityInformation: { - label: 'Toggle Bottom Panel', + label: label, role: 'button' }, priority: -1000 diff --git a/packages/core/src/browser/tree/search-box.ts b/packages/core/src/browser/tree/search-box.ts index 017125885ce0a..ed3ad7a44fda6 100644 --- a/packages/core/src/browser/tree/search-box.ts +++ b/packages/core/src/browser/tree/search-box.ts @@ -18,6 +18,7 @@ import { SearchBoxDebounce, SearchBoxDebounceOptions } from '../tree/search-box- import { BaseWidget, Message } from '../widgets/widget'; import { Emitter, Event } from '../../common/event'; import { KeyCode, Key } from '../keyboard/keys'; +import { nls } from '../../common/nls'; /** * Initializer properties for the search box widget. @@ -253,7 +254,7 @@ export class SearchBox extends BaseWidget { SearchBox.Styles.BUTTON, ...SearchBox.Styles.FILTER, ); - filter.title = 'Enable Filter on Type'; + filter.title = nls.localizeByDefault('Enable Filter on Type'); buttons.appendChild(filter); filter.onclick = this.fireFilterToggle.bind(this); } @@ -268,7 +269,7 @@ export class SearchBox extends BaseWidget { SearchBox.Styles.BUTTON, SearchBox.Styles.BUTTON_PREVIOUS ); - previous.title = 'Previous (Up)'; + previous.title = nls.localize('theia/core/searchbox/previous', 'Previous (Up)'); buttons.appendChild(previous); previous.onclick = () => this.firePrevious.bind(this)(); @@ -277,7 +278,7 @@ export class SearchBox extends BaseWidget { SearchBox.Styles.BUTTON, SearchBox.Styles.BUTTON_NEXT ); - next.title = 'Next (Down)'; + next.title = nls.localize('theia/core/searchbox/next', 'Next (Down)'); buttons.appendChild(next); next.onclick = () => this.fireNext.bind(this)(); } @@ -288,7 +289,7 @@ export class SearchBox extends BaseWidget { SearchBox.Styles.BUTTON, SearchBox.Styles.BUTTON_CLOSE ); - close.title = 'Close (Escape)'; + close.title = nls.localize('theia/core/searchbox/close', 'Close (Escape)'); buttons.appendChild(close); close.onclick = () => this.hide.bind(this)(); } diff --git a/packages/git/src/browser/diff/git-diff-widget.tsx b/packages/git/src/browser/diff/git-diff-widget.tsx index bfc1f96b39511..edd935eea1b8e 100644 --- a/packages/git/src/browser/diff/git-diff-widget.tsx +++ b/packages/git/src/browser/diff/git-diff-widget.tsx @@ -26,6 +26,7 @@ import { ScmService } from '@theia/scm/lib/browser/scm-service'; import { GitRepositoryProvider } from '../git-repository-provider'; import { ScmTreeWidget } from '@theia/scm/lib/browser/scm-tree-widget'; import { ScmPreferences } from '@theia/scm/lib/browser/scm-preferences'; +import { nls } from '@theia/core'; /* eslint-disable @typescript-eslint/no-explicit-any */ @@ -33,7 +34,7 @@ export const GIT_DIFF = 'git-diff'; @injectable() export class GitDiffWidget extends BaseWidget implements StatefulWidget { - protected readonly GIT_DIFF_TITLE = 'Diff'; + protected readonly GIT_DIFF_TITLE = nls.localize('theia/git/diff', 'Diff'); @inject(GitRepositoryProvider) protected readonly repositoryProvider: GitRepositoryProvider; @inject(DiffNavigatorProvider) protected readonly diffNavigatorProvider: DiffNavigatorProvider; diff --git a/packages/plugin-dev/src/browser/hosted-plugin-informer.ts b/packages/plugin-dev/src/browser/hosted-plugin-informer.ts index 8a0b575431934..b1c44d63c9904 100644 --- a/packages/plugin-dev/src/browser/hosted-plugin-informer.ts +++ b/packages/plugin-dev/src/browser/hosted-plugin-informer.ts @@ -31,7 +31,7 @@ import { nls } from '@theia/core/lib/common/nls'; @injectable() export class HostedPluginInformer implements FrontendApplicationContribution { - public static readonly DEVELOPMENT_HOST_TITLE = 'Development Host'; + public static readonly DEVELOPMENT_HOST_TITLE = nls.localize('theia/plugin-dev/devHost', 'Development Host'); public static readonly DEVELOPMENT_HOST = 'development-host'; diff --git a/packages/timeline/src/browser/timeline-widget.tsx b/packages/timeline/src/browser/timeline-widget.tsx index 39d2c8168ec6d..9e46eecc969fb 100644 --- a/packages/timeline/src/browser/timeline-widget.tsx +++ b/packages/timeline/src/browser/timeline-widget.tsx @@ -31,6 +31,7 @@ import { TimelineEmptyWidget } from './timeline-empty-widget'; import { toArray } from '@theia/core/shared/@phosphor/algorithm'; import URI from '@theia/core/lib/common/uri'; import { URI as CodeURI } from '@theia/core/shared/vscode-uri'; +import { nls } from '@theia/core/lib/common/nls'; @injectable() export class TimelineWidget extends BaseWidget { @@ -50,7 +51,7 @@ export class TimelineWidget extends BaseWidget { constructor() { super(); this.id = TimelineWidget.ID; - this.title.label = 'Timeline'; + this.title.label = nls.localizeByDefault('Timeline'); this.title.caption = this.title.label; this.addClass('theia-timeline'); } diff --git a/packages/vsx-registry/src/browser/vsx-extension-editor.tsx b/packages/vsx-registry/src/browser/vsx-extension-editor.tsx index 7cc6cec65b4f7..a31de53a6cbc6 100644 --- a/packages/vsx-registry/src/browser/vsx-extension-editor.tsx +++ b/packages/vsx-registry/src/browser/vsx-extension-editor.tsx @@ -20,6 +20,7 @@ import { ReactWidget, Message, Widget, codicon } from '@theia/core/lib/browser'; import { VSXExtension, VSXExtensionEditorComponent } from './vsx-extension'; import { VSXExtensionsModel } from './vsx-extensions-model'; import { Deferred } from '@theia/core/lib/common/promise-util'; +import { nls } from '@theia/core/lib/common/nls'; @injectable() export class VSXExtensionEditor extends ReactWidget { @@ -66,7 +67,7 @@ export class VSXExtensionEditor extends ReactWidget { } protected updateTitle(): void { - const label = 'Extension: ' + (this.extension.displayName || this.extension.name); + const label = nls.localizeByDefault('Extension: {0}', (this.extension.displayName || this.extension.name)); this.title.label = label; this.title.caption = label; } diff --git a/packages/vsx-registry/src/browser/vsx-extensions-search-bar.tsx b/packages/vsx-registry/src/browser/vsx-extensions-search-bar.tsx index 246bcc90629fe..92f2813bfecca 100644 --- a/packages/vsx-registry/src/browser/vsx-extensions-search-bar.tsx +++ b/packages/vsx-registry/src/browser/vsx-extensions-search-bar.tsx @@ -18,6 +18,7 @@ import * as React from '@theia/core/shared/react'; import { injectable, postConstruct, inject } from '@theia/core/shared/inversify'; import { ReactWidget, Message } from '@theia/core/lib/browser/widgets'; import { VSXExtensionsSearchModel } from './vsx-extensions-search-model'; +import { nls } from '@theia/core/lib/common/nls'; @injectable() export class VSXExtensionsSearchBar extends ReactWidget { @@ -40,7 +41,7 @@ export class VSXExtensionsSearchBar extends ReactWidget { defaultValue={this.model.query} spellCheck={false} className='theia-input' - placeholder='Search Extensions in Open VSX Registry' + placeholder={nls.localize('theia/vsx-registry/searchPlaceholder', 'Search Extensions in {0}', 'Open VSX Registry')} onChange={this.updateQuery}> ; } diff --git a/packages/workspace/src/browser/workspace-delete-handler.ts b/packages/workspace/src/browser/workspace-delete-handler.ts index 57220f476dcb4..6baef03b5d693 100644 --- a/packages/workspace/src/browser/workspace-delete-handler.ts +++ b/packages/workspace/src/browser/workspace-delete-handler.ts @@ -85,11 +85,11 @@ export class WorkspaceDeleteHandler implements UriCommandHandler { * @param uris URIs of selected resources. */ protected confirm(uris: URI[], options: FileDeleteOptions): Promise { - let title = `File${uris.length === 1 ? '' : 's'}`; + let title = uris.length === 1 ? nls.localizeByDefault('File') : nls.localizeByDefault('Files'); if (options.useTrash) { - title = 'Move ' + title + ' to Trash'; + title = nls.localize('theia/workspace/trashTitle', 'Move {0} to Trash', title); } else { - title = 'Delete ' + title; + title = nls.localizeByDefault('Delete {0}', title); } return new ConfirmDialog({ title, @@ -106,18 +106,18 @@ export class WorkspaceDeleteHandler implements UriCommandHandler { const dirty = this.getDirty(uris); if (dirty.length) { if (dirty.length === 1) { - return `Do you really want to delete ${dirty[0].path.base} with unsaved changes?`; + return nls.localize('theia/workspace/confirmMessage.dirtySingle', 'Do you really want to delete {0} with unsaved changes?', dirty[0].path.base); } - return `Do you really want to delete ${dirty.length} files with unsaved changes?`; + return nls.localize('theia/workspace/confirmMessage.dirtyMultiple', 'Do you really want to delete {0} files with unsaved changes?', dirty.length); } if (uris.length === 1) { - return `Do you really want to delete ${uris[0].path.base}?`; + return nls.localize('theia/workspace/confirmMessage.uriSingle', 'Do you really want to delete {0}?', uris[0].path.base); } if (uris.length > 10) { - return `Do you really want to delete all the ${uris.length} selected files?`; + return nls.localize('theia/workspace/confirmMessage.uriMultiple', 'Do you really want to delete all the {0} selected files?', uris.length); } const messageContainer = document.createElement('div'); - messageContainer.textContent = 'Do you really want to delete the following files?'; + messageContainer.textContent = nls.localize('theia/workspace/confirmMessage.delete', 'Do you really want to delete the following files?'); const list = document.createElement('ul'); list.style.listStyleType = 'none'; for (const uri of uris) {