import { MissingMessageHandler } from './MissingMessageHandler'; import _ from 'lodash'; import { I18nProvider, Locale, TranslationMessages } from 'ra-core'; import { default as polyglotI18nProvider } from 'ra-i18n-polyglot'; type IMessage = { id: string; code: string; lang: string; text: string; }; type IDictionary = { [key: string]: string }; type ITranslations = { [key: string]: IDictionary }; type ICreateI18nProviderData = { apiUrl: string; defaultLocale: string; allowMissing?: boolean; createMissing?: boolean; customProvider?: Promise; }; type ICreateJsonI18nProviderData = { path: string; locales: Locale[]; defaultLocale: string; }; type IPolyglotOptions = { phrases?: IDictionary; locale?: string; allowMissing?: boolean; onMissingKey?: (key: string, options: IPolyglotOptions, locale: string) => string; interpolation?: { prefix?: string; suffix?: string; }; }; function createI18nProvider(data: ICreateI18nProviderData): Promise { const { apiUrl, defaultLocale, allowMissing = false, createMissing = false } = data; const defaultLanguages: Array = [{ locale: defaultLocale, name: defaultLocale }]; const headers = new Headers({ Accept: 'application/json', 'Content-Type': 'application/json' }); const missingMessageHandler = new MissingMessageHandler({ apiUrl: apiUrl }); function getLanguages(): Promise { return fetch(`${apiUrl}/i18n/languages`, { headers: headers, method: 'get' }) .then((response) => response.json()) .catch(() => { return Promise.resolve(defaultLanguages); }); } function getMessages(): Promise { return fetch(`${apiUrl}/i18n/messages`, { headers: headers, method: 'get' }) .then((response) => response.json()) .then((response: Array): ITranslations => { return response.reduce( (messages: ITranslations, message: IMessage) => ({ ...messages, [message.lang]: { ...(messages[message.lang] || {}), [message.code]: message.text } }), {} ); }); } function onMissingKey(key: string, _options: IPolyglotOptions, locale: string): string { if (!allowMissing) { //eslint-disable-next-line console.error(`Warning: Missing translation for key: "${key}"`); } if (createMissing) { if (!_.isString(key)) { //eslint-disable-next-line console.error('[createI18nProvider] onMissingKey: provided key is not a string'); } else if (key.match(new RegExp(/[\s[\]]/, 'gm'))) { //eslint-disable-next-line console.error(`[createI18nProvider] onMissingKey: illegal character in key ${key}`); } else { missingMessageHandler.handleMessage({ code: key, lang: locale }); } } return key; } return Promise.all([getLanguages(), getMessages()]).then((responses) => { const [languages, messages] = responses; function getMessages(locale: string): TranslationMessages { //@ts-ignore return _.get(messages, locale, {}); } return polyglotI18nProvider(getMessages, defaultLocale, languages, { allowMissing: allowMissing || createMissing, onMissingKey: onMissingKey }); }); } /** * Create an I18nProvider that fetches translations from JSON files. * * @param data {ICreateI18nProviderData} - The data to create the I18nProvider * @returns {Promise} - The I18nProvider */ function createJsonI18nProvider(data: ICreateJsonI18nProviderData): Promise { const { locales, defaultLocale, path } = data; const headers = new Headers({ Accept: 'application/json', 'Content-Type': 'application/json' }); function getMessages(locale: Locale): Promise { return fetch(`${path}/${locale.locale}.json`, { headers: headers, method: 'get' }) .then((response) => response.json()) .then((response: Array): ITranslations => { return response.reduce( (messages: ITranslations, message: IMessage) => ({ ...messages, [message.lang]: { ...(messages[message.lang] || {}), [message.code]: message.text } }), {} ); }); } return Promise.all(locales.map(getMessages)) .then((responses: ITranslations[]) => _.reduce( responses, (acc, messages) => ({ ...acc, ...messages } as ITranslations), {} ) ) .then((messages) => { function getMessages(locale: string): TranslationMessages { return _.get(messages, locale, {}) as TranslationMessages; } return polyglotI18nProvider(getMessages, defaultLocale, locales, { allowMissing: true }); }); } export type { ICreateI18nProviderData }; export { createI18nProvider, createJsonI18nProvider };