美文网首页
基于React Hook的国际化(i18n)解决方案

基于React Hook的国际化(i18n)解决方案

作者: 请叫我Pro大叔 | 来源:发表于2020-11-12 17:17 被阅读0次

    设计思路

    • 持久化locale信息到localeStorage
    • 创建useLocale 用于获取locale以及设置并持久化locale信息
    • 创建I18nConfigProvider提供locale配置加载方法
    • 创建useLocaleConfig用于根据locale的变化加载locale配置
    • 创建LocaleConfigProvider.tsx将LocaleConfig配置应用于组件中

    代码

    /* types.ts */
    import { Locale as AntdLocale } from 'antd/lib/locale-provider'
    import { IntlConfig } from 'react-intl'
    
    export type SupportedLocale = 'en-US' | 'zh-CN'
    
    export interface LocaleConfig extends Pick<IntlConfig, 'messages'> {
      locale: SupportedLocale
      /** 支持antd配置 */
      antdLocale: AntdLocale
    }
    
    export interface I18nConfigProvider {
      defaultConfig: LocaleConfig
      getConfig: (locale?: SupportedLocale) => Promise<LocaleConfig>
    }
    
    /** locale.ts */
    
    /** 默认i18nProvider */
    const defaultI18nProvider: I18nConfigProvider = {
      defaultConfig: enConfig,
      // defaultConfig: zhConfig,
      async getConfig(locale?: SupportedLocale) {
        if (locale === 'zh-CN') {
          return (await import('./zh_CN')).default
        }
    
        if (locale === 'en-US') {
          return enConfig
        }
    
        return this.defaultConfig
      }
    }
    
    const KEY_LOCALE = '__locale__'
    const DEFAULT_LOCALE = 'en-US'
    
    function persistLocale(lang: SupportedLocale) {
      window.localStorage.setItem(KEY_LOCALE, lang || DEFAULT_LOCALE)
    
      // 重新刷新整个页面
      // window.location.reload()
    }
    
    export function getLocale(): SupportedLocale {
      return (
        (window.localStorage.getItem(KEY_LOCALE) as SupportedLocale) ??
        DEFAULT_LOCALE
      )
    }
    
    const createLocaleHook = (defaultLocale: SupportedLocale = getLocale()) => {
      let localeCache = defaultLocale
      let reactions = []
    
      const setStoreFn = (newLocale: SupportedLocale) => {
        localeCache = newLocale
    
        persistLocale(localeCache)
    
        // Call reactions
        reactions.forEach(fn => fn())
      }
    
      return (): [SupportedLocale, (newLocale: SupportedLocale) => void] => {
        const [locale, setLocale] = useState<SupportedLocale>(localeCache)
        const reaction = useCallback(() => {
          setLocale(localeCache)
        }, [])
    
        useEffect(() => {
          reactions.push(reaction)
    
          return () => {
            reactions = reactions.filter(f => reaction !== f)
          }
        }, [])
    
        return [locale, setStoreFn]
      }
    }
    
    export const useLocale = createLocaleHook()
    
    export const useLocaleConfig = (
      defaultI18nConfigProvider: I18nConfigProvider = defaultI18nProvider
    ) => {
      const { getConfig, defaultConfig } = defaultI18nConfigProvider
      const [locale] = useLocale()
      const [localeConfig, setLocaleConfig] = useState<LocaleConfig>(defaultConfig)
      useEffect(() => {
        // DO Load New Locale Config
        const load = async () => {
          const newLocaleConfig = await getConfig(locale)
          console.log('newLocaleConfig ---> ', newLocaleConfig)
          setLocaleConfig(newLocaleConfig)
        }
    
        if (locale && locale !== defaultConfig.locale) {
          load()
        } else {
          setLocaleConfig(defaultConfig)
        }
      }, [locale, localeConfigProvider])
    
      return localeConfig
    }
    
    /** LocaleConfigProvider.tsx */
    import { useLocaleConfig } from '@/locales'
    import { ConfigProvider } from 'antd'
    import React from 'react'
    import { IntlProvider } from 'react-intl'
    
    const LocaleConfigProvider: React.FC = ({ children }) => {
      const currentConfig = useLocaleConfig()
    
      return (
        <IntlProvider
          messages={currentConfig.messages}
          locale={currentConfig.locale}
          defaultLocale={currentConfig.locale}
        >
          <ConfigProvider locale={currentConfig.antdLocale}>
            {children}
          </ConfigProvider>
        </IntlProvider>
      )
    }
    
    export default LocaleConfigProvider
    

    相关文章

      网友评论

          本文标题:基于React Hook的国际化(i18n)解决方案

          本文链接:https://www.haomeiwen.com/subject/aaupbktx.html