I18n: Add Chinese (Simplified) (#56739)

* Prevent _old.json files from being created

* Add contrib docs for adding new locale

* add chinese (simplified)
This commit is contained in:
Josh Hunt 2022-10-12 11:12:46 +01:00 committed by GitHub
parent 85e3ed491d
commit 719769ee7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 62 additions and 23 deletions

View File

@ -38,6 +38,18 @@ const ErrorMessage = ({ id, message }) => <Trans id={`errors.${id}`}>There was a
3. Before submitting your PR, run the `yarn i18n:extract` command to extract the messages you added into the `messages.po` file and make them available for translation.
## How to add a new language
1. Add new locale in Crowdin and sync files to repo
1. Grafana OSS Crowdin project -> "dot dot dot" menu in top right -> Target languages
2. Grafana OSS Crowdin project -> Integrations -> Github -> Sync Now
3. If Crowdin's locale code is different from our IETF language tag, add a custom mapping in Project Settings -> Language mapping
2. Update `public/app/core/internationalization/constants.ts` (add new constant, and add to `VALID_LOCALES`)
3. Update `public/app/core/internationalization/index.tsx` to add the message loader for the new locale
4. Update `public/app/core/components/SharedPreferences/SharedPreferences.tsx` to add the new locale to the options.
5. Update `public/locales/i18next-parser.config.js` to add the new locale to `locales`
6. Run `yarn i18n:extract` and commit the result
## How translations work in Grafana
Grafana uses the [LinguiJS](https://github.com/lingui/js-lingui) framework for managing translating phrases in the Grafana frontend. It:

View File

@ -19,7 +19,13 @@ import {
} from '@grafana/ui';
import { DashboardPicker } from 'app/core/components/Select/DashboardPicker';
import { t, Trans } from 'app/core/internationalization';
import { ENGLISH_US, FRENCH_FRANCE, PSEUDO_LOCALE, SPANISH_SPAIN } from 'app/core/internationalization/constants';
import {
CHINESE_SIMPLIFIED,
ENGLISH_US,
FRENCH_FRANCE,
PSEUDO_LOCALE,
SPANISH_SPAIN,
} from 'app/core/internationalization/constants';
import { PreferencesService } from 'app/core/services/PreferencesService';
import { UserPreferencesDTO } from 'app/types';
@ -43,15 +49,19 @@ const languages: Array<SelectableValue<string>> = [
},
{
value: ENGLISH_US,
label: t('common.locale.en', 'English'),
label: t('common.locale.en-US', 'English'),
},
{
value: SPANISH_SPAIN,
label: t('common.locale.es', 'Spanish'),
label: t('common.locale.es-ES', 'Spanish'),
},
{
value: FRENCH_FRANCE,
label: t('common.locale.fr', 'French'),
label: t('common.locale.fr-FR', 'French'),
},
{
value: CHINESE_SIMPLIFIED,
label: t('common.locale.zh-Hans', 'Chinese (Simplified)'),
},
// TODO: dev only
{

View File

@ -1,8 +1,9 @@
export const ENGLISH_US = 'en-US';
export const FRENCH_FRANCE = 'fr-FR';
export const SPANISH_SPAIN = 'es-ES';
export const CHINESE_SIMPLIFIED = 'zh-Hans';
export const PSEUDO_LOCALE = 'pseudo-LOCALE';
export const DEFAULT_LOCALE = ENGLISH_US;
export const VALID_LOCALES: string[] = [ENGLISH_US, FRENCH_FRANCE, SPANISH_SPAIN, PSEUDO_LOCALE];
export const VALID_LOCALES: string[] = [ENGLISH_US, FRENCH_FRANCE, SPANISH_SPAIN, CHINESE_SIMPLIFIED, PSEUDO_LOCALE];

View File

@ -2,12 +2,21 @@ import i18n, { BackendModule, ResourceKey } from 'i18next';
import React from 'react';
import { Trans as I18NextTrans, initReactI18next } from 'react-i18next'; // eslint-disable-line no-restricted-imports
import { DEFAULT_LOCALE, ENGLISH_US, FRENCH_FRANCE, SPANISH_SPAIN, PSEUDO_LOCALE, VALID_LOCALES } from './constants';
import {
DEFAULT_LOCALE,
ENGLISH_US,
FRENCH_FRANCE,
SPANISH_SPAIN,
PSEUDO_LOCALE,
VALID_LOCALES,
CHINESE_SIMPLIFIED,
} from './constants';
const messageLoaders: Record<string, () => Promise<ResourceKey>> = {
[ENGLISH_US]: () => import('../../../locales/en-US/grafana.json'),
[FRENCH_FRANCE]: () => import('../../../locales/fr-FR/grafana.json'),
[SPANISH_SPAIN]: () => import('../../../locales/es-ES/grafana.json'),
[CHINESE_SIMPLIFIED]: () => import('../../../locales/zh-Hans/grafana.json'),
[PSEUDO_LOCALE]: () => import('../../../locales/pseudo-LOCALE/grafana.json'),
};

View File

@ -2,9 +2,10 @@
"common": {
"locale": {
"default": "Default",
"en": "English",
"es": "Spanish",
"fr": "French"
"en-US": "English",
"es-ES": "Spanish",
"fr-FR": "French",
"zh-Hans": "Chinese (Simplified)"
},
"save": "Save"
},

View File

@ -2,9 +2,10 @@
"common": {
"locale": {
"default": "",
"en": "",
"es": "",
"fr": ""
"en-US": "",
"es-ES": "",
"fr-FR": "",
"zh-Hans": ""
},
"save": ""
},

View File

@ -2,9 +2,10 @@
"common": {
"locale": {
"default": "",
"en": "",
"es": "",
"fr": ""
"en-US": "",
"es-ES": "",
"fr-FR": "",
"zh-Hans": ""
},
"save": ""
},

View File

@ -2,7 +2,7 @@ module.exports = {
// Default namespace used in your i18next config
defaultNamespace: 'grafana',
locales: ['en-US', 'fr-FR', 'es-ES', 'pseudo-LOCALE'],
locales: ['en-US', 'fr-FR', 'es-ES', "zh-Hans", 'pseudo-LOCALE'],
output: './public/locales/$LOCALE/$NAMESPACE.json',
@ -10,6 +10,8 @@ module.exports = {
sort: true,
createOldCatalogs: false,
// Don't include default values for English, they'll remain in the source code
skipDefaultValues: (locale) => locale !== 'en-US',
};

View File

@ -2,9 +2,10 @@
"common": {
"locale": {
"default": "Đęƒäūľŧ",
"en": "Ēʼnģľįşĥ",
"es": "Ŝpäʼnįşĥ",
"fr": "Fřęʼnčĥ"
"en-US": "Ēʼnģľįşĥ",
"es-ES": "Ŝpäʼnįşĥ",
"fr-FR": "Fřęʼnčĥ",
"zh-Hans": "Cĥįʼnęşę (Ŝįmpľįƒįęđ)"
},
"save": "Ŝävę"
},

View File

@ -2,9 +2,10 @@
"common": {
"locale": {
"default": "",
"en": "",
"es": "",
"fr": ""
"en-US": "",
"es-ES": "",
"fr-FR": "",
"zh-Hans": ""
},
"save": ""
},