4

I have an 'external' intl provider because I have to handle some labels outside react components. I am trying to dynamically load the locales without using require statements and I am having a issue I am not sure why it's happening. So, the following code works:

//intlProvider.js
import { IntlProvider, addLocaleData } from 'react-intl';
import Locale from '../../../../utils/locale';

const locale = Locale.getLocale();
addLocaleData(require(`react-intl/locale-data/${locale}`));
const messages = Locale.getMessages('prot');
const intlProvider = new IntlProvider({ locale, messages });
const { intl } = intlProvider.getChildContext();

export default intl;

then I read the intl in a sharedMessages.js file:

import { defineMessages } from 'react-intl';
import intl from '../components/i18n/Intl';

const messages = defineMessages({
  interest: {
    id: 'sharedMessages.rate.label',
    defaultMessage: 'Interest',
  },
  bank: {
    id: 'sharedMessages.bank.label',
    defaultMessage: 'Bank',
  },
});
function prepareSharedMessages() {
  const msgsObj = {};
  Object.keys(messages).forEach(item => {
    msgsObj[item] = intl.formatMessage(messages[item]);
  });
  return msgsObj;
}
const sharedMessages = prepareSharedMessages();

export default sharedMessages;

The above code works fine, but since I want to get rid of the require statement in this line (as dynamic imports increase the bundle a lot):

addLocaleData(require(`react-intl/locale-data/${locale}`));

I tryed to replace it for:

(async localeCode => {
  const localeData = await import(`react-intl/locale-data/${localeCode}`);
  addLocaleData(localeData.default);
})(locale);

Expected behavior I'd expect the locale to be loaded properly, but apparently the application is trying to get it before it should. Since I am using async/await, I'd expect it to be set before the rest of the application tries to use it. (If it was inside react components, I could use componentDidMount to trigger the locale, but how can I achieve this behavior for non react components?)

Current behavior After replacing the require for the import statement above mentioned, I am getting the react-intl warning:

[React Intl] Missing locale data for locale: "de". Using default locale: "en" as fallback.

My Environment:

  • react-intl 2.7.0
  • react 16.0.0
  • node 9.10.0

OS: macOS Mojave 10.14

Browser Version: Chrome 71.0.3578.98 (Official Build) (64-bit)

sergioviniciuss
  • 4,596
  • 3
  • 36
  • 50
  • not sure if `import` works same as `require` for dynamic module loading .... you might need some boilerplate ... maybe something like this https://gist.githubusercontent.com/WebReflection/22bed7942d1da36dc6731c45fd792cc5/raw/8f715aafbd46459be4931a0aae61ac683d88fbb0/imports.js – Anirudh Mangalvedhekar Dec 27 '18 at 14:41
  • 1
    It doesn’t because import returns a promise and this is why I am using async/await . This was supposed to be there already, but apparently it is not. – sergioviniciuss Dec 27 '18 at 14:59
  • As far as I am aware, require will always load first, any async/await will load second, by that time you're out of luck and this is the reason why you're getting the error message. You keep mentioning non-react components and achieving the same behavior, can you perhaps elaborate as to why you're trying to modify a react component to be used by something that isn't react? – kowie le roux Dec 27 '18 at 18:53
  • This is built this way to allow the application to have i18n in javascript files that are not importing react. So this requires the react-intl imperative api to be used, and this file is, at the end, exporting the intl. this intl is later imported in a messages file which is the sharedMessages.js described in the question. This is one of my requirements (because the react components are part of an external library and used by different applications, that can have different translations, so you can’t attach them to the components. Instead, I generate them before and then I pass just the labels. – sergioviniciuss Dec 28 '18 at 00:33
  • "*Since I am using async/await, I'd expect it to be set before the rest of the application tries to use it.*" - only the code inside the `async function` will wait, so `addLocaleData` isn't called before the `import` is done. But the code after your IEFE, and the whole `intlProvider.js` module, will not wait for anything. – Bergi Dec 28 '18 at 11:21
  • I realised that @Bergi. After spending a lot of time on it, I realised that the issue is that I am trying to use async code for sync code... basically I need to set the addLocaleData async, but it has to happen before the rest of the application proceeds. I tried to isolate it as another module once if I exports are sync, but I still couldnt get it to work. – sergioviniciuss Dec 28 '18 at 11:25
  • I would recommend to export a promise for the `intl` (created as the result of your async IIFE invocation), then in your main module that imports the `intlProvider.js` wait for the promise before calling your main function – Bergi Dec 28 '18 at 12:00

0 Answers0