diff --git a/e2e/various-suite/verify-i18n.spec.ts b/e2e/various-suite/verify-i18n.spec.ts new file mode 100644 index 00000000000..3de37d5d863 --- /dev/null +++ b/e2e/various-suite/verify-i18n.spec.ts @@ -0,0 +1,65 @@ +import { e2e } from '../utils'; +import { fromBaseUrl } from '../utils/support/url'; + +describe('Verify i18n', () => { + const I18N_USER = 'i18n-test'; + const I18N_PASSWORD = 'i18n-test'; + + // create a new user to isolate the language changes from other tests + before(() => { + e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); + cy.request({ + method: 'POST', + url: fromBaseUrl('/api/admin/users'), + body: { + email: I18N_USER, + login: I18N_USER, + name: I18N_USER, + password: I18N_PASSWORD, + }, + }).then((response) => { + cy.wrap(response.body.uid).as('uid'); + }); + }); + + // remove the user created in the before hook + after(() => { + e2e.flows.login(Cypress.env('USERNAME'), Cypress.env('PASSWORD')); + cy.get('@uid').then((uid) => { + cy.request({ + method: 'DELETE', + url: fromBaseUrl(`/api/admin/users/${uid}`), + }); + }); + }); + + beforeEach(() => { + e2e.flows.login(I18N_USER, I18N_PASSWORD); + }); + + // map between languages in the language picker and the corresponding translation of the 'Language' label + const languageMap: Record = { + Deutsch: 'Sprache', + English: 'Language', + Español: 'Idioma', + Français: 'Langue', + 'Português Brasileiro': 'Idioma', + '中文(简体)': '语言', + }; + + // basic test which loops through the defined languages in the picker + // and verifies that the corresponding label is translated correctly + it('loads all the languages correctly', () => { + cy.visit('/profile'); + const LANGUAGE_SELECTOR = '[id="locale-select"]'; + + cy.wrap(Object.entries(languageMap)).each(([language, label]: [string, string]) => { + cy.get(LANGUAGE_SELECTOR).should('not.be.disabled'); + cy.get(LANGUAGE_SELECTOR).click(); + cy.get(LANGUAGE_SELECTOR).clear().type(language).type('{downArrow}{enter}'); + e2e.components.UserProfile.preferencesSaveButton().click(); + cy.contains('label', label).should('be.visible'); + cy.get(LANGUAGE_SELECTOR).should('have.value', language); + }); + }); +}); diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index cd6475c45ac..462e38863a5 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -31,7 +31,9 @@ export interface Props { onConfirm?: () => Promise; } -export type State = UserPreferencesDTO; +export type State = UserPreferencesDTO & { + isLoading: boolean; +}; function getLanguageOptions(): ComboboxOption[] { const languageOptions = LANGUAGES.map((v) => ({ @@ -69,6 +71,7 @@ export class SharedPreferences extends PureComponent { this.service = new PreferencesService(props.resourceUri); this.state = { + isLoading: false, theme: '', timezone: '', weekStart: '', @@ -87,9 +90,13 @@ export class SharedPreferences extends PureComponent { } async componentDidMount() { + this.setState({ + isLoading: true, + }); const prefs = await this.service.load(); this.setState({ + isLoading: false, homeDashboardUID: prefs.homeDashboardUID, theme: prefs.theme, timezone: prefs.timezone, @@ -144,7 +151,7 @@ export class SharedPreferences extends PureComponent { }; render() { - const { theme, timezone, weekStart, homeDashboardUID, language } = this.state; + const { theme, timezone, weekStart, homeDashboardUID, language, isLoading } = this.state; const { disabled } = this.props; const styles = getStyles(); const languages = getLanguageOptions(); @@ -153,7 +160,11 @@ export class SharedPreferences extends PureComponent { return (
Preferences} disabled={disabled}> - + { @@ -183,6 +196,8 @@ export class SharedPreferences extends PureComponent { @@ -195,17 +210,21 @@ export class SharedPreferences extends PureComponent { diff --git a/public/app/core/internationalization/constants.test.ts b/public/app/core/internationalization/constants.test.ts index 6dee3878b36..68defb081b3 100644 --- a/public/app/core/internationalization/constants.test.ts +++ b/public/app/core/internationalization/constants.test.ts @@ -21,7 +21,7 @@ describe('internationalization constants', () => { expect(GERMAN_GERMANY).toBe('de-DE'); expect(BRAZILIAN_PORTUGUESE).toBe('pt-BR'); expect(CHINESE_SIMPLIFIED).toBe('zh-Hans'); - expect(PSEUDO_LOCALE).toBe('pseudo-LOCALE'); + expect(PSEUDO_LOCALE).toBe('pseudo'); expect(DEFAULT_LANGUAGE).toBe(ENGLISH_US); }); diff --git a/public/app/core/internationalization/constants.ts b/public/app/core/internationalization/constants.ts index f4ab99631cc..b28e5499d92 100644 --- a/public/app/core/internationalization/constants.ts +++ b/public/app/core/internationalization/constants.ts @@ -7,7 +7,7 @@ export const SPANISH_SPAIN = 'es-ES'; export const GERMAN_GERMANY = 'de-DE'; export const BRAZILIAN_PORTUGUESE = 'pt-BR'; export const CHINESE_SIMPLIFIED = 'zh-Hans'; -export const PSEUDO_LOCALE = 'pseudo-LOCALE'; +export const PSEUDO_LOCALE = 'pseudo'; export const DEFAULT_LANGUAGE = ENGLISH_US;