import { IntlShape, createIntl, createIntlCache } from 'react-intl'; import captcha from 'app/services/captcha'; import locales from 'app/i18n'; import intlPolyfill from './intlPolyfill'; export const SUPPORTED_LANGUAGES = Object.keys(locales); export const DEFAULT_LANGUAGE = 'en'; function getBrowserPreferredLanguages(): string[] { return ([] as string[]).concat(navigator['languages'] || []).concat(navigator['language'] || []); } function detectLanguage(userLanguages: string[], availableLanguages: string[], defaultLanguage: string): string { return ( userLanguages .map((lang) => (lang.split('-').shift() || '').toLowerCase()) .find((lang) => availableLanguages.indexOf(lang) !== -1) || defaultLanguage ); } const cache = createIntlCache(); let intl: IntlShape; class I18N { detectLanguage(lang: string = ''): string { return detectLanguage( [lang].concat(getBrowserPreferredLanguages()).filter((item) => !!item), SUPPORTED_LANGUAGES, DEFAULT_LANGUAGE, ); } getIntl(): IntlShape { if (!intl) { intl = createIntl( { locale: 'en', messages: {}, }, cache, ); } return intl; } async changeLocale(locale: string = DEFAULT_LANGUAGE): Promise { const { messages } = await this.require(locale); captcha.setLang(locale); intl = createIntl( { locale, messages, }, cache, ); return intl; } async ensureIntl() { await intlPolyfill('en'); } async require(locale: string): Promise<{ locale: string; messages: Record; }> { try { const [{ default: messages }] = await Promise.all([ import(/* webpackChunkName: "locale-[request]" */ `app/i18n/${locale}.json`), intlPolyfill(locale), ]); return { locale, messages, }; } catch (err) { if (process.env.NODE_ENV !== 'production') { if (err.message === "Cannot find module './en.json'") { console.warn( [ "Locales module for the source language isn't exists.", 'You may generate this file by running yarn i18n:extract command.', 'Until then, defaultMessages will be used for displaying on the site.', ].join(' '), ); } else { console.error(err); } return { locale, messages: {} }; } throw err; } } } export default new I18N();