diff --git a/src/vs/platform/driver/browser/baseDriver.ts b/src/vs/platform/driver/browser/baseDriver.ts index 90610713f9d..9debf9b8a1f 100644 --- a/src/vs/platform/driver/browser/baseDriver.ts +++ b/src/vs/platform/driver/browser/baseDriver.ts @@ -5,7 +5,8 @@ import { getTopLeftOffset, getClientArea } from 'vs/base/browser/dom'; import { coalesce } from 'vs/base/common/arrays'; -import { IElement, IWindowDriver } from 'vs/platform/driver/common/driver'; +import { IElement, ILocalizedStrings, IWindowDriver } from 'vs/platform/driver/common/driver'; +import localizedStrings from 'vs/platform/localizations/common/localizedStrings'; function serializeElement(element: Element, recursive: boolean): IElement { const attributes = Object.create(null); @@ -161,6 +162,14 @@ export abstract class BaseWindowDriver implements IWindowDriver { xterm._core._coreService.triggerDataEvent(text); } + getLocalizedStrings(): Promise { + return Promise.resolve({ + open: localizedStrings.open, + close: localizedStrings.close, + find: localizedStrings.find + }); + } + protected async _getElementXY(selector: string, offset?: { x: number, y: number }): Promise<{ x: number; y: number; }> { const element = document.querySelector(selector); diff --git a/src/vs/platform/driver/common/driver.ts b/src/vs/platform/driver/common/driver.ts index b444cb31e03..849874ef804 100644 --- a/src/vs/platform/driver/common/driver.ts +++ b/src/vs/platform/driver/common/driver.ts @@ -18,6 +18,12 @@ export interface IElement { left: number; } +export interface ILocalizedStrings { + open: string; + close: string; + find: string; +} + export interface IDriver { readonly _serviceBrand: undefined; @@ -36,6 +42,7 @@ export interface IDriver { typeInEditor(windowId: number, selector: string, text: string): Promise; getTerminalBuffer(windowId: number, selector: string): Promise; writeInTerminal(windowId: number, selector: string, text: string): Promise; + getLocalizedStrings(windowId: number): Promise } //*END @@ -53,6 +60,7 @@ export interface IWindowDriver { typeInEditor(selector: string, text: string): Promise; getTerminalBuffer(selector: string): Promise; writeInTerminal(selector: string, text: string): Promise; + getLocalizedStrings(): Promise } export interface IDriverOptions { diff --git a/src/vs/platform/driver/common/driverIpc.ts b/src/vs/platform/driver/common/driverIpc.ts index f492817c1d3..d756e6814d5 100644 --- a/src/vs/platform/driver/common/driverIpc.ts +++ b/src/vs/platform/driver/common/driverIpc.ts @@ -5,7 +5,7 @@ import { Event } from 'vs/base/common/event'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; -import { IDriverOptions, IElement, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; +import { IDriverOptions, IElement, ILocalizedStrings as ILocalizedStrings, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; export class WindowDriverChannel implements IServerChannel { @@ -27,6 +27,7 @@ export class WindowDriverChannel implements IServerChannel { case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1]); case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg); case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1]); + case 'getLocalizedStrings': return this.driver.getLocalizedStrings(); } throw new Error(`Call not found: ${command}`); @@ -78,6 +79,10 @@ export class WindowDriverChannelClient implements IWindowDriver { writeInTerminal(selector: string, text: string): Promise { return this.channel.call('writeInTerminal', [selector, text]); } + + getLocalizedStrings(): Promise { + return this.channel.call('getLocalizedStrings'); + } } export class WindowDriverRegistryChannelClient implements IWindowDriverRegistry { diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index f33718e8f7d..c45aad9a1ed 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -18,7 +18,7 @@ import { IEnvironmentMainService } from 'vs/platform/environment/electron-main/e import { ScanCodeBinding } from 'vs/base/common/scanCode'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; import { timeout } from 'vs/base/common/async'; -import { IDriver, IDriverOptions, IElement, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; +import { IDriver, IDriverOptions, IElement, ILocalizedStrings, IWindowDriver, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; import { ILifecycleMainService } from 'vs/platform/lifecycle/electron-main/lifecycleMainService'; import { INativeHostMainService } from 'vs/platform/native/electron-main/nativeHostMainService'; @@ -189,6 +189,11 @@ export class Driver implements IDriver, IWindowDriverRegistry { await windowDriver.writeInTerminal(selector, text); } + async getLocalizedStrings(windowId: number): Promise { + const windowDriver = await this.getWindowDriver(windowId); + return await windowDriver.getLocalizedStrings(); + } + private async getWindowDriver(windowId: number): Promise { await this.whenUnfrozen(windowId); diff --git a/src/vs/platform/driver/node/driver.ts b/src/vs/platform/driver/node/driver.ts index ba435b01de2..f9d78661aec 100644 --- a/src/vs/platform/driver/node/driver.ts +++ b/src/vs/platform/driver/node/driver.ts @@ -7,7 +7,7 @@ import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { connect as connectNet } from 'vs/base/parts/ipc/node/ipc.net'; import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { Event } from 'vs/base/common/event'; -import { IDriver, IElement, IWindowDriverRegistry } from 'vs/platform/driver/common/driver'; +import { IDriver, IElement, IWindowDriverRegistry, ILocalizedStrings } from 'vs/platform/driver/common/driver'; export class DriverChannel implements IServerChannel { @@ -34,6 +34,7 @@ export class DriverChannel implements IServerChannel { case 'typeInEditor': return this.driver.typeInEditor(arg[0], arg[1], arg[2]); case 'getTerminalBuffer': return this.driver.getTerminalBuffer(arg[0], arg[1]); case 'writeInTerminal': return this.driver.writeInTerminal(arg[0], arg[1], arg[2]); + case 'getLocalizedStrings': return this.driver.getLocalizedStrings(arg); } throw new Error(`Call not found: ${command}`); @@ -105,6 +106,10 @@ export class DriverChannelClient implements IDriver { writeInTerminal(windowId: number, selector: string, text: string): Promise { return this.channel.call('writeInTerminal', [windowId, selector, text]); } + + getLocalizedStrings(windowId: number): Promise { + return this.channel.call('getLocalizedStrings', windowId); + } } export class WindowDriverRegistryChannel implements IServerChannel { diff --git a/src/vs/platform/localizations/common/localizedStrings.ts b/src/vs/platform/localizations/common/localizedStrings.ts new file mode 100644 index 00000000000..5432fbcb609 --- /dev/null +++ b/src/vs/platform/localizations/common/localizedStrings.ts @@ -0,0 +1,21 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nls from 'vs/nls'; + +/** + * These are some predefined strings that we test during smoke testing that they are localized + * correctly. Don't change these strings!! + */ + +const open: string = nls.localize('open', 'open'); +const close: string = nls.localize('close', 'close'); +const find: string = nls.localize('find', 'find'); + +export default { + open: open, + close: close, + find: find +}; diff --git a/test/automation/src/code.ts b/test/automation/src/code.ts index f9da593f8fc..54b255c7c2e 100644 --- a/test/automation/src/code.ts +++ b/test/automation/src/code.ts @@ -9,7 +9,7 @@ import * as os from 'os'; import * as fs from 'fs'; import * as mkdirp from 'mkdirp'; import { tmpName } from 'tmp'; -import { IDriver, connect as connectElectronDriver, IDisposable, IElement, Thenable } from './driver'; +import { IDriver, connect as connectElectronDriver, IDisposable, IElement, Thenable, ILocalizedStrings } from './driver'; import { connect as connectPlaywrightDriver, launch } from './playwrightDriver'; import { Logger } from './logger'; import { ncp } from 'ncp'; @@ -360,6 +360,11 @@ export class Code { await poll(() => this.driver.writeInTerminal(windowId, selector, value), () => true, `writeInTerminal '${selector}'`); } + async getLocalizedStrings(): Promise { + const windowId = await this.getActiveWindowId(); + return await this.driver.getLocalizedStrings(windowId); + } + private async getActiveWindowId(): Promise { if (typeof this._activeWindowId !== 'number') { const windows = await this.driver.getWindowIds(); diff --git a/test/automation/src/index.ts b/test/automation/src/index.ts index 1eb4c8005e3..61f72fe7322 100644 --- a/test/automation/src/index.ts +++ b/test/automation/src/index.ts @@ -23,5 +23,6 @@ export * from './settings'; export * from './statusbar'; export * from './terminal'; export * from './viewlet'; +export * from './localization'; export * from './workbench'; export * from './driver'; diff --git a/test/automation/src/localization.ts b/test/automation/src/localization.ts new file mode 100644 index 00000000000..0de0ad71827 --- /dev/null +++ b/test/automation/src/localization.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Code } from './code'; +import { ILocalizedStrings } from './driver'; + +export class Localization { + constructor(private code: Code) { } + + async getLocalizedStrings(): Promise { + return this.code.getLocalizedStrings(); + } +} diff --git a/test/automation/src/playwrightDriver.ts b/test/automation/src/playwrightDriver.ts index d9f75c511fa..cef69c8b31a 100644 --- a/test/automation/src/playwrightDriver.ts +++ b/test/automation/src/playwrightDriver.ts @@ -81,7 +81,8 @@ function buildDriver(browser: playwright.Browser, page: playwright.Page): IDrive getElementXY: (windowId, selector, xoffset?, yoffset?) => page.evaluate(`window.driver.getElementXY('${selector}', ${xoffset}, ${yoffset})`), typeInEditor: (windowId, selector, text) => page.evaluate(`window.driver.typeInEditor('${selector}', '${text}')`), getTerminalBuffer: (windowId, selector) => page.evaluate(`window.driver.getTerminalBuffer('${selector}')`), - writeInTerminal: (windowId, selector, text) => page.evaluate(`window.driver.writeInTerminal('${selector}', '${text}')`) + writeInTerminal: (windowId, selector, text) => page.evaluate(`window.driver.writeInTerminal('${selector}', '${text}')`), + getLocalizedStrings: (windowId) => page.evaluate(`window.driver.getLocalizedStrings()`) }; return driver; } diff --git a/test/automation/src/workbench.ts b/test/automation/src/workbench.ts index eaceaa7c09b..c2f5abe8096 100644 --- a/test/automation/src/workbench.ts +++ b/test/automation/src/workbench.ts @@ -20,6 +20,7 @@ import { Editors } from './editors'; import { Code } from './code'; import { Terminal } from './terminal'; import { Notebook } from './notebook'; +import { Localization } from './localization'; export interface Commands { runCommand(command: string): Promise; @@ -43,6 +44,7 @@ export class Workbench { readonly keybindingsEditor: KeybindingsEditor; readonly terminal: Terminal; readonly notebook: Notebook; + readonly localization: Localization; constructor(code: Code, userDataPath: string) { this.editors = new Editors(code); @@ -61,5 +63,6 @@ export class Workbench { this.keybindingsEditor = new KeybindingsEditor(code); this.terminal = new Terminal(code, this.quickaccess); this.notebook = new Notebook(this.quickaccess, code); + this.localization = new Localization(code); } } diff --git a/test/smoke/src/areas/workbench/localization.test.ts b/test/smoke/src/areas/workbench/localization.test.ts index 9ae63024de8..697b0145e23 100644 --- a/test/smoke/src/areas/workbench/localization.test.ts +++ b/test/smoke/src/areas/workbench/localization.test.ts @@ -30,25 +30,15 @@ export function setup(opts: minimist.ParsedArgs) { it(`starts with 'DE' locale and verifies title and viewlets text is in German`, async function () { const app = this.app as Application; + const result = await app.workbench.localization.getLocalizedStrings(); if (app.quality === Quality.Dev || app.remote) { - this.skip(); + if (result.open !== 'open' || result.close !== 'close' || result.find !== 'find') { + throw new Error(`Received localized strings: ${JSON.stringify(result, undefined, 0)}`); + } return; } - // await app.workbench.explorer.waitForOpenEditorsViewTitle(title => /geƶffnete editoren/i.test(title)); - - await app.workbench.search.openSearchViewlet(); - await app.workbench.search.waitForTitle(title => /suchen/i.test(title)); - - // await app.workbench.scm.openSCMViewlet(); - // await app.workbench.scm.waitForTitle(title => /quellcodeverwaltung/i.test(title)); - - // See https://github.com/microsoft/vscode/issues/93462 - // await app.workbench.debug.openDebugViewlet(); - // await app.workbench.debug.waitForTitle(title => /starten/i.test(title)); - - // await app.workbench.extensions.openExtensionsViewlet(); - // await app.workbench.extensions.waitForTitle(title => /extensions/i.test(title)); + // As soon as strings are translated in the next round we can check for german as well. }); }); }