React i18next 和更改语言的正确方法

Posted

技术标签:

【中文标题】React i18next 和更改语言的正确方法【英文标题】:React i18next and correct way of changing language 【发布时间】:2016-06-14 05:00:31 【问题描述】:

我正在使用 React、i18nexti18next-browser-languagedetector 开发一个多语言应用程序。

我通过以下方式初始化 i18next:

i18n
  .use(LanguageDetector)
  .init(
    lng: localStorage.getItem(I18N_LANGUAGE) || "pt",
    fallbackLng: "pt",
    resources: 
      en: stringsEn,
      pt: stringsPt
    ,
    detection: 
      order: ["localStorage", "navigator"],
      lookupQuerystring: "lng",
      lookupLocalStorage: I18N_LANGUAGE,
      caches: ["localStorage"]
    
  );

export default i18n;

我已经实现了一个语言选择器,它只是将localStorage 中的值更改为用户选择的值。

这是正确的做法吗?

我之所以问,是因为即使这可行,我也觉得我通过设置 localStorage.getItem(I18N_LANGUAGE) || "pt" 来“作弊”,而且我没有按应有的方式使用语言检测。

【问题讨论】:

我正在尝试解决同样的问题并找到了两个解决方案。首先:您可以将语言环境存储为 url 参数 (:locale\you_url),例如 this。第二个是您的变体 - 将语言环境存储在 localStorage 或 cookie 中。我想和你一样,但 i18next 找不到密钥。请你写一个例子或分享你的代码吗? 我们选择在 localStorage 中设置语言环境。 i18next 找不到钥匙是什么意思?顺便说一句,我正在使用react-i18next。检查这个:gist.github.com/pteixeira/4a75160ca15e3edf6975 我还有一个语言选择器组件,它在初始化时将 localStorage 条目设置为语言的值,检查默认值或用户选择的内容。 谢谢,对我很有帮助。还有一个问题:有没有办法在运行时改变语言? 运行时是什么意思?如果您在应用程序运行时询问,在我在上面的评论中提到的那个语言选择器组件中,我添加了一个事件侦听器到一个具有我们支持的语言选项的选择组件中,我们使用 i18n.changeLanguage(ev.target.value); 设置语言( i18n来自i18next) 和localStorage.setItem(I18N_LANGUAGE, ev.target.value);。希望它有用:) 【参考方案1】:

根据documentation,您不需要自己指定语言:

import i18next from 'i18next';
import LngDetector from 'i18next-browser-languagedetector';

i18next
  .use(LngDetector)
  .init(
    detection: options
  );

并且根据i18next中的this piece of source,确实使用了插件的检测能力:

if (!lng && this.services.languageDetector) lng = this.services.languageDetector.detect();

这是正确的做法吗?

所以,不,不是。让插件完成它的工作。 :)

【讨论】:

正确响应...如果您在 init 上设置语言,则语言检测器将无法完成检测工作。可以标记为正确答案。 Best Jan(又名 jamuhl:i18next 的维护者) 我查看了代码并对其进行了重构以正确使用插件。还将答案标记为已接受。 我有一个疑问。当然插件在这部分做得很完美,但是如果用户想要更新默认的首选语言而不使用插件上的那一套呢?根据这个答案,用户将始终使用默认值加载,但(s)他将无法将首选语言保存在本地存储中,然后重新加载应用程序。我们怎样才能做到这一点?【参考方案2】:

希望这对将来的某人有所帮助。文档并没有完全为您提供如何设置检测的全貌,然后我找到了一个 closed Github issue,其中有几个人在问一个合理的问题,维护人员的回答有点粗鲁,但也碰巧提供了一个link 应该在文档中 - 但在 Github 评论之外绝对没有被引用。该示例通过对当前文档说明的内容进行了一些小调整,从而解决了我的问题。

然后,我可以在我的网址中使用https:www.domain.com?lng=es 以及在使用允许我更改浏览器语言的浏览器扩展程序时获得语言检测。

这是我的工作 i18n.ts 文件:

import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import  initReactI18next  from 'react-i18next'
import XHR from "i18next-http-backend" // <---- add this

import commonDe from './locales/de/common.json'
import commonEn from './locales/en/common.json'
import commonEs from './locales/es/common.json'
import commonFr from './locales/fr/common.json'

