React + umi(使用umi內(nèi)部組件SelectLang)實(shí)現(xiàn)多語言

前言:眾所周知項(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值,我們可以看到里面并沒有類似于SelectOptions屬性,那么我們?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è)不是組件SelectLangProps嗎?沒錯(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)的配置來給國際語言切換組件SelectLangMenu來渲染,這樣我們就不用postLocalesData這個(gè)屬性就可以實(shí)現(xiàn)我們想要的功能

本篇文章到這里就結(jié)束了感謝看我啰嗦 哈哈

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,978評論 2 374

推薦閱讀更多精彩內(nèi)容