diff --git a/e2e/various-suite/verify-i18n.spec.ts b/e2e/various-suite/verify-i18n.spec.ts index 3de37d5d863..319a2d254cf 100644 --- a/e2e/various-suite/verify-i18n.spec.ts +++ b/e2e/various-suite/verify-i18n.spec.ts @@ -38,22 +38,33 @@ describe('Verify i18n', () => { }); // 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', - '中文(简体)': '语言', + // const languageMap: Record = { + // Deutsch: 'Sprache', + // English: 'Language', + // Español: 'Idioma', + // Français: 'Langue', + // 'Português Brasileiro': 'Idioma', + // '中文(简体)': '语言', + // }; + + // map between languages in the weekstart picker and the corresponding translation of the 'Week Start' label + const weekStartMap: Record = { + Deutsch: 'Wochenbeginn', + English: 'Week start', + Español: 'Inicio de la semana', + Français: 'Début de la semaine', + 'Português Brasileiro': 'Início da semana', + '中文(简体)': '每周开始日', }; // 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]) => { + const LANGUAGE_SELECTOR = '[id="language-preference-select"]'; + //TODO ckeck translations using language label when its translations get updated + // Checking the Week start label instead + cy.wrap(Object.entries(weekStartMap)).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}'); diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index 373ad066648..2cd7ca041e9 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -24,6 +24,7 @@ import { import { DashboardPicker } from 'app/core/components/Select/DashboardPicker'; import { t, Trans } from 'app/core/internationalization'; import { LANGUAGES, PSEUDO_LOCALE } from 'app/core/internationalization/constants'; +import { LOCALES } from 'app/core/internationalization/locales'; import { PreferencesService } from 'app/core/services/PreferencesService'; import { changeTheme } from 'app/core/services/theme'; @@ -39,7 +40,6 @@ export interface Props { export type State = UserPreferencesDTO & { isLoading: boolean; }; - function getLanguageOptions(): ComboboxOption[] { const languageOptions = LANGUAGES.map((v) => ({ value: v.code, @@ -67,9 +67,29 @@ function getLanguageOptions(): ComboboxOption[] { return options; } +function getLocaleOptions(): ComboboxOption[] { + const localeOptions = LOCALES.map((v) => ({ + value: v.code, + label: v.name, + })).sort((a, b) => { + return a.label.localeCompare(b.label); + }); + + const options = [ + { + value: '', + label: t('common.locale.default', 'Default'), + }, + ...localeOptions, + ]; + return options; +} + export class SharedPreferences extends PureComponent { service: PreferencesService; themeOptions: ComboboxOption[]; + languageOptions: ComboboxOption[]; + localeOptions: ComboboxOption[]; constructor(props: Props) { super(props); @@ -81,17 +101,22 @@ export class SharedPreferences extends PureComponent { timezone: '', weekStart: '', language: '', + locale: '', queryHistory: { homeTab: '' }, navbar: { bookmarkUrls: [] }, }; const themes = getSelectableThemes(); + // Options are translated, so must be called after init but call them + // in constructor to avoid memo-break of array changing every render this.themeOptions = themes.map((theme) => ({ value: theme.id, label: getTranslatedThemeName(theme), group: theme.isExtra ? t('shared-preferences.theme.experimental', 'Experimental') : undefined, })); + this.languageOptions = getLanguageOptions(); + this.localeOptions = getLocaleOptions(); // Add default option this.themeOptions.unshift({ value: '', label: t('shared-preferences.theme.default-label', 'Default') }); @@ -110,6 +135,7 @@ export class SharedPreferences extends PureComponent { timezone: prefs.timezone, weekStart: prefs.weekStart, language: prefs.language, + locale: prefs.locale, queryHistory: prefs.queryHistory, navbar: prefs.navbar, }); @@ -120,13 +146,22 @@ export class SharedPreferences extends PureComponent { const confirmationResult = this.props.onConfirm ? await this.props.onConfirm() : true; if (confirmationResult) { - const { homeDashboardUID, theme, timezone, weekStart, language, queryHistory, navbar } = this.state; + const { homeDashboardUID, theme, timezone, weekStart, language, locale, queryHistory, navbar } = this.state; reportInteraction('grafana_preferences_save_button_clicked', { preferenceType: this.props.preferenceType, theme, language, }); - await this.service.update({ homeDashboardUID, theme, timezone, weekStart, language, queryHistory, navbar }); + await this.service.update({ + homeDashboardUID, + theme, + timezone, + weekStart, + language, + locale, + queryHistory, + navbar, + }); window.location.reload(); } }; @@ -167,11 +202,19 @@ export class SharedPreferences extends PureComponent { }); }; + onLocaleChanged = (locale: string) => { + this.setState({ locale }); + + reportInteraction('grafana_preferences_locale_changed', { + toLocale: locale, + preferenceType: this.props.preferenceType, + }); + }; + render() { - const { theme, timezone, weekStart, homeDashboardUID, language, isLoading } = this.state; + const { theme, timezone, weekStart, homeDashboardUID, language, isLoading, locale } = this.state; const { disabled } = this.props; const styles = getStyles(); - const languages = getLanguageOptions(); const currentThemeOption = this.themeOptions.find((x) => x.value === theme) ?? this.themeOptions[0]; return ( @@ -257,23 +300,50 @@ export class SharedPreferences extends PureComponent { loading={isLoading} disabled={isLoading} label={ - + } + description={t( + 'shared-preferences.fields.locale-preference-description', + 'Choose your region to see the corresponding date, time, and number format' + )} + data-testid="User preferences locale drop down" + > + loc.value === locale)?.value || ''} + onChange={(locale: ComboboxOption | null) => this.onLocaleChanged(locale?.value ?? '')} + options={this.localeOptions} + placeholder={t('shared-preferences.fields.locale-preference-placeholder', 'Choose region')} + id="locale-preference-select" + /> + + )}