diff --git a/.linguirc b/.linguirc index 3a6a7c4b82f..a64726b556b 100644 --- a/.linguirc +++ b/.linguirc @@ -1,8 +1,8 @@ { "locales": [ - "en", - "fr", - "es", + "en-US", + "fr-FR", + "es-ES", "pseudo-LOCALE" ], "catalogs": [ @@ -20,11 +20,11 @@ } ], "fallbackLocales": { - "pseudo-LOCALE": "en", - "default": "en" + "pseudo-LOCALE": "en-US", + "default": "en-US" }, "pseudoLocale": "pseudo-LOCALE", - "sourceLocale": "en", + "sourceLocale": "en-US", "format": "po", "formatOptions": { "lineNumbers": false diff --git a/package.json b/package.json index 1988b499f7a..a9da25aa0c4 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "lint": "yarn run lint:ts && yarn run lint:sass", "lint:ts": "eslint . --ext .js,.tsx,.ts --cache", "lint:sass": "yarn stylelint '{public/sass,packages}/**/*.scss' --cache", - "test:ci": "mkdir -p reports/junit && JEST_JUNIT_OUTPUT_DIR=reports/junit jest --ci --reporters=default --reporters=jest-junit -w ${TEST_MAX_WORKERS:-100%}", + "test:ci": "yarn i18n:compile && mkdir -p reports/junit && JEST_JUNIT_OUTPUT_DIR=reports/junit jest --ci --reporters=default --reporters=jest-junit -w ${TEST_MAX_WORKERS:-100%}", "lint:fix": "yarn lint:ts --fix", "packages:build": "lerna run clean && lerna run build --ignore @grafana-plugins/input-datasource", "packages:docsExtract": "rm -rf ./reports/docs && lerna run docsExtract", diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx index 868df02d1d6..29351822ab1 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.test.tsx @@ -175,7 +175,7 @@ describe('SharedPreferences', () => { queryHistory: { homeTab: '', }, - locale: 'fr', + locale: 'fr-FR', }); }); diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index 6117947e2ba..2fcd57379f6 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -20,6 +20,7 @@ import { WeekStartPicker, FeatureBadge, } from '@grafana/ui'; +import { ENGLISH_US, FRENCH_FRANCE, SPANISH_SPAIN } from 'app/core/internationalization/constants'; import { PreferencesService } from 'app/core/services/PreferencesService'; import { backendSrv } from 'app/core/services/backend_srv'; import { DashboardSearchItem, DashboardSearchItemType } from 'app/features/search/types'; @@ -50,21 +51,21 @@ const languages: Array> = [ }), }, { - value: 'en', + value: ENGLISH_US, label: t({ id: 'common.locale.en', message: 'English', }), }, { - value: 'es', + value: SPANISH_SPAIN, label: t({ id: 'common.locale.es', message: 'Spanish', }), }, { - value: 'fr', + value: FRENCH_FRANCE, label: t({ id: 'common.locale.fr', message: 'French', diff --git a/public/app/core/internationalization/constants.ts b/public/app/core/internationalization/constants.ts new file mode 100644 index 00000000000..7d5dc045c55 --- /dev/null +++ b/public/app/core/internationalization/constants.ts @@ -0,0 +1,9 @@ +type LocaleIdentifier = `${string}-${string}`; + +export const ENGLISH_US: LocaleIdentifier = 'en-US'; +export const FRENCH_FRANCE: LocaleIdentifier = 'fr-FR'; +export const SPANISH_SPAIN: LocaleIdentifier = 'es-ES'; + +export const DEFAULT_LOCALE: LocaleIdentifier = ENGLISH_US; + +export const VALID_LOCALES: LocaleIdentifier[] = [ENGLISH_US, FRENCH_FRANCE, SPANISH_SPAIN]; diff --git a/public/app/core/internationalization/index.tsx b/public/app/core/internationalization/index.tsx index 4004759b71a..bf1c889f91a 100644 --- a/public/app/core/internationalization/index.tsx +++ b/public/app/core/internationalization/index.tsx @@ -4,22 +4,28 @@ import React, { useEffect } from 'react'; import config from 'app/core/config'; -import { messages } from '../../../locales/en/messages'; +import { messages as fallbackMessages } from '../../../locales/en-US/messages'; + +import { DEFAULT_LOCALE, FRENCH_FRANCE, SPANISH_SPAIN, VALID_LOCALES } from './constants'; let i18nInstance: I18n; -export async function getI18n(locale = 'en') { +export async function getI18n(localInput = DEFAULT_LOCALE) { if (i18nInstance) { return i18nInstance; } + + const validatedLocale = VALID_LOCALES.includes(localInput) ? localInput : DEFAULT_LOCALE; + // Dynamically load the messages for the user's locale const imp = config.featureToggles.internationalization && - (await import(`../../../locales/${locale}/messages`).catch((err) => { + (await import(`../../../locales/${validatedLocale}/messages`).catch((err) => { // TODO: Properly return an error if we can't find the messages for a locale return err; })); - i18n.load(locale, imp?.messages || messages); + + i18n.load(validatedLocale, imp?.messages || fallbackMessages); // Browser support for Intl.PluralRules is good and covers what we support in .browserlistrc, // but because this could potentially be in a the critical path of loading the frontend lets @@ -27,16 +33,16 @@ export async function getI18n(locale = 'en') { // If this isnt loaded, Lingui will log a warning and plurals will not be translated correctly. const supportsPluralRules = 'Intl' in window && 'PluralRules' in Intl; if (supportsPluralRules) { - const pluralsOrdinal = new Intl.PluralRules(locale, { type: 'ordinal' }); - const pluralsCardinal = new Intl.PluralRules(locale, { type: 'cardinal' }); - i18n.loadLocaleData(locale, { + const pluralsOrdinal = new Intl.PluralRules(validatedLocale, { type: 'ordinal' }); + const pluralsCardinal = new Intl.PluralRules(validatedLocale, { type: 'cardinal' }); + i18n.loadLocaleData(validatedLocale, { plurals(count: number, ordinal: boolean) { return (ordinal ? pluralsOrdinal : pluralsCardinal).select(count); }, }); } - i18n.activate(locale); + i18n.activate(validatedLocale); i18nInstance = i18n; return i18nInstance; @@ -52,13 +58,13 @@ export function I18nProvider({ children }: I18nProviderProps) { // TODO: Use locale preference instead of weekStart switch (config.bootData.user.weekStart) { case 'saturday': - loc = 'es'; + loc = SPANISH_SPAIN; break; case 'sunday': - loc = 'fr'; + loc = FRENCH_FRANCE; break; default: - loc = 'en'; + loc = DEFAULT_LOCALE; break; } } diff --git a/public/locales/en/messages.po b/public/locales/en-US/messages.po similarity index 100% rename from public/locales/en/messages.po rename to public/locales/en-US/messages.po diff --git a/public/locales/es/messages.po b/public/locales/es-ES/messages.po similarity index 100% rename from public/locales/es/messages.po rename to public/locales/es-ES/messages.po diff --git a/public/locales/fr/messages.po b/public/locales/fr-FR/messages.po similarity index 100% rename from public/locales/fr/messages.po rename to public/locales/fr-FR/messages.po