4

I'm using a react app with react-i18next and loading the translation with i18next-xhr-backend

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

If I run it locally my app is served over http://localhost:3000/

and the translation file is also loading nicely (src is located in public/statuc/locales/ ) http://localhost:3000/static/locales/de/translation.json

I'm now facing the issue that in production the app is not served from root, instead the builded files are served over a subfolder. Because of that I changed my packages.json and added homepage

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

After building the application and deploying it on prod, it still loads correctly, but the translation files are not found.

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

react app files are loaded correctly http://production.tld/static/app/static/js/main*.js

but the translation file is still fetched by http://production.tld/static/locales/de/translation.json which is not available anymore (instead http://production.tld/static/app/static/locales/de/translation.json would be correct)

I could fix it by changing the i18n config

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

then it works in production, but not locally anymore :-/

I'm not sure how to avoid this situation ?

Evil_skunk
  • 3,040
  • 4
  • 30
  • 42

3 Answers3

7

You can pass loadPath as function.

backend: {
  loadPath: () => {
    // check the domain
    const host = window.location.host;
    return (host === 'production.ltd' ? '/static/app':'') + '/static/app/static/locales/{{lng}}/{{ns}}.json';
  },
},
felixmosh
  • 32,615
  • 9
  • 69
  • 88
  • it's working, I'm surprised there is no other solution, because it looks like a workaround? but I will use it now :-) – Evil_skunk Jan 17 '20 at 08:52
  • You can use env variable with different path for dev & prod as well but it requires more work & explanation :) – felixmosh Jan 17 '20 at 09:50
  • Thank you for mentioning the possibility of a function. That might make my life much easier in the future. – Naxos84 Jul 30 '20 at 08:23
2

Another solution would be to work with environment variables. Only the condition would be different and without a function, the idea is like @felixmosh's solution.

An example with create-react-app, here you can use the environment variable 'NODE_ENV' for the condition.

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"],
    },
});

Here the documentation of create-react-app https://create-react-app.dev/docs/adding-custom-environment-variables

mediatrash
  • 21
  • 3
1

Here's a follow-along question that may deserve its own top-level question:

it appears that if your locales directories have dashes in the name (e.g. locales/en-us/translation.json), then things don't work. How are we supposed to get around that? I stumbled on this answer because I thought perhaps I could do something along the lines of:

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

But during my initial testing, that didn't work.

hairbo
  • 3,113
  • 2
  • 27
  • 34