简体   繁体   English

react-i18next:如何同步浏览器和Express LanguageDetector?

[英]react-i18next: How to sync Browser and Express LanguageDetector?

In my server's routes, I do something like this (Note: The i18next-express-middleware is already in the pipeline, and Server Side Rendering is working good): 在服务器的路由中,我这样做是这样的(注意: i18next-express-middleware已经在管道中,并且Server Side Rendering运行良好):

export default function (req, res) {
  const lng = req.language.toUpperCase()

  console.log(lng) // Always display [EN]

  MyModel
    .findOne(query, { fieldEN: 1, fieldFR: 1 })
    .exec()
    .then(res => reply(res[`field${lng}`]))
    .catch(err => handle(err))
}

So I try to return the right version of the field, base on the USER's selected language. 因此,我尝试根据用户选择的语言返回正确的字段版本。

But no matter what language is selected on the browser side, on the server side it is always set to the default, EN. 但是,无论在浏览器端选择哪种语言,在服务器端始终将其设置为默认值EN。

Is there a way to let the server side LanguageDetector know about the current language on the browser side ? 有没有办法让服务器端LanguageDetector知道浏览器端的当前语言?

This is my Client i18n init : 这是我的客户i18n init

import i18n from 'i18next'
import Backend from 'i18next-xhr-backend'
import LanguageDetector from 'i18next-browser-languagedetector'

i18n
  .use(Backend)
  .use(LanguageDetector)
  .init({
    whitelist: ['en', 'fr'],
    fallbackLng: 'en',
    preload: ['en', 'fr'],

    // debug: true,

    interpolation: {
      escapeValue: false
    },

    ns: ['home', 'channel', 'common'],
    defaultNS: 'home',

    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json'
    },

    react: {
      wait: true,
      bindI18n: 'languageChanged loaded',
      bindStore: 'added removed',
      nsMode: 'default'
    }
  })

export default i18n

And this is my server i18n init : 这是我的服务器i18n init

import i18n from 'i18next'
import Backend from 'i18next-node-fs-backend'
import { LanguageDetector } from 'i18next-express-middleware'

i18n
  .use(Backend)
  .use(LanguageDetector)
  .init({
    whitelist: ['en', 'fr'],
    fallbackLng: 'en',
    preload: ['en', 'fr'],

    // debug: true,

    interpolation: {
      escapeValue: false
    },

    ns: ['home', 'channel', 'common'],
    defaultNS: 'home',

    backend: {
      loadPath: `${__dirname}/public/locales/{{lng}}/{{ns}}.json`,
      jsonIndent: 2
    }
  })

export default i18n

Guess issue on github https://github.com/i18next/react-i18next/issues/471 gives the answer... github上的猜测问题https://github.com/i18next/react-i18next/issues/471给出了答案...

And no stackoverflow...i won't write the full reply here again ;) 而且没有stackoverflow ...我不会在这里再次写完整的答复;)

With code pasted here it will / should work...but reading above issue - there is a missing piece - creating a new instance (beside the one getting in req) and setting the language there -> leads to desync if relying on detection and not setting initialLanguage right... 将代码粘贴到这里,它将/应该工作...但是阅读上面的问题-缺少一个片段-创建一个新实例(除了进入req的那个实例)并在那里设置语言->如果依赖于检测并导致异步没有正确设置initialLanguage ...

In fact the issue was not my i18n init config. 实际上,问题不是我的i18n init配置。

When doing SSR, we must keep in mind that we have two distinct instances of i18next , one running on the server, and the other in the browser. 在执行SSR时,必须记住,我们有两个不同的i18next实例,一个在服务器上运行,另一个在浏览器中运行。

On the instance that you create on the server, the current language will be detected base on your config. 在您在服务器上创建的实例上,将根据您的配置检测到当前语言。 Then you will render on the server, with something like this: 然后,您将在服务器上呈现以下内容:

<I18nextProvider i18n={i18n_}>
    <StaticRouter location={req.url} context={{}}>
        <Route component={App} />
    </StaticRouter>
</I18nextProvider>

But when your browser app will launch, it will use whatever it will detect as the current language from its own config. 但是,当您的浏览器应用启动时,它将使用从其自己的配置中检测为当前语言的任何内容。

So the first thing to do, is to initialize the browser app with i18n info from the server. 因此,第一件事就是使用来自服务器的i18n信息初始化浏览器应用。 So when building the markup server side, just create two properties on window object to hold initialStore and initialLanguage (Note: I use hbs ): 因此,在构建标记服务器端时,只需在window对象上创建两个属性来保存initialStoreinitialLanguage (注意:我使用hbs ):

window.__initialI18nStore__ = {{json initialI18nStore}}
window.__initialLanguage__ = {{json initialLanguage}}

Then on the browser app, you will render with something like this: 然后在浏览器应用程序上,您将使用以下内容进行渲染:

<I18nextProvider
    i18n={i18n}
    initialI18nStore={window.__initialI18nStore__}
    initialLanguage={window.__initialLanguage__}
  >
      <BrowserRouter>
          <Route component={App} />
      </BrowserRouter>
</I18nextProvider>

So the browser app will use the same language and store from the server. 因此,浏览器应用程序将使用相同的语言并从服务器存储。

But you are not done yet. 但是您还没有完成。 Initializing the browser app with the same language don't link both instances of i18next, if you change the language on the browser, and press refresh, you will still have the previous language, coming from the server, because the server instance of i18next is not aware of the change you did. 使用相同的语言初始化浏览器应用程序不会链接i18next的两个实例,如果您在浏览器上更改语言,然后按刷新,您仍将使用来自服务器的先前语言,因为i18next的服务器实例是不知道您所做的更改。

The thing that fix all this is the caches setting, for the LanguageDetector . 解决所有这些问题的方法是LanguageDetectorcaches设置。 You have to specify it on both config, browser and server: 您必须在配置,浏览器和服务器上都指定它:

detection: {
  caches: [..., 'cookie', ...]
}

When you use the cookie for example, then each time the browser change the language, the cookie will be updated, and then on the server side, the behavior of the Language detector will be altered, it will first try to get the current language from the cookie, and set it as req.i18n.language . 例如,当您使用cookie时,每次浏览器更改语言时,cookie都会更新,然后在服务器端,语言检测器的行为将被更改,它将首先尝试从中获取当前语言。 cookie,并将其设置为req.i18n.language So both instance will now be in sync through that cookie. 因此,这两个实例现在将通过该Cookie进行同步。

May be you should read the example razzle-ssr on react-i18next github repo, and check these links to learn more about LanguageDetector options: for browser and for node 可能是您应该阅读react-i18next github react-i18next库上的示例razzle-ssr ,并检查以下链接以了解有关LanguageDetector选项的更多信息: 对于浏览器节点

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM