feat: support Korean i18n

Support Korean i18n

Change-Id: Idf5efce1ad02743f0ba8734009e1bb661038c087
This commit is contained in:
Jingwei.Zhang 2023-03-23 10:23:18 +08:00
parent decd2bfec7
commit 235ee19da6
9 changed files with 3077 additions and 51 deletions

View File

@ -19,7 +19,7 @@ module.exports = function (grunt) {
src: ['src/**/*.{jsx,js}'], src: ['src/**/*.{jsx,js}'],
dest: 'src', dest: 'src',
options: { options: {
lngs: ['en', 'zh'], lngs: ['en', 'zh', 'ko-kr'],
removeUnusedKeys: true, removeUnusedKeys: true,
sort: true, sort: true,
keySeparator: false, keySeparator: false,
@ -39,10 +39,10 @@ module.exports = function (grunt) {
extensions: ['.js', '.jsx'], extensions: ['.js', '.jsx'],
}, },
defaultValue: (lng, ns, key) => { defaultValue: (lng, ns, key) => {
if (lng === 'zh') { if (lng === 'en') {
return '';
}
return key; return key;
}
return '';
}, },
}, },
}, },

View File

@ -0,0 +1,10 @@
---
features:
- |
Support Korean I18n:
* Korean language switching is supported on the login page.
* Support switch Korean in the avatar hover box on the upper right of the page after logged in.
* Support automatic collection of Korean i18n file.

View File

@ -14,7 +14,7 @@
import React from 'react'; import React from 'react';
import { inject, observer } from 'mobx-react'; import { inject, observer } from 'mobx-react';
import { Menu, Spin, Button } from 'antd'; import { Menu, Spin, Button, Select } from 'antd';
import { UserOutlined } from '@ant-design/icons'; import { UserOutlined } from '@ant-design/icons';
import i18n from 'core/i18n'; import i18n from 'core/i18n';
import ItemActionButtons from 'components/Tables/Base/ItemActionButtons'; import ItemActionButtons from 'components/Tables/Base/ItemActionButtons';
@ -24,7 +24,7 @@ import OpenRc from './OpenRc';
import HeaderDropdown from '../HeaderDropdown'; import HeaderDropdown from '../HeaderDropdown';
import styles from './index.less'; import styles from './index.less';
const { getLocale, setLocale } = i18n; const { getLocale, setLocale, SUPPORT_LOCALES } = i18n;
export class AvatarDropdown extends React.Component { export class AvatarDropdown extends React.Component {
get rootStore() { get rootStore() {
@ -58,6 +58,51 @@ export class AvatarDropdown extends React.Component {
} }
}; };
onClickSelectLanguage = (e) => {
e && e.preventDefault();
e && e.stopPropagation();
};
renderLanguageSwitch() {
const selectedLang = getLocale();
const { length } = SUPPORT_LOCALES;
if (length > 3) {
const options = SUPPORT_LOCALES.map((it) => ({
label: it.shortName.toLocaleUpperCase(),
value: it.value,
}));
return (
<div style={{ float: 'right' }}>
<Select
options={options}
value={selectedLang}
onChange={this.changeLang}
onClick={this.onClickSelectLanguage}
/>
</div>
);
}
const btns = SUPPORT_LOCALES.map((item, index) => {
const { value, shortName } = item;
return (
<>
<Button
className={index === 0 ? styles['no-padding-top'] : ''}
type="link"
disabled={selectedLang === value}
onClick={() => {
this.changeLang(value);
}}
>
{shortName.toUpperCase()}
</Button>
{index !== length - 1 && <span>/</span>}
</>
);
});
return <span style={{ float: 'right' }}>{btns}</span>;
}
render() { render() {
if (!this.user) { if (!this.user) {
return ( return (
@ -71,7 +116,6 @@ export class AvatarDropdown extends React.Component {
); );
} }
const { name: username } = this.user.user; const { name: username } = this.user.user;
const selectedLang = getLocale();
// const { selectedLang } = this.state.selectedLang; // const { selectedLang } = this.state.selectedLang;
const menuHeaderDropdown = ( const menuHeaderDropdown = (
<Menu className={styles.menu} onClick={this.onMenuClick}> <Menu className={styles.menu} onClick={this.onMenuClick}>
@ -97,28 +141,7 @@ export class AvatarDropdown extends React.Component {
className={`${styles['no-hover']} ${styles['menu-item']}`} className={`${styles['no-hover']} ${styles['menu-item']}`}
> >
<span>{t('Switch Language')}</span> <span>{t('Switch Language')}</span>
<span style={{ float: 'right' }}> {this.renderLanguageSwitch()}
<Button
className={styles['no-padding-top']}
type="link"
disabled={selectedLang === 'zh-cn'}
onClick={() => {
this.changeLang('zh-cn');
}}
>
CN
</Button>
<span>/</span>
<Button
type="link"
disabled={selectedLang === 'en'}
onClick={() => {
this.changeLang('en');
}}
>
EN
</Button>
</span>
</Menu.Item> </Menu.Item>
<Menu.Item key="password" className={styles['menu-item']}> <Menu.Item key="password" className={styles['menu-item']}>
<ItemActionButtons <ItemActionButtons

View File

@ -19,7 +19,7 @@ import classNames from 'classnames';
import { GlobalOutlined } from '@ant-design/icons'; import { GlobalOutlined } from '@ant-design/icons';
import styles from './index.less'; import styles from './index.less';
const { getLocale, setLocale } = i18n; const { getLocale, setLocale, SUPPORT_LOCALES } = i18n;
const SelectLang = (props) => { const SelectLang = (props) => {
const { className } = props; const { className } = props;
@ -29,27 +29,21 @@ const SelectLang = (props) => {
setLocale(key, false); setLocale(key, false);
}; };
const locales = ['zh-cn', 'en']; const locales = SUPPORT_LOCALES.map((it) => it.value);
const languageLabels = { const languageLabels = SUPPORT_LOCALES.map((it) => it.name);
'zh-cn': '简体中文', const languageIcons = SUPPORT_LOCALES.map((it) => it.icon);
en: 'English',
};
const languageIcons = {
'zh-cn': '🇨🇳',
en: '🇺🇸',
};
const langMenu = ( const langMenu = (
<Menu <Menu
className={styles.menu} className={styles.menu}
selectedKeys={[selectedLang]} selectedKeys={[selectedLang]}
onClick={changeLang} onClick={changeLang}
> >
{locales.map((locale) => ( {locales.map((locale, index) => (
<Menu.Item key={locale}> <Menu.Item key={locale}>
<span role="img" aria-label={languageLabels[locale]}> <span role="img" aria-label={languageLabels[index]}>
{languageIcons[locale]} {languageIcons[index]}
</span>{' '} </span>{' '}
{languageLabels[locale]} {languageLabels[index]}
</Menu.Item> </Menu.Item>
))} ))}
</Menu> </Menu>

View File

@ -24,10 +24,20 @@ const SUPPORT_LOCALES = [
{ {
name: 'English', name: 'English',
value: 'en', value: 'en',
shortName: 'en',
icon: 'us',
}, },
{ {
name: '简体中文', name: '简体中文',
value: 'zh-cn', value: 'zh-cn',
shortName: 'zh',
icon: 'cn',
},
{
name: '한글',
value: 'ko-kr',
shortName: 'kr',
icon: 'kr',
}, },
]; ];
@ -63,6 +73,12 @@ const getLocale = () => {
return currentLocale; return currentLocale;
}; };
const getLocaleShortName = () => {
const fullName = getLocale();
const item = SUPPORT_LOCALES.find((it) => it.value === fullName);
return item ? item.shortName : fullName;
};
const loadLocales = () => { const loadLocales = () => {
const currentLocale = getLocale(); const currentLocale = getLocale();
return intl.init({ return intl.init({
@ -131,4 +147,6 @@ export default {
init, init,
t, t,
isLocaleZh, isLocaleZh,
getLocaleShortName,
SUPPORT_LOCALES,
}; };

View File

@ -36,9 +36,10 @@ export class BlankLayout extends Component {
} }
get title() { get title() {
const { title: { zh = t('Cloud'), en = 'Cloud' } = {} } = this.info; const { title = { zh: t('Cloud'), en: 'Cloud' } } = this.info;
const { isLocaleZh } = i18n; const { getLocaleShortName } = i18n;
return isLocaleZh ? zh : en; const language = getLocaleShortName();
return title[language] || t('Cloud') || 'Cloud';
} }
render() { render() {

View File

@ -14,8 +14,10 @@
import zhData from './zh.json'; import zhData from './zh.json';
import enData from './en.json'; import enData from './en.json';
import krData from './ko-kr.json';
export default { export default {
'zh-cn': zhData, 'zh-cn': zhData,
en: enData, en: enData,
'ko-kr': krData,
}; };

2976
src/locales/ko-kr.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -69,11 +69,13 @@ export class Login extends Component {
} }
get productName() { get productName() {
const { const { product_name = { zh: t('Cloud Platform'), en: 'Cloud Platform' } } =
product_name: { zh = t('Cloud Platform'), en = 'Cloud Platform' } = {}, this.info;
} = this.info; const { getLocaleShortName } = i18n;
const { isLocaleZh } = i18n; const language = getLocaleShortName();
return t('Welcome, {name}', { name: isLocaleZh ? zh : en }); const name =
product_name[language] || t('Cloud Platform') || 'Cloud Platform';
return t('Welcome, {name}', { name });
} }
get domains() { get domains() {