React i18next 后端路径在本地和生产环境中不同

React i18next Backend-Path different in local and production environment

我正在使用带有 react-i18next 的 React 应用程序并使用 i18next-xhr-backend

加载翻译
i18n
  .use(Backend) 
  .use(initReactI18next) // passes i18n down to react-i18next
  .init({
    lng: "de",
    backend: {
      loadPath: '/static/locales/{{lng}}/{{ns}}.json'
    }        
  });

如果我 运行 在本地我的应用程序在 http://localhost:3000/

上运行

并且翻译文件也加载得很好(src 位于 public/statuc/locales/http://localhost:3000/static/locales/de/translation.json

我现在面临的问题是,在生产环境中,应用程序不是从根目录提供的,而是通过子文件夹提供构建的文件。因此,我更改了 packages.json 并添加了 homepage

{
  "name": "myapp",
  "version": "0.1.0",
  "homepage": "/static/app/",
  ...
}

构建应用程序并将其部署到 prod 后,它仍然可以正确加载,但找不到翻译文件。

http://production.tld/static/app/index.html

react 应用程序文件已正确加载 http://production.tld/static/app/static/js/main*.js

但翻译文件仍由 http://production.tld/static/locales/de/translation.json which is not available anymore (instead http://production.tld/static/app/static/locales/de/translation.json 提取是正确的)

我可以通过更改 i18n 配置来修复它

 backend: {
     loadPath: '/static/app/static(locales/{{lng}}/{{ns}}.json'
 }  

然后它可以在生产中工作,但不再在本地工作了:-/

我不确定如何避免这种情况?

您可以将 loadPath 作为 函数 传递。

backend: {
  loadPath: () => {
    // check the domain
    const host = window.location.host;
    return (host === 'production.ltd' ? '/static/app':'') + '/static/app/static/locales/{{lng}}/{{ns}}.json';
  },
},

另一个解决方案是使用环境变量。只有条件会有所不同并且没有功能,这个想法就像@felixmosh 的解决方案。

create-react-app为例,这里可以使用环境变量'NODE_ENV'作为条件。

i18n.use(XHR)
.use(initReactI18next)
.init({
    backend: {
        loadPath:
            process.env.NODE_ENV !== "production"
                ? `./locales/{{lng}}/{{ns}}.json`
                : ` /static/app/static/locales/{{lng}}/{{ns}}.json`,
    },
    lng: "de",
    fallbackLng: "de",
    load: "languageOnly",
    debug: true,
    react: {
        transSupportBasicHtmlNodes: true,
        transKeepBasicHtmlNodesFor: ["br", "strong", "i", "sub", "sup", "li"],
    },
});

这里是create-react-app的文档 https://create-react-app.dev/docs/adding-custom-environment-variables

下面是一个后续问题,可能值得单独提出一个顶级问题:

看来,如果您的区域设置目录的名称中有破折号(例如 locales/en-us/translation.json),那么事情就不会起作用。我们应该如何解决这个问题?我偶然发现了这个答案,因为我想也许我可以按照以下方式做一些事情:

loadPath: (lng, ns) => { return `/locales/{{lng.replace(/-/g,'')/{{ns}}.json` }

但在我最初的测试中,这没有用。