react-i18next:如何同步浏览器和 Express LanguageDetector?
react-i18next: How to sync Browser and Express LanguageDetector?
在我的服务器路由中,我做了这样的事情(注意:i18next-express-middleware
已经在管道中,服务器端渲染工作正常):
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))
}
所以我尝试 return 字段的正确版本,基于用户选择的语言。
但是无论在浏览器端选择什么语言,在服务器端总是设置为默认的,EN。
有没有办法让服务器端LanguageDetector
知道浏览器端当前的语言?
这是我的客户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
这是我的服务器 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
github 上的猜题 https://github.com/i18next/react-i18next/issues/471 给出了答案...
而且没有 Whosebug...我不会再在这里写完整的回复 ;)
将代码粘贴到此处,它将/应该可以工作...但是阅读上面的问题 - 缺少一块 - 创建一个新实例(在请求中的实例旁边)并在那里设置语言 -> 导致不同步如果依靠检测而不正确设置 initialLanguage...
实际上问题不是我的 i18n init
配置。
在进行 SSR 时,我们必须记住我们有两个不同的 i18next
实例,一个 运行 在服务器上,另一个在浏览器中。
在您在服务器上创建的实例上,将根据您的配置检测当前语言。然后你将在服务器上渲染,像这样:
<I18nextProvider i18n={i18n_}>
<StaticRouter location={req.url} context={{}}>
<Route component={App} />
</StaticRouter>
</I18nextProvider>
但是当您的浏览器应用程序启动时,它将使用从其自己的配置中检测到的任何语言作为当前语言。
所以要做的第一件事就是使用来自服务器的 i18n
信息初始化浏览器应用程序。因此,在构建标记服务器端时,只需在 window 对象上创建两个属性来保存 initialStore
和 initialLanguage
(注意:我使用 hbs
):
window.__initialI18nStore__ = {{json initialI18nStore}}
window.__initialLanguage__ = {{json initialLanguage}}
然后在浏览器应用程序上,您将呈现如下内容:
<I18nextProvider
i18n={i18n}
initialI18nStore={window.__initialI18nStore__}
initialLanguage={window.__initialLanguage__}
>
<BrowserRouter>
<Route component={App} />
</BrowserRouter>
</I18nextProvider>
因此浏览器应用程序将使用与服务器相同的语言和存储。
但是你还没有完成。使用相同的语言初始化浏览器应用程序不会 link i18next 的两个实例,如果您更改浏览器上的语言,然后按刷新,您仍然会使用以前的语言,来自服务器,因为服务器i18next 实例不知道您所做的更改。
解决所有这些问题的是 caches
设置,用于 LanguageDetector
。您必须在配置、浏览器和服务器上指定它:
detection: {
caches: [..., 'cookie', ...]
}
例如,当您使用 cookie 时,每次浏览器更改语言时,cookie 都会更新,然后在服务器端,语言检测器的行为会发生变化,它会首先尝试从 cookie 中获取当前语言,并将其设置为 req.i18n.language
。所以这两个实例现在将通过该 cookie 同步。
也许您应该阅读 react-i18next
github 存储库中的示例 razzle-ssr,并查看这些 link 以了解有关 LanguageDetector 选项的更多信息:
for browser and for node
在我的服务器路由中,我做了这样的事情(注意:i18next-express-middleware
已经在管道中,服务器端渲染工作正常):
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))
}
所以我尝试 return 字段的正确版本,基于用户选择的语言。
但是无论在浏览器端选择什么语言,在服务器端总是设置为默认的,EN。
有没有办法让服务器端LanguageDetector
知道浏览器端当前的语言?
这是我的客户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
这是我的服务器 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
github 上的猜题 https://github.com/i18next/react-i18next/issues/471 给出了答案...
而且没有 Whosebug...我不会再在这里写完整的回复 ;)
将代码粘贴到此处,它将/应该可以工作...但是阅读上面的问题 - 缺少一块 - 创建一个新实例(在请求中的实例旁边)并在那里设置语言 -> 导致不同步如果依靠检测而不正确设置 initialLanguage...
实际上问题不是我的 i18n init
配置。
在进行 SSR 时,我们必须记住我们有两个不同的 i18next
实例,一个 运行 在服务器上,另一个在浏览器中。
在您在服务器上创建的实例上,将根据您的配置检测当前语言。然后你将在服务器上渲染,像这样:
<I18nextProvider i18n={i18n_}>
<StaticRouter location={req.url} context={{}}>
<Route component={App} />
</StaticRouter>
</I18nextProvider>
但是当您的浏览器应用程序启动时,它将使用从其自己的配置中检测到的任何语言作为当前语言。
所以要做的第一件事就是使用来自服务器的 i18n
信息初始化浏览器应用程序。因此,在构建标记服务器端时,只需在 window 对象上创建两个属性来保存 initialStore
和 initialLanguage
(注意:我使用 hbs
):
window.__initialI18nStore__ = {{json initialI18nStore}}
window.__initialLanguage__ = {{json initialLanguage}}
然后在浏览器应用程序上,您将呈现如下内容:
<I18nextProvider
i18n={i18n}
initialI18nStore={window.__initialI18nStore__}
initialLanguage={window.__initialLanguage__}
>
<BrowserRouter>
<Route component={App} />
</BrowserRouter>
</I18nextProvider>
因此浏览器应用程序将使用与服务器相同的语言和存储。
但是你还没有完成。使用相同的语言初始化浏览器应用程序不会 link i18next 的两个实例,如果您更改浏览器上的语言,然后按刷新,您仍然会使用以前的语言,来自服务器,因为服务器i18next 实例不知道您所做的更改。
解决所有这些问题的是 caches
设置,用于 LanguageDetector
。您必须在配置、浏览器和服务器上指定它:
detection: {
caches: [..., 'cookie', ...]
}
例如,当您使用 cookie 时,每次浏览器更改语言时,cookie 都会更新,然后在服务器端,语言检测器的行为会发生变化,它会首先尝试从 cookie 中获取当前语言,并将其设置为 req.i18n.language
。所以这两个实例现在将通过该 cookie 同步。
也许您应该阅读 react-i18next
github 存储库中的示例 razzle-ssr,并查看这些 link 以了解有关 LanguageDetector 选项的更多信息:
for browser and for node