前言:眾所周知項(xiàng)目國際化首先會想到的是有英文,其次就是我們開發(fā)者所在地的語言比如我們的中文,那么如果想要添加一個(gè)其他國家的語言該怎么辦?還是第一次接觸添加其他國家的語言,直接想法是一個(gè)下拉框里面添加你想要的國家然后根據(jù)下拉的value值進(jìn)行切換對應(yīng)的國際化的文件。我們拿React + Umi
通過解析源碼來記錄一下
首先我們找到Umi的國際化切換組件SelectLang
發(fā)現(xiàn)這并不直接是一個(gè)下拉框,那么我們初始的構(gòu)想在里面加一個(gè)選項(xiàng)的想法就被迫落空,下面看下代碼
Umi提供的切換語言的組件
<SelectLang />
按著Ctrl
點(diǎn)擊組件名可以看到該組建所接受的Props
就有哪些下面列一下
組件的Props屬性有
globalIconClassName?: string;
postLocalesData?: (locales: LocalData[]) => LocalData[];
onItemClick?: (params: ClickParam) => void;
className?: string;
reload?: boolean;
icon?: React.ReactNode;
可以看到onItemClick
是切換國際化的回調(diào)函數(shù),參數(shù)是所切換成的語言的value
值,我們可以看到里面并沒有類似于Select
的Options
屬性,那么我們?nèi)绻砑游覀兿胍膰H化語言
通過按Ctrl
同時(shí)用鼠標(biāo)點(diǎn)擊SelectLang
標(biāo)簽會進(jìn)入到源碼,也就是SelectLang.tsx
文件
const langMenu = (
<Menu selectedKeys={[selectedLang]} onClick={handleClick}>
{allLangUIConfig.map((localeObj) => {
return (
<Menu.Item key={localeObj.lang || localeObj.key} style={menuItemStyle}>
<span role="img" aria-label={localeObj?.label || "en-US"} style={menuItemIconStyle}>
{localeObj?.icon || "??"}
</span>
{localeObj?.label || "en-US"}
</Menu.Item>
);
})}
</Menu>
);
這個(gè)就是組件源碼下拉的渲染部分,我們可以看到是通過allLangUIConfig
負(fù)責(zé)渲染我們想要的語言,那么allLangUIConfig
的來源是什么呢,我們接著往下看,通過查找發(fā)現(xiàn)還是在源碼中發(fā)現(xiàn)
const allLangUIConfig =
postLocalesData?.(defaultLangUConfig) || defaultLangUConfig;
const handleClick = onItemClick
? (params: ClickParam) => onItemClick(params)
: changeLang;
我們此時(shí)又看到了postLocalesData
,這個(gè)不是組件SelectLang
的Props
嗎?沒錯(cuò)就是這樣的,這個(gè)組件接收一個(gè)LocalData
類型的數(shù)組
interface LocalData {
lang: string,
label?: string,
icon?: string,
title?: string,
}
等等我們可以看到allLangUIConfig =postLocalesData?.(defaultLangUConfig) || defaultLangUConfig
如果我們不傳postLocalesData
這個(gè)Props
那么怎么實(shí)現(xiàn)呢,我們再來看下defaultLangUConfig
的來源是什么
const defaultLangUConfig = getAllLocales().map(
(key) =>
defaultLangUConfigMap[key] || {
lang: key,
label: key,
icon: "??",
title: key,
}
);
我們不止看到了defaultLangUConfigMap又看到了getAllLocales,像不像套娃一個(gè)接一個(gè)哈哈,那么我們一層一層的看,先來看一下getAllLocales,發(fā)現(xiàn)getAllLocales的來源是
import { getLocale, getAllLocales, setLocale } from './localeExports';
那么localeExports里面是什么呢,我們一起來看下
export const localeInfo: {[key: string]: any} = {
'en-US': {
messages: {
...lang_enUS0,
},
locale: 'en-US',
antd: {
...enUS0,
},
momentLocale: '',
},
'th-TH': {
messages: {
...lang_thTH0,
},
locale: 'th-TH',
antd: {
...thTH0,
},
momentLocale: 'th',
},
'zh-CN': {
messages: {
...lang_zhCN0,
},
locale: 'zh-CN',
antd: {
...zhCN0,
},
momentLocale: 'zh-cn',
},
};
/**
* 獲取語言列表
* @returns string[]
*/
export const getAllLocales = () => Object.keys(localeInfo);
比如我們需要日本的語言,localeInfo
里面的信息不需要我們?nèi)藶榈奶砑?,只需要?code>defaultLangUConfigMap中找到日本所對應(yīng)的key,日本對應(yīng)的語言的key就是ja-JP
,我們只需在我們的項(xiàng)目中找到locales
這個(gè)文件夾在里面新建一個(gè)文件夾叫做ja-JP
,里面放日本的語言文件,然后再建一個(gè)ja-JP.ts
來引入文件夾ja-JP
下面的文件即可
接著看下defaultLangUConfigMap
,勝利就在眼前了撐住兄弟們
const defaultLangUConfigMap = {
'ar-EG': {
lang: 'ar-EG',
label: '???????',
icon: '????',
title: '???'
},
'az-AZ': {
lang: 'az-AZ',
label: 'Az?rbaycan dili',
icon: '????',
title: 'Dil'
},
'bg-BG': {
lang: 'bg-BG',
label: 'Български език',
icon: '????',
title: 'език'
},
'bn-BD': {
lang: 'bn-BD',
label: '?????',
icon: '????',
title: '????'
},
'ca-ES': {
lang: 'ca-ES',
label: 'Catalá',
icon: '????',
title: 'llengua'
},
'cs-CZ': {
lang: 'cs-CZ',
label: '?e?tina',
icon: '????',
title: 'Jazyk'
},
'da-DK': {
lang: 'da-DK',
label: 'Dansk',
icon: '????',
title: 'Sprog'
},
'de-DE': {
lang: 'de-DE',
label: 'Deutsch',
icon: '????',
title: 'Sprache'
},
'el-GR': {
lang: 'el-GR',
label: 'Ελληνικ?',
icon: '????',
title: 'Γλ?σσα'
},
'en-GB': {
lang: 'en-GB',
label: 'English',
icon: '????',
title: 'Language'
},
'en-US': {
lang: 'en-US',
label: 'English',
icon: '????',
title: 'Language'
},
'es-ES': {
lang: 'es-ES',
label: 'Espa?ol',
icon: '????',
title: 'Idioma'
},
'et-EE': {
lang: 'et-EE',
label: 'Eesti',
icon: '????',
title: 'Keel'
},
'fa-IR': {
lang: 'fa-IR',
label: '?????',
icon: '????',
title: '????'
},
'fi-FI': {
lang: 'fi-FI',
label: 'Suomi',
icon: '????',
title: 'Kieli'
},
'fr-BE': {
lang: 'fr-BE',
label: 'Fran?ais',
icon: '????',
title: 'Langue'
},
'fr-FR': {
lang: 'fr-FR',
label: 'Fran?ais',
icon: '????',
title: 'Langue'
},
'ga-IE': {
lang: 'ga-IE',
label: 'Gaeilge',
icon: '????',
title: 'Teanga'
},
'he-IL': {
lang: 'he-IL',
label: '?????',
icon: '????',
title: '???'
},
'hi-IN': {
lang: 'hi-IN',
label: '??????, ?????',
icon: '????',
title: '????: ??????'
},
'hr-HR': {
lang: 'hr-HR',
label: 'Hrvatski jezik',
icon: '????',
title: 'Jezik'
},
'hu-HU': {
lang: 'hu-HU',
label: 'Magyar',
icon: '????',
title: 'Nyelv'
},
'hy-AM': {
lang: 'hu-HU',
label: '???????',
icon: '????',
title: '?????'
},
'id-ID': {
lang: 'id-ID',
label: 'Bahasa Indonesia',
icon: '????',
title: 'Bahasa'
},
'it-IT': {
lang: 'it-IT',
label: 'Italiano',
icon: '????',
title: 'Linguaggio'
},
'is-IS': {
lang: 'is-IS',
label: 'íslenska',
icon: '????',
title: 'Tungumál'
},
'ja-JP': {
lang: 'ja-JP',
label: '日本語',
icon: '????',
title: '言語'
},
'ku-IQ': {
lang: 'ku-IQ',
label: '?????',
icon: '????',
title: 'Ziman'
},
'kn-IN': {
lang: 'zh-TW',
label: '?????',
icon: '????',
title: '????'
},
'ko-KR': {
lang: 'ko-KR',
label: '???',
icon: '????',
title: '??'
},
'lv-LV': {
lang: 'lv-LV',
label: 'Latvie?u valoda',
icon: '????',
title: 'Kalba'
},
'mk-MK': {
lang: 'mk-MK',
label: 'македонски ?азик',
icon: '????',
title: '?азик'
},
'mn-MN': {
lang: 'mn-MN',
label: 'Монгол хэл',
icon: '????',
title: 'Хэл'
},
'ms-MY': {
lang: 'ms-MY',
label: '???? ?????',
icon: '????',
title: 'Bahasa'
},
'nb-NO': {
lang: 'nb-NO',
label: 'Norsk',
icon: '????',
title: 'Spr?k'
},
'ne-NP': {
lang: 'ne-NP',
label: '??????',
icon: '????',
title: '????'
},
'nl-BE': {
lang: 'nl-BE',
label: 'Vlaams',
icon: '????',
title: 'Taal'
},
'nl-NL': {
lang: 'nl-NL',
label: 'Vlaams',
icon: '????',
title: 'Taal'
},
'pl-PL': {
lang: 'pl-PL',
label: 'Polski',
icon: '????',
title: 'J?zyk'
},
'pt-BR': {
lang: 'pt-BR',
label: 'Português',
icon: '????',
title: 'Idiomas'
},
'pt-PT': {
lang: 'pt-PT',
label: 'Português',
icon: '????',
title: 'Idiomas'
},
'ro-RO': {
lang: 'ro-RO',
label: 'Roman?',
icon: '????',
title: 'Limba'
},
'ru-RU': {
lang: 'ru-RU',
label: 'Русский',
icon: '????',
title: 'язык'
},
'sk-SK': {
lang: 'sk-SK',
label: 'Sloven?ina',
icon: '????',
title: 'Jazyk'
},
'sr-RS': {
lang: 'sr-RS',
label: 'српски ?език',
icon: '????',
title: '?език'
},
'sl-SI': {
lang: 'sl-SI',
label: 'Sloven??ina',
icon: '????',
title: 'Jezik'
},
'sv-SE': {
lang: 'sv-SE',
label: 'Svenska',
icon: '????',
title: 'Spr?k'
},
'ta-IN': {
lang: 'ta-IN',
label: '?????',
icon: '????',
title: '????'
},
'th-TH': {
lang: 'th-TH',
label: '???',
icon: '????',
title: '????'
},
'tr-TR': {
lang: 'tr-TR',
label: 'Türk?e',
icon: '????',
title: 'Dil'
},
'uk-UA': {
lang: 'uk-UA',
label: 'Укра?нська',
icon: '????',
title: 'Мова'
},
'vi-VN': {
lang: 'vi-VN',
label: 'Ti?ng Vi?t',
icon: '????',
title: 'Ng?n ng?'
},
'zh-CN': {
lang: 'zh-CN',
label: '簡體中文',
icon: '????',
title: '語言'
},
'zh-TW': {
lang: 'zh-TW',
label: '繁體中文',
icon: '????',
title: '語言'
}
};
可以看到defaultLangUConfigMap
這個(gè)信息還是非常全面的幾乎覆蓋所有的國家,
最后拿著getAllLocales
獲取的所有的配置信息在defaultLangUConfigMap
中挑出對應(yīng)的配置來給國際語言切換組件SelectLang
的Menu
來渲染,這樣我們就不用postLocalesData
這個(gè)屬性就可以實(shí)現(xiàn)我們想要的功能
本篇文章到這里就結(jié)束了感謝看我啰嗦 哈哈