React + umi(使用umi内部组件SelectLang)实现多语言

前言:众所周知项目国际化首先会想到的是有英文,其次就是我们开发者所在地的语言比如我们的中文,那么如果想要添加一个其他国家的语言该怎么办?还是第一次接触添加其他国家的语言,直接想法是一个下拉框里面添加你想要的国家然后根据下拉的value值进行切换对应的国际化的文件。我们拿React + Umi通过解析源码来记录一下

首先我们找到Umi的国际化切换组件SelectLang发现这并不直接是一个下拉框,那么我们初始的构想在里面加一个选项的想法就被迫落空,下面看下代码

Umi提供的切换语言的组件
<SelectLang />

按着Ctrl点击组件名可以看到该组建所接受的Props就有哪些下面列一下

组件的Props属性有
globalIconClassName?: string;
postLocalesData?: (locales: LocalData[]) => LocalData[];
onItemClick?: (params: ClickParam) => void;
className?: string;
reload?: boolean;
icon?: React.ReactNode;

可以看到onItemClick是切换国际化的回调函数,参数是所切换成的语言的value值,我们可以看到里面并没有类似于SelectOptions属性,那么我们如果添加我们想要的国际化语言
通过按Ctrl同时用鼠标点击SelectLang标签会进入到源码,也就是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>
  );

这个就是组件源码下拉的渲染部分,我们可以看到是通过allLangUIConfig负责渲染我们想要的语言,那么allLangUIConfig的来源是什么呢,我们接着往下看,通过查找发现还是在源码中发现

  const allLangUIConfig =
    postLocalesData?.(defaultLangUConfig) || defaultLangUConfig;
  const handleClick = onItemClick
    ? (params: ClickParam) => onItemClick(params)
    : changeLang;

我们此时又看到了postLocalesData,这个不是组件SelectLangProps吗?没错就是这样的,这个组件接收一个LocalData类型的数组

interface LocalData {
    lang: string,
    label?: string,
    icon?: string,
    title?: string,
}

等等我们可以看到allLangUIConfig =postLocalesData?.(defaultLangUConfig) || defaultLangUConfig如果我们不传postLocalesData这个Props那么怎么实现呢,我们再来看下defaultLangUConfig的来源是什么

  const defaultLangUConfig = getAllLocales().map(
    (key) =>
      defaultLangUConfigMap[key] || {
        lang: key,
        label: key,
        icon: "🌐",
        title: key,
      }
  );

我们不止看到了defaultLangUConfigMap又看到了getAllLocales,像不像套娃一个接一个哈哈,那么我们一层一层的看,先来看一下getAllLocales,发现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里面的信息不需要我们人为的添加,只需要在defaultLangUConfigMap中找到日本所对应的key,日本对应的语言的key就是ja-JP,我们只需在我们的项目中找到locales这个文件夹在里面新建一个文件夹叫做ja-JP,里面放日本的语言文件,然后再建一个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: 'Română',
    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这个信息还是非常全面的几乎覆盖所有的国家,
最后拿着getAllLocales获取的所有的配置信息在defaultLangUConfigMap中挑出对应的配置来给国际语言切换组件SelectLangMenu来渲染,这样我们就不用postLocalesData这个属性就可以实现我们想要的功能

本篇文章到这里就结束了感谢看我啰嗦 哈哈

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容