import { ReactNode, Component, createElement } from 'react'; import { IntlMessageFormat } from 'intl-messageformat'; import { globalLocale } from './global-locale'; import { isI18nData } from '@alilc/lowcode-utils'; import { observer } from '../utils'; function generateTryLocales(locale: string) { const tries = [locale, locale.replace('-', '_')]; if (locale === 'zh-TW' || locale === 'en-US') { tries.push('zh-CN'); tries.push('zh_CN'); } else { tries.push('en-US'); tries.push('en_US'); if (locale !== 'zh-CN') { tries.push('zh-CN'); tries.push('zh_CN'); } } return tries; } function injectVars(msg: string, params: any, locale: string): string { if (!msg || !params) { return msg; } const formater = new IntlMessageFormat(msg, locale); return formater.format(params as any) as string; /* return template.replace(/({\w+})/g, (_, $1) => { const key = (/\d+/.exec($1) || [])[0] as any; if (key && params[key] != null) { return params[key]; } return $1; }); */ } export function intl(data: any, params?: object): ReactNode { if (!isI18nData(data)) { return data; } if (data.intl) { return data.intl; } const locale = globalLocale.getLocale(); const tries = generateTryLocales(locale); let msg: string | undefined; for (const lan of tries) { msg = data[lan]; if (msg != null) { break; } } if (msg == null) { return `##intl@${locale}##`; } return injectVars(msg, params, locale); } export function shallowIntl(data: any): any { if (!data || typeof data !== 'object') { return data; } const maps: any = {}; Object.keys(data).forEach(key => { maps[key] = intl(data[key]); }); return maps; } export function intlNode(data: any, params?: object): ReactNode { if (isI18nData(data)) { if (data.intlNode) { return data.intlNode; } return createElement(IntlElement, { data, params }); } return data; } @observer class IntlElement extends Component<{ data: any; params?: object }> { render() { const { data, params } = this.props; return intl(data, params); } } export function createIntl( instance: string | object, ): { intlNode(id: string, params?: object): ReactNode; intl(id: string, params?: object): string; getLocale(): string; setLocale(locale: string): void; } { // TODO: make reactive const data = (() => { const locale = globalLocale.getLocale(); if (typeof instance === 'string') { if ((window as any)[instance]) { return (window as any)[instance][locale] || {}; } const key = `${instance}_${locale.toLocaleLowerCase()}`; return (window as any)[key] || {}; } if (instance && typeof instance === 'object') { return (instance as any)[locale] || {}; } return {}; })(); function intl(key: string, params?: object): string { // TODO: tries lost language const str = data[key]; if (str == null) { return `##intl@${key}##`; } return injectVars(str, params, globalLocale.getLocale()); } @observer class IntlElement extends Component<{ id: string; params?: object }> { render() { const { id, params } = this.props; return intl(id, params); } } return { intlNode(id: string, params?: object) { return createElement(IntlElement, { id, params }); }, intl, getLocale() { return globalLocale.getLocale(); }, setLocale(locale: string) { globalLocale.setLocale(locale); }, }; } export { globalLocale };