0

I believe I have searched all parts of the internet for an answer and fixes but none seem to work.

Issue :

  • When building a react app for production that uses i18n as a translation will cause the production build to only display the strings only as a result and not the translated text itself (see picture reference)Example of result in the production build

  • The weird part is that inside localhost when the development server is running it display the translation correctly. (see picture for reference)Wanted result for the production build

  • After building the production build, inside the browser console (using chrome) it displays the following error : Fetch API cannot load file:///Documents/streaming_site/build/static/locales/en/translation.json. URL scheme must be "http" or "https" for CORS request.

After seeing this error, I imediately came to the assumption that it was inside my i18next.js file that was causing the issue. Here is the file :

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';
import XHR from 'i18next-xhr-backend';

// don't want to use this?
// have a look at the Quick start guide 
// for passing in lng and translations on init

const Languages = ['en', 'fr'];

i18n
  .use(XHR)
  // load translation using http -> see /public/locales (i.e. https://github.com/i18next/react-i18next/tree/master/example/react/public/locales)
  // learn more: https://github.com/i18next/i18next-http-backend
  .use(Backend)
  // detect user language
  // learn more: https://github.com/i18next/i18next-browser-languageDetector
  .use(LanguageDetector)
  // pass the i18n instance to react-i18next.
  .use(initReactI18next)
  // init i18next
  // for all options read: https://www.i18next.com/overview/configuration-options
  .init({
    lng : 'en',
    react: { 
      useSuspense: false,
      wait: true
    },
    fallbackLng: 'en',
    debug: false,
    whitelist: Languages,
    interpolation: {
      escapeValue: false, // not needed for react as it escapes by default
    },
    nsSeperator : false,
    keySeperator : false,
    backend:{
      loadPath: () => {

        var cors = require('cors');
        var app = cors();
        
        // check the domain
        const host = window.location.host;
        return (host === 'index.html#' ? '':'') + '/static/locales/{{lng}}/{{ns}}.json';
      },
    }
  });


export default i18n;

Furhtermore inside my index.js file I added these extra fixes to ensure that the app would properly display the translated text on a production build :

i18next.init({// <-- This was added
  interpolation: {escapeValue: false},
});
i18next.init().then(() => // <-- This was added
  ReactDOM.render(
    <React.StrictMode>
    <Suspense fallback={<div>Loading...</div>}>// <-- This was added
      <I18nextProvider i18n={i18next}>// <-- This was added
        <App />
      </I18nextProvider>
    </Suspense>
    </React.StrictMode>,
    document.getElementById('root')
  )
);

Alas, the same error occurs (the one from the third point) after making an npm run build

This leads me to believe that it is impossible without a backend server hosting the translation.json files for en and fr to have them be accessed locally.

My questions is the following: Is it possible to have i18n translation run locally after building the production build without needing a server to host the json files? If yes how would I proceed?

For references I have tried a few fixes from this website such as :

  1. React i18next Backend-Path different in local and production environment

  2. react-i18next doesn't translate

  3. Allow Access-Control-Allow-Origin header using HTML5 fetch API

I've gotten close when I attempted --> res.header('Access-Control-Allow-Origin', "*"); although it comes at the cost of posing some security issue and I don't want that. Although if this is a potential fix, I am willing to try it.

So here I am out of ideas... :/

majinnp
  • 35
  • 6

1 Answers1

0

Looks like there is some misconfig of the i18next service.

First of all, i18next-http-backend & i18next-xhr-backend are solving the same problem, fetching json files.

Remove the second one (i18next-xhr-backend) since it is deprecated in favor of i18next-http-backend.

Change the backend.loadPath to be a string, your code doesn't make sense.

it should look like:

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import Backend from 'i18next-http-backend';
import LanguageDetector from 'i18next-browser-languagedetector';

// don't want to use this?
// have a look at the Quick start guide
// for passing in lng and translations on init

const Languages = ['en', 'fr'];

i18n
  .use(Backend)
  // detect user language
  // learn more: https://github.com/i18next/i18next-browser-languageDetector
  .use(LanguageDetector)
  // pass the i18n instance to react-i18next.
  .use(initReactI18next)
  // init i18next
  // for all options read: https://www.i18next.com/overview/configuration-options
  .init({
    lng: 'en',
    react: {
      useSuspense: false,
      wait: true,
    },
    fallbackLng: 'en',
    debug: false,
    whitelist: Languages,
    interpolation: {
      escapeValue: false, // not needed for react as it escapes by default
    },
    nsSeperator: false,
    keySeperator: false,
    backend: {
      loadPath: '/locales/{{lng}}/{{ns}}.json',
    },
  });

export default i18n;

felixmosh
  • 32,615
  • 9
  • 69
  • 88
  • Thank you for your fix, but when I attempted to create a new prod build the debug console in Chrome displays the same issue : `Fetch API cannot load file:///Users/user/Documents/streaming_site/build/static/locales/en/translation.json. URL scheme must be "http" or "https" for CORS request.` https://imgur.com/a/D3CFiBZ So the app finds the json with no problem but chrome refuses to load it due to this error. I also tried other browsers such as Safari and the same issue occurs. – majinnp Dec 24 '20 at 16:03
  • How do you lunch the app? – felixmosh Dec 24 '20 at 16:05
  • I just drag & drop the index.html into Chrome or do `open with > Chrome` – majinnp Dec 24 '20 at 16:11
  • So this is your issue, since you are opening the index.html file as `file://` protocol. This is not allows you to make Ajax requests. You need to serve the html file using some server, (like webpack-dev-server serves your file at dev time) – felixmosh Dec 24 '20 at 16:30