0

I have a small app that gives support to 30+ languages. I used react-intl to achieve my task. In react-intl I got to import every locale where every local file is around 7-8kbs, whereas I want to reduce these unnecessary imports and want to import only one file

app.js

import {IntlProvider, addLocaleData} from 'react-intl'
import ca from 'react-intl/locale-data/ca'
import cs from 'react-intl/locale-data/cs'
...
import hu from 'react-intl/locale-data/hu'
import id from 'react-intl/locale-data/id'
import enMessages from '../assets/translations/en.json'

Translations.getLocale('fr').then(function(localeData){
  addLocaleData(localeData);
  console.log("localeData");
  console.log(localeData);  //Code instead of array of objects
 }, function(status) {
  alert('Something went wrong.');
});

Now the ca, cs,hu etc. contain array of objects returned from the respective js files.

I tried using XHR but instead of returning the array of objects, I get the code that is written in the .js file. Is there any way I can dynamically import the js file or if I can get the array of objects from the code returned by XMLHttpRequest.

Translations.js

getLocale: function(lang, successHandler, errorHandler){
  var url = 'http://localhost/img/' + lang + '.js';
  return new Promise(function(resolve, reject) {
    var xhr = new XMLHttpRequest();
    xhr.open('get', url, true);
    //xhr.responseType = 'application/javascript';
    xhr.onload = function() {
      var status = xhr.status;
      if (status == 200) {
        resolve(xhr.response);
      } else {
        reject(status);
      }
    };
  xhr.send();
  });
  //return message;
}
iamsaksham
  • 2,879
  • 4
  • 26
  • 50

2 Answers2

0

If I understand you correctly, you retrieve the javascript code, which you want retrieve the output from.

One solution is to use eval, although this is generally not considered very secure. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

You can also make the code an automatically executing function that puts the output on a global variable, and access it from there. Append the content of the js file as a script in the head tag, and make the file contain something like.

myGlobalVar = (function() {
    return {
        key: val
    };
})();

I do not know the format of your translate.js files, but you could also consider putting the translations in a json file, if it's a fixed output for each language. Which I think would be the safest solution.

Robin
  • 1,251
  • 11
  • 18
0

I managed to load the locale files dynamically like this :

Note that my locale string formatting might not be ideal, and ignore the polyfill if you don't plan on supporting old browsers.

import {addLocaleData}  from 'react-intl';

const locale = // get this from browser language

// ensure that the polyfill is loaded before calling this
const isUsingIntlPolyfill = Object.prototype.hasOwnProperty.call(window, 'IntlPolyfill');

// eg: turns 'fr-fr' into 'fr-FR' because intl polyfill locale files are formatted like this
const formatLocale = str => `${str.split('-')[0]}${str.split('-')[1] ? `-${str.split('-')[1].toUpperCase()}` : ''}`;

if (isUsingIntlPolyfill) {
    const polyfill = document.createElement('script');
    // path of the file might differ for your setup
    polyfill.setAttribute('src', `/i18n/polyfill/${formatLocale(locale)}.js`);
    document.getElementsByTagName('head')[0].appendChild(polyfill);
}

const script = document.createElement('script');
// path of the file might differ for your setup
script.setAttribute('src', `/i18n/${locale.split('-')[0]}.js`);
script.onload = () => {
    addLocaleData([...window.ReactIntlLocaleData[locale.substring(0, 2)]]);
    // your locale is loaded, do some more stuff from here ...
};
document.getElementsByTagName('head')[0].appendChild(script);
LoicUV
  • 386
  • 5
  • 9