const resources = 
  de:  common: commonDe ,
  en:  common: commonEn ,
  es:  common: commonEs ,
  fr:  common: commonFr 


const options = 
  order: ['querystring', 'navigator'],
  lookupQuerystring: 'lng'


i18n
  .use(XHR) // <---- add this
  .use(LanguageDetector)
  .use(initReactI18next)
  .init(
    // lng: 'en' // <--- turn off for detection to work
    detection: options,
    resources,
    ns: ['common'],
    defaultNS: 'common',
    fallbackLng: 'en',
    supportedLngs: ['de', 'en', 'es', 'fr'],
    interpolation: 
      escapeValue: false,
    ,
    debug: false,
  )

export default i18n

(额外帮助 - 如果有人在这部分卡住)

我在一个 Next.js 项目中工作,上面的文件被加载到 project-root/pages/_app.tsx 文件中,如下所示:

import React from 'react'
import  AppProps  from 'next/app'
import '../i18n/i18n'

import '../public/styles.css'

const TacoFridayApp = ( Component, pageProps: AppProps): JSX.Element => 
  
  return <Component ...pageProps />


export default TacoFridayApp

【讨论】:

【参考方案3】:

我认为你很接近。您最初可以使用备用语言设置i18n。然后在为 localstorage 或 localforage 或任何存储加载保存的语言信息后,调用i18nInstance.changeLanguage(lng)

【讨论】:

【参考方案4】:

@firstdoit:

关于自动浏览器语言检测的好答案。但是,您不这么认为吗,让用户同时使用自动和手动配置是一种更好的方法。

例如,如果一个浏览器设置为英文,这对于您根据文档建议的自动方法来说是可以的。如果用户将页面语言从英语更改为法语,这不会影响浏览器语言,因此仅将网站保持为英语,因为配置设置为自动检测浏览器语言。

反过来,我会优先考虑当前页面的语言:

通过参数传递(/george.php?lang=fr 或 /fr_FR/george.php)

这将作为道具传递给我的代码,如下所示

var lang = this.props.lang || this.services.languageDetector.detect() || “恩”;

你怎么看?

【讨论】:

【参考方案5】:

在这件事上浪费了很多时间,但幸运的是 taco_friday 用他的 answer 挽救了我的一天。在这里添加我的两分钱:

我基本上试图将数据从我的 localStorage 加载到 i18-next 中。有一个名为 i18next-localstorage-backend 的插件应该有助于实现这一点,但我没有设法让它运行。

但是在 taco-friday 分享的内容中找到了灵感,我可以相应地调整我的 i18n.ts

import i18n from 'i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
import  initReactI18next  from 'react-i18next'
import BrowserStorageManager from './services/browserStorageManager'
import loadTranslations from './services/loadTranslations'

const service = new BrowserStorageManager()
loadTranslations()

const resources = 
    'de-CH': service.getItem<any>('de-CH')?.value,


i18n.use(LanguageDetector)
    .use(initReactI18next)
    .init(
        debug: false,
        fallbackLng: 'deCH',
        resources,
        interpolation: 
            escapeValue: false, // not needed for react!!
        ,
    ) 

browserStorageManager.ts的内容是:

import logSymbols from 'log-symbols'

class BrowserStorageManager 
    public setItem(key: string, value: any): void 
        localStorage.setItem(key, JSON.stringify( value ))
    

    public getItem<T>(key: string): T | null 
        const data: string | null = localStorage.getItem(key)
        if (data !== null) 
            return JSON.parse(data)
        
        console.log(logSymbols.error, ` $key-key is empty - aborting ...`)
        return null
    


export default BrowserStorageManager

最后,我的 localStorage 中的 resourceBundle 的结构如下:


    value:
        translation:
            key: "value",
            ....
        
    
 

translation 是默认命名空间,因此无需在.init 中定义它

【讨论】:

以上是关于React i18next 和更改语言的正确方法的主要内容,如果未能解决你的问题,请参考以下文章

如何在 React Native 中导入 i18next?

下一个.js。将全球供应商放在哪里?

Typescript next.js + i18n 的正确 getServerSideProps 语法

在 JSON 字符串中反应 i18n 换行符

React项目多语言国际化:react-i18next插件实现——本地数据篇

React-intl 多语言应用程序:更改语言和翻译存储