Match-id-417ad546618f89732bb60368a0b25e5f7f547b20

This commit is contained in:
* 2023-09-19 16:45:20 +08:00
commit 9fbaf33e17
21 changed files with 161 additions and 145 deletions

View File

@ -4,7 +4,7 @@
"description": "", "description": "",
"main": "build/intl.umd.js", "main": "build/intl.umd.js",
"type": "commonjs", "type": "commonjs",
"types": "build/@types/index.d.ts", "types": "build/index.d.ts",
"scripts": { "scripts": {
"demo-serve": "webpack serve --mode=development", "demo-serve": "webpack serve --mode=development",
"rollup-build": "rollup --config rollup.config.js", "rollup-build": "rollup --config rollup.config.js",

View File

@ -17,8 +17,9 @@ import EventDispatcher from '../utils/eventListener';
import DateTimeFormatter from "../format/fomatters/DateTimeFormatter"; import DateTimeFormatter from "../format/fomatters/DateTimeFormatter";
import NumberFormatter from "../format/fomatters/NumberFormatter"; import NumberFormatter from "../format/fomatters/NumberFormatter";
import { getFormatMessage } from '../format/getFormatMessage'; import { getFormatMessage } from '../format/getFormatMessage';
import { I18nProps, MessageDescriptor, MessageOptions } from '../types/interfaces'; import {I18nCache, I18nProps, MessageDescriptor, MessageOptions} from '../types/interfaces';
import { Locale, Locales, Messages, AllLocaleConfig, AllMessages, LocaleConfig, Error, Events } from '../types/types'; import { Locale, Locales, Messages, AllLocaleConfig, AllMessages, LocaleConfig, Error, Events } from '../types/types';
import creatI18nCache from "../format/cache/cache";
export class I18n extends EventDispatcher<Events> { export class I18n extends EventDispatcher<Events> {
public locale: Locale; public locale: Locale;
@ -26,7 +27,7 @@ export class I18n extends EventDispatcher<Events> {
private readonly _localeConfig: AllLocaleConfig; private readonly _localeConfig: AllLocaleConfig;
private readonly allMessages: AllMessages; private readonly allMessages: AllMessages;
public readonly error?: Error; public readonly error?: Error;
public readonly useMemorize?: boolean; public readonly cache?: I18nCache;
constructor(props: I18nProps) { constructor(props: I18nProps) {
super(); super();
@ -48,6 +49,8 @@ export class I18n extends EventDispatcher<Events> {
this.formatMessage = this.formatMessage.bind(this); this.formatMessage = this.formatMessage.bind(this);
this.formatDate = this.formatDate.bind(this); this.formatDate = this.formatDate.bind(this);
this.formatNumber = this.formatNumber.bind(this); this.formatNumber = this.formatNumber.bind(this);
this.cache = props.cache ?? creatI18nCache();
} }
get messages(): string | Messages | AllMessages { get messages(): string | Messages | AllMessages {
@ -115,18 +118,18 @@ export class I18n extends EventDispatcher<Events> {
formatMessage( formatMessage(
id: MessageDescriptor | string, id: MessageDescriptor | string,
values: Object | undefined = {}, values: Object | undefined = {},
{ message, context, formatOptions, useMemorize}: MessageOptions = {}, { message, context, formatOptions}: MessageOptions = {},
) { ) {
return getFormatMessage(this, id, values, { message, context, formatOptions, useMemorize}); return getFormatMessage(this, id, values, { message, context, formatOptions});
} }
formatDate(value: string | Date, formatOptions?: Intl.DateTimeFormatOptions): string { formatDate(value: string | Date, formatOptions?: Intl.DateTimeFormatOptions): string {
const dateTimeFormatter = new DateTimeFormatter(this.locale || this.locales, formatOptions, this.useMemorize); const dateTimeFormatter = new DateTimeFormatter(this.locale || this.locales, formatOptions, this.cache);
return dateTimeFormatter.dateTimeFormat(value); return dateTimeFormatter.dateTimeFormat(value);
} }
formatNumber(value: number, formatOptions?: Intl.NumberFormatOptions): string { formatNumber(value: number, formatOptions?: Intl.NumberFormatOptions): string {
const numberFormatter = new NumberFormatter(this.locale || this.locales, formatOptions, this.useMemorize); const numberFormatter = new NumberFormatter(this.locale || this.locales, formatOptions, this.cache);
return numberFormatter.numberFormat(value); return numberFormatter.numberFormat(value);
} }
} }

View File

@ -12,8 +12,7 @@
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import Inula, { useRef, useState, useEffect, useMemo, Component } from 'inulajs'; import Inula, { useRef, useState, useEffect, useMemo } from 'inulajs';
import utils from '../../utils/utils';
import { InjectProvider } from './InjectI18n'; import { InjectProvider } from './InjectI18n';
import I18n, { createI18nInstance } from '../I18n'; import I18n, { createI18nInstance } from '../I18n';
import { I18nProviderProps } from '../../types/types'; import { I18nProviderProps } from '../../types/types';

View File

@ -14,6 +14,7 @@
*/ */
import { configProps, I18nCache } from '../types/interfaces'; import { configProps, I18nCache } from '../types/interfaces';
import I18n, { createI18nInstance } from './I18n'; import I18n, { createI18nInstance } from './I18n';
import creatI18nCache from '../format/cache/cache';
/** /**
* createI18n hook函数i8n实例 * createI18n hook函数i8n实例
@ -22,9 +23,9 @@ import I18n, { createI18nInstance } from './I18n';
export const createI18n = (config: configProps, cache?: I18nCache): I18n => { export const createI18n = (config: configProps, cache?: I18nCache): I18n => {
const { locale, defaultLocale, messages } = config; const { locale, defaultLocale, messages } = config;
return createI18nInstance({ return createI18nInstance({
locale: locale || defaultLocale || 'en', locale: locale || defaultLocale || 'zh',
messages: messages, messages: messages,
useMemorize: !!cache, cache: cache ?? creatI18nCache(),
}); });
}; };

View File

@ -16,7 +16,8 @@
import { UNICODE_REG } from '../constants'; import { UNICODE_REG } from '../constants';
import { CompiledMessage, Locale, LocaleConfig, Locales } from '../types/types'; import { CompiledMessage, Locale, LocaleConfig, Locales } from '../types/types';
import generateFormatters from './generateFormatters'; import generateFormatters from './generateFormatters';
import { FormatOptions } from '../types/interfaces'; import {FormatOptions, I18nCache} from '../types/interfaces';
import {createIntlCache} from "../../index";
/** /**
* *
@ -26,14 +27,14 @@ class Translation {
private readonly locale: Locale; private readonly locale: Locale;
private readonly locales: Locales; private readonly locales: Locales;
private readonly localeConfig: Record<string, any>; private readonly localeConfig: Record<string, any>;
private readonly useMemorize?: boolean; private readonly cache: I18nCache;
constructor(compiledMessage, locale, locales, localeConfig, memorize?) { constructor(compiledMessage, locale, locales, localeConfig, cache?) {
this.compiledMessage = compiledMessage; this.compiledMessage = compiledMessage;
this.locale = locale; this.locale = locale;
this.locales = locales; this.locales = locales;
this.localeConfig = localeConfig; this.localeConfig = localeConfig;
this.useMemorize = memorize ?? true; this.cache = cache ?? createIntlCache;
} }
/** /**
@ -47,12 +48,11 @@ class Translation {
values: object, values: object,
formatOptions: FormatOptions, formatOptions: FormatOptions,
localeConfig: LocaleConfig, localeConfig: LocaleConfig,
useMemorize?: boolean
) => { ) => {
const textFormatter = (name: string, type: string, format: any) => { const textFormatter = (name: string, type: string, format: any) => {
const formatters = generateFormatters(locale, locales, localeConfig, formatOptions); const formatters = generateFormatters(locale, locales, localeConfig, formatOptions, this.cache);
const value = values[name]; const value = values[name];
const formatter = formatters[type](value, format, useMemorize); const formatter = formatters[type](value, format);
let message; let message;
if (typeof formatter === 'function') { if (typeof formatter === 'function') {
@ -73,7 +73,6 @@ class Translation {
values, values,
formatOptions, formatOptions,
this.localeConfig, this.localeConfig,
this.useMemorize
); );
// 通过递归方法formatCore进行格式化处理 // 通过递归方法formatCore进行格式化处理
const result = this.formatMessage(this.compiledMessage, textFormatter); const result = this.formatMessage(this.compiledMessage, textFormatter);

View File

@ -22,7 +22,6 @@ function creatI18nCache(): I18nCache {
dateTimeFormat: {}, dateTimeFormat: {},
numberFormat: {}, numberFormat: {},
plurals: {}, plurals: {},
messages: {},
select: {}, select: {},
octothorpe: {}, octothorpe: {},
}; };

View File

@ -16,6 +16,7 @@
import creatI18nCache from '../cache/cache'; import creatI18nCache from '../cache/cache';
import utils from '../../utils/utils'; import utils from '../../utils/utils';
import { DatePool, Locales } from '../../types/types'; import { DatePool, Locales } from '../../types/types';
import {I18nCache} from "../../types/interfaces";
/** /**
* *
@ -23,17 +24,13 @@ import { DatePool, Locales } from '../../types/types';
class DateTimeFormatter { class DateTimeFormatter {
private readonly locales: Locales; private readonly locales: Locales;
private readonly formatOptions: Intl.DateTimeFormatOptions; private readonly formatOptions: Intl.DateTimeFormatOptions;
// 是否进行存储
private readonly useMemorize: boolean;
// 创建一个缓存对象用于存储DateTimeFormat的对象 // 创建一个缓存对象用于存储DateTimeFormat的对象
private cache = creatI18nCache().dateTimeFormat; private readonly cache?: I18nCache;
constructor(locales: Locales, formatOptions?: Intl.DateTimeFormatOptions, useMemorize?: boolean) { constructor(locales: Locales, formatOptions?: Intl.DateTimeFormatOptions, cache?: I18nCache) {
this.locales = locales; this.locales = locales;
this.formatOptions = formatOptions ?? {}; this.formatOptions = formatOptions ?? {};
this.useMemorize = useMemorize ?? true; this.cache = cache ?? creatI18nCache();
} }
dateTimeFormat(value: DatePool, formatOptions?: Intl.DateTimeFormatOptions): string { dateTimeFormat(value: DatePool, formatOptions?: Intl.DateTimeFormatOptions): string {
@ -45,16 +42,16 @@ class DateTimeFormatter {
} }
// 如果启用了记忆化且已经有对应的数字格式化器缓存,则直接返回缓存中的格式化结果。否则创建新的格式化数据,并进行缓存 // 如果启用了记忆化且已经有对应的数字格式化器缓存,则直接返回缓存中的格式化结果。否则创建新的格式化数据,并进行缓存
if (this.useMemorize) { if (this.cache?.dateTimeFormat) {
// 造缓存的keykey包含区域设置和日期时间格式选项 // 造缓存的keykey包含区域设置和日期时间格式选项
const cacheKey = utils.generateKey<Intl.DateTimeFormatOptions>(this.locales, options); const cacheKey = utils.generateKey<Intl.DateTimeFormatOptions>(this.locales, options);
if (this.cache[cacheKey]) { if (this.cache.dateTimeFormat[cacheKey]) {
return this.cache[cacheKey].format(value); return this.cache.dateTimeFormat[cacheKey].format(value);
} }
// 查询缓存中的key 若无key则创建新key // 查询缓存中的key 若无key则创建新key
this.cache[cacheKey] = formatter; this.cache.dateTimeFormat[cacheKey] = formatter;
return formatter.format(value); return formatter.format(value);
} }

View File

@ -16,6 +16,7 @@
import creatI18nCache from '../cache/cache'; import creatI18nCache from '../cache/cache';
import { Locales } from '../../types/types'; import { Locales } from '../../types/types';
import utils from '../../utils/utils'; import utils from '../../utils/utils';
import {I18nCache} from "../../types/interfaces";
/** /**
* *
@ -23,13 +24,12 @@ import utils from '../../utils/utils';
class NumberFormatter { class NumberFormatter {
private readonly locales: Locales; private readonly locales: Locales;
private readonly formatOption?: Intl.NumberFormatOptions; private readonly formatOption?: Intl.NumberFormatOptions;
private readonly useMemorize?: boolean; private cache?: I18nCache; // 创建一个缓存对象,用于缓存已经创建的数字格式化器
private cache = creatI18nCache().numberFormat; // 创建一个缓存对象,用于缓存已经创建的数字格式化器
constructor(locales: Locales, formatOption?: Intl.NumberFormatOptions, useMemorize?: boolean) { constructor(locales: Locales, formatOption?: Intl.NumberFormatOptions, cache?: I18nCache) {
this.locales = locales; this.locales = locales;
this.formatOption = formatOption ?? {}; this.formatOption = formatOption ?? {};
this.useMemorize = useMemorize ?? true; this.cache = cache ?? creatI18nCache();
} }
numberFormat(value: number, formatOption?: Intl.NumberFormatOptions): string { numberFormat(value: number, formatOption?: Intl.NumberFormatOptions): string {
@ -37,15 +37,15 @@ class NumberFormatter {
const formatter = new Intl.NumberFormat(this.locales, options); const formatter = new Intl.NumberFormat(this.locales, options);
// 如果启用了记忆化且已经有对应的数字格式化器缓存,则直接返回缓存中的格式化结果。否则创建新的格式化数据,并进行缓存 // 如果启用了记忆化且已经有对应的数字格式化器缓存,则直接返回缓存中的格式化结果。否则创建新的格式化数据,并进行缓存
if (this.useMemorize) { if (this.cache?.numberFormat) {
// 造缓存的keykey包含区域设置数字格式选项 // 造缓存的keykey包含区域设置数字格式选项
const cacheKey = utils.generateKey<Intl.NumberFormatOptions>(this.locales, options); const cacheKey = utils.generateKey<Intl.NumberFormatOptions>(this.locales, options);
if (this.cache[cacheKey]) { if (this.cache.numberFormat[cacheKey]) {
return this.cache[cacheKey].format(value); return this.cache.numberFormat[cacheKey].format(value);
} }
this.cache[cacheKey] = formatter; this.cache.numberFormat[cacheKey] = formatter;
return formatter.format(value); return formatter.format(value);
} }
return formatter.format(value); return formatter.format(value);

View File

@ -16,6 +16,8 @@
import utils from '../../utils/utils'; import utils from '../../utils/utils';
import NumberFormatter from './NumberFormatter'; import NumberFormatter from './NumberFormatter';
import { Locale, Locales } from '../../types/types'; import { Locale, Locales } from '../../types/types';
import {I18nCache} from "../../types/interfaces";
import {createIntlCache} from "../../../index";
/** /**
* *
@ -25,15 +27,14 @@ class PluralFormatter {
private readonly locales: Locales; private readonly locales: Locales;
private readonly value: number; private readonly value: number;
private readonly message: any; private readonly message: any;
private readonly useMemorize: boolean; private readonly cache: I18nCache;
private octothorpe: Record<string, any> = {};
constructor(locale, locales, value, message, useMemorize?) { constructor(locale, locales, value, message, cache?) {
this.locale = locale; this.locale = locale;
this.locales = locales; this.locales = locales;
this.value = value; this.value = value;
this.message = message; this.message = message;
this.useMemorize = useMemorize ?? true; this.cache = cache ?? createIntlCache();
} }
// 将 message中的“#”替换为指定数字value并返回新的字符串或者字符串数组 // 将 message中的“#”替换为指定数字value并返回新的字符串或者字符串数组
@ -44,17 +45,17 @@ class PluralFormatter {
const numberFormatter = new NumberFormatter(this.locales); const numberFormatter = new NumberFormatter(this.locales);
const valueStr = numberFormatter.numberFormat(this.value); const valueStr = numberFormatter.numberFormat(this.value);
if (this.useMemorize) { if (this.cache.octothorpe) {
// 创建key用于唯一标识 // 创建key用于唯一标识
const cacheKey = utils.generateKey<Intl.NumberFormatOptions>(this.locale, this.message); const cacheKey = utils.generateKey<Intl.NumberFormatOptions>(this.locale, this.message);
// 如果key存在则使用缓存中的替代 // 如果key存在则使用缓存中的替代
if (this.octothorpe[cacheKey]) { if (this.cache.octothorpe[cacheKey]) {
return messages.map(msg => (typeof msg === 'string' ? msg.replace('#', this.octothorpe[cacheKey]) : msg)); return messages.map(msg => (typeof msg === 'string' ? msg.replace('#', this.cache.octothorpe[cacheKey]) : msg));
} }
// 如果不存在,则进行缓存 // 如果不存在,则进行缓存
this.octothorpe[cacheKey] = valueStr; this.cache.octothorpe[cacheKey] = valueStr;
} }
return messages.map(msg => (typeof msg === 'string' ? msg.replace('#', valueStr) : msg)); return messages.map(msg => (typeof msg === 'string' ? msg.replace('#', valueStr) : msg));

View File

@ -15,6 +15,7 @@
import utils from '../../utils/utils'; import utils from '../../utils/utils';
import { Locale } from '../../types/types'; import { Locale } from '../../types/types';
import {I18nCache} from "../../types/interfaces";
/** /**
* *
@ -23,24 +24,25 @@ import { Locale } from '../../types/types';
*/ */
class SelectFormatter { class SelectFormatter {
private readonly locale: Locale; private readonly locale: Locale;
private selectCache = {}; private readonly cache: I18nCache;
constructor(locale) { constructor(locale, cache) {
this.locale = locale; this.locale = locale;
this.cache = cache;
} }
getRule(value, rules, useMemorize?) { getRule(value, rules) {
if (useMemorize) { if (this.cache.select) {
// 创建key用于唯一标识 // 创建key用于唯一标识
const cacheKey = utils.generateKey<Intl.NumberFormatOptions>(this.locale, rules); const cacheKey = utils.generateKey<Intl.NumberFormatOptions>(this.locale, rules);
// 如果key存在则使用缓存中的替代 // 如果key存在则使用缓存中的替代
if (this.selectCache[cacheKey]) { if (this.cache.select[cacheKey]) {
return this.selectCache[cacheKey][value] || this.selectCache[cacheKey].other; return this.cache.select[cacheKey][value] || this.cache.select[cacheKey].other;
} }
// 如果不存在,则进行缓存 // 如果不存在,则进行缓存
this.selectCache[cacheKey] = rules; this.cache.select[cacheKey] = rules;
} }
return rules[value] || rules.other; return rules[value] || rules.other;

View File

@ -18,7 +18,8 @@ import NumberFormatter from './fomatters/NumberFormatter';
import { DatePool, Locale, Locales, SelectPool } from '../types/types'; import { DatePool, Locale, Locales, SelectPool } from '../types/types';
import PluralFormatter from './fomatters/PluralFormatter'; import PluralFormatter from './fomatters/PluralFormatter';
import SelectFormatter from './fomatters/SelectFormatter'; import SelectFormatter from './fomatters/SelectFormatter';
import { FormatOptions, IntlMessageFormat } from '../types/interfaces'; import {FormatOptions, I18nCache, IntlMessageFormat} from '../types/interfaces';
import cache from "./cache/cache";
/** /**
* *
@ -27,7 +28,8 @@ const generateFormatters = (
locale: Locale | Locales, locale: Locale | Locales,
locales: Locales, locales: Locales,
localeConfig: Record<string, any> = { plurals: undefined }, localeConfig: Record<string, any> = { plurals: undefined },
formatOptions: FormatOptions = {} // 自定义格式对象 formatOptions: FormatOptions = {}, // 自定义格式对象
cache: I18nCache
): IntlMessageFormat => { ): IntlMessageFormat => {
locale = locales || locale; locale = locales || locale;
const { plurals } = localeConfig; const { plurals } = localeConfig;
@ -45,13 +47,13 @@ const generateFormatters = (
return { return {
// 复数规则 // 复数规则
plural: (value: number, { offset = 0, ...rules }, useMemorize?) => { plural: (value: number, { offset = 0, ...rules }) => {
const pluralFormatter = new PluralFormatter( const pluralFormatter = new PluralFormatter(
locale, locale,
locales, locales,
value - offset, value - offset,
rules[value] || rules[(plurals as any)?.(value - offset)] || rules.other, rules[value] || rules[(plurals as any)?.(value - offset)] || rules.other,
useMemorize cache
); );
return pluralFormatter.replaceSymbol.bind(pluralFormatter); return pluralFormatter.replaceSymbol.bind(pluralFormatter);
}, },
@ -63,14 +65,14 @@ const generateFormatters = (
}, },
// 选择规则,如果规则对象中包含与该值相对应的属性,则返回该属性的值;否则,返回 "other" 属性的值。 // 选择规则,如果规则对象中包含与该值相对应的属性,则返回该属性的值;否则,返回 "other" 属性的值。
select: (value: SelectPool, formatRules, useMemorize?) => { select: (value: SelectPool, formatRules) => {
const selectFormatter = new SelectFormatter(locale); const selectFormatter = new SelectFormatter(locale, cache);
return selectFormatter.getRule(value, formatRules, useMemorize); return selectFormatter.getRule(value, formatRules);
}, },
// 用于将数字格式化为字符串,接受一个数字和一个格式化规则。它会根据规则返回格式化后的字符串。 // 用于将数字格式化为字符串,接受一个数字和一个格式化规则。它会根据规则返回格式化后的字符串。
numberFormat: (value: number, formatOption, useMemorize) => { numberFormat: (value: number, formatOption) => {
return new NumberFormatter(locales, getStyleOption(formatOption), useMemorize).numberFormat(value); return new NumberFormatter(locales, getStyleOption(formatOption), cache).numberFormat(value);
}, },
// 用于将日期格式化为字符串,接受一个日期对象和一个格式化规则。它会根据规则返回格式化后的字符串。 // 用于将日期格式化为字符串,接受一个日期对象和一个格式化规则。它会根据规则返回格式化后的字符串。
@ -83,8 +85,8 @@ const generateFormatters = (
* @param formatOption { year: 'numeric', month: 'long', day: 'numeric' } * @param formatOption { year: 'numeric', month: 'long', day: 'numeric' }
* @param useMemorize * @param useMemorize
*/ */
dateTimeFormat: (value: DatePool, formatOption, useMemorize) => { dateTimeFormat: (value: DatePool, formatOption) => {
return new DateTimeFormatter(locales, getStyleOption(formatOption), useMemorize).dateTimeFormat( return new DateTimeFormatter(locales, getStyleOption(formatOption), cache).dateTimeFormat(
value, value,
formatOption formatOption
); );

View File

@ -18,6 +18,7 @@ import Translation from './Translation';
import I18n from '../core/I18n'; import I18n from '../core/I18n';
import { MessageDescriptor, MessageOptions } from '../types/interfaces'; import { MessageDescriptor, MessageOptions } from '../types/interfaces';
import { CompiledMessage } from '../types/types'; import { CompiledMessage } from '../types/types';
import creatI18nCache from "./cache/cache";
export function getFormatMessage( export function getFormatMessage(
i18n: I18n, i18n: I18n,
@ -25,8 +26,8 @@ export function getFormatMessage(
values: Object | undefined = {}, values: Object | undefined = {},
options: MessageOptions = {} options: MessageOptions = {}
) { ) {
let { message, context, formatOptions, useMemorize } = options; let { message, context, formatOptions } = options;
const memorize = useMemorize ?? i18n.useMemorize; const cache = i18n.cache ?? creatI18nCache();
if (typeof id !== 'string') { if (typeof id !== 'string') {
values = values || id.defaultValues; values = values || id.defaultValues;
message = id.message || id.defaultMessage; message = id.message || id.defaultMessage;
@ -59,6 +60,6 @@ export function getFormatMessage(
// 对解析的messages进行parse解析并输出解析后的Token // 对解析的messages进行parse解析并输出解析后的Token
compliedMessage = typeof compliedMessage === 'string' ? utils.compile(compliedMessage) : compliedMessage; compliedMessage = typeof compliedMessage === 'string' ? utils.compile(compliedMessage) : compliedMessage;
const translation = new Translation(compliedMessage, i18n.locale, i18n.locales, i18n.localeConfig, memorize); const translation = new Translation(compliedMessage, i18n.locale, i18n.locales, i18n.localeConfig, cache);
return translation.translate(values, formatOptions); return translation.translate(values, formatOptions);
} }

View File

@ -46,7 +46,6 @@ export interface MessageOptions {
message?: string; message?: string;
context?: string; context?: string;
formatOptions?: FormatOptions; formatOptions?: FormatOptions;
useMemorize?: boolean;
} }
// I18n类的缓存定义 // I18n类的缓存定义
@ -54,8 +53,7 @@ export interface I18nCache {
dateTimeFormat: Record<string, Intl.DateTimeFormat>; dateTimeFormat: Record<string, Intl.DateTimeFormat>;
numberFormat: Record<string, Intl.NumberFormat>; numberFormat: Record<string, Intl.NumberFormat>;
plurals: Record<string, Intl.PluralRules>; plurals: Record<string, Intl.PluralRules>;
messages: Record<string, IntlMessageFormat>; select: Record<string, any>;
select: Record<string, object>;
octothorpe: Record<string, any>; octothorpe: Record<string, any>;
} }
@ -65,7 +63,7 @@ export interface I18nProps {
locales?: Locales; locales?: Locales;
messages?: AllMessages; messages?: AllMessages;
localeConfig?: AllLocaleConfig; localeConfig?: AllLocaleConfig;
useMemorize?: boolean; cache?: I18nCache;
error?: Error; error?: Error;
} }
@ -91,23 +89,41 @@ export interface configProps {
defaultLocale?: string; defaultLocale?: string;
RenderOnLocaleChange?: boolean; RenderOnLocaleChange?: boolean;
children?: any; children?: any;
uesMemorize?: boolean; onWarn?: Error;
} }
export interface IntlMessageFormat extends configProps, MessageOptions { export interface IntlMessageFormat extends configProps, MessageOptions {
plural: ( plural: (
value: number, value: number,
{ offset, ...rules }: { [x: string]: any; offset?: number }, {
useMemorize?: boolean offset,
...rules
}: {
[x: string]: any;
offset?: number | undefined;
}
) => (ctx: any) => any[]; ) => (ctx: any) => any[];
selectordinal: ( selectordinal: (
value: number, value: number,
{ offset, ...rules }: { [x: string]: any; offset?: number }, {
useMemorize?: boolean offset,
...rules
}: {
[x: string]: any;
offset?: number | undefined;
}
) => (ctx: any) => any[]; ) => (ctx: any) => any[];
select: (value: SelectPool, formatRules: any, useMemorize?: boolean) => any; select: (value: SelectPool, formatRules: any) => any;
numberFormat: (value: number, formatOption: any, useMemorize: boolean) => string; numberFormat: (value: number, formatOption: any) => string;
dateTimeFormat: (value: DatePool, formatOption: any, useMemorize: boolean) => string; /**
* eg: { year: 'numeric', month: 'long', day: 'numeric' } DateTimeFormatter如何将日期对象转换为字符串的参数
* \year: 'numeric' 2023
* month: 'long' January
* day: 'numeric' 1
* @param value
* @param formatOption { year: 'numeric', month: 'long', day: 'numeric' }
*/
dateTimeFormat: (value: DatePool, formatOption: any) => string;
undefined: (value: any) => any; undefined: (value: any) => any;
} }

View File

@ -77,7 +77,7 @@ describe('I18n', () => {
locale: 'en', locale: 'en',
messages: { messages: {
en: messages, en: messages,
fr:{} fr: {},
}, },
}); });

View File

@ -13,66 +13,63 @@
* See the Mulan PSL v2 for more details. * See the Mulan PSL v2 for more details.
*/ */
import * as React from 'react' import * as React from 'react';
import {render} from '@testing-library/react' import { render } from '@testing-library/react';
import {IntlProvider, useIntl} from "../../../index"; import { IntlProvider, useIntl } from '../../../index';
const FunctionComponent = ({spy}: { spy?: Function }) => { const FunctionComponent = ({ spy }: { spy?: Function }) => {
const {i18n} = useIntl() const { i18n } = useIntl();
spy!(i18n.locale) spy!(i18n.locale);
return null return null;
} };
const FC = () => { const FC = () => {
const i18n = useIntl() const i18n = useIntl();
return i18n.formatNumber(10000, {style: 'currency', currency: 'USD'}) as any return i18n.formatNumber(10000, { style: 'currency', currency: 'USD' }) as any;
} };
describe('useIntl() hooks', () => { describe('useIntl() hooks', () => {
it('throws when <IntlProvider> is missing from ancestry', () => { it('throws when <IntlProvider> is missing from ancestry', () => {
// So it doesn't spam the console // So it doesn't spam the console
jest.spyOn(console, 'error').mockImplementation(() => { jest.spyOn(console, 'error').mockImplementation(() => {});
}) expect(() => render(<FunctionComponent />)).toThrow('I18n object is not found!');
expect(() => render(<FunctionComponent/>)).toThrow( });
'I18n object is not found!'
)
})
it('hooks onto the intl context', () => { it('hooks onto the intl context', () => {
const spy = jest.fn() const spy = jest.fn();
render( render(
<IntlProvider locale="en"> <IntlProvider locale="en">
<FunctionComponent spy={spy}/> <FunctionComponent spy={spy} />
</IntlProvider> </IntlProvider>
) );
expect(spy).toHaveBeenCalledWith('en') expect(spy).toHaveBeenCalledWith('en');
}) });
it('should work when switching locale on provider', () => { it('should work when switching locale on provider', () => {
const {rerender, getByTestId} = render( const { rerender, getByTestId } = render(
<IntlProvider locale="en"> <IntlProvider locale="en">
<span data-testid="comp"> <span data-testid="comp">
<FC/> <FC />
</span> </span>
</IntlProvider> </IntlProvider>
) );
expect(getByTestId('comp')).toMatchSnapshot() expect(getByTestId('comp')).toMatchSnapshot();
rerender( rerender(
<IntlProvider locale="es"> <IntlProvider locale="es">
<span data-testid="comp"> <span data-testid="comp">
<FC/> <FC />
</span> </span>
</IntlProvider> </IntlProvider>
) );
expect(getByTestId('comp')).toMatchSnapshot() expect(getByTestId('comp')).toMatchSnapshot();
rerender( rerender(
<IntlProvider locale="en"> <IntlProvider locale="en">
<span data-testid="comp"> <span data-testid="comp">
<FC/> <FC />
</span> </span>
</IntlProvider> </IntlProvider>
) );
expect(getByTestId('comp')).toMatchSnapshot() expect(getByTestId('comp')).toMatchSnapshot();
}) });
}) });

View File

@ -14,6 +14,7 @@
*/ */
import Translation from '../../src/format/Translation'; import Translation from '../../src/format/Translation';
import {createIntlCache} from "../../index";
describe('Translation', () => { describe('Translation', () => {
let translation; let translation;
@ -23,8 +24,7 @@ describe('Translation', () => {
const locale = 'en'; const locale = 'en';
const locales = {}; const locales = {};
const localeConfig = {}; const localeConfig = {};
const useMemorize = true; translation = new Translation(compiledMessage, locale, locales, localeConfig, createIntlCache());
translation = new Translation(compiledMessage, locale, locales, localeConfig, useMemorize);
}); });
describe('formatMessage', () => { describe('formatMessage', () => {
it('should return the message if it is not an array', () => { it('should return the message if it is not an array', () => {

View File

@ -21,7 +21,6 @@ describe('creatI18nCache', () => {
expect(intlCache).toEqual({ expect(intlCache).toEqual({
dateTimeFormat: {}, dateTimeFormat: {},
numberFormat: {}, numberFormat: {},
messages: {},
plurals: {}, plurals: {},
select: {}, select: {},
octothorpe: {}, octothorpe: {},

View File

@ -43,7 +43,6 @@ describe('compile', function () {
it('should compile message with variable', function () { it('should compile message with variable', function () {
const cache = utils.compile('Hey {name}!'); const cache = utils.compile('Hey {name}!');
console.log(cache)
expect(new Translation(cache, 'en', [], {}).translate({})).toEqual('Hey {name}!'); expect(new Translation(cache, 'en', [], {}).translate({})).toEqual('Hey {name}!');
}); });
@ -58,7 +57,6 @@ describe('compile', function () {
expect(translate({ value: 1 })).toEqual('1 Book'); expect(translate({ value: 1 })).toEqual('1 Book');
expect(translate({ value: 2 })).toEqual('2 Books'); expect(translate({ value: 2 })).toEqual('2 Books');
const translatePlurals = prepare('{value, plural, offset:1 =0 {No Books} one {# Book} other {# Books}}'); const translatePlurals = prepare('{value, plural, offset:1 =0 {No Books} one {# Book} other {# Books}}');
expect(translatePlurals({ value: 0 })).toEqual('No Books'); expect(translatePlurals({ value: 0 })).toEqual('No Books');

View File

@ -14,6 +14,7 @@
*/ */
import { DateTimeFormatter } from '../../../index'; import { DateTimeFormatter } from '../../../index';
import creatI18nCache from "../../../src/format/cache/cache";
describe('DateTimeFormatter', () => { describe('DateTimeFormatter', () => {
const date = new Date('2023-04-03T12:34:56Z'); const date = new Date('2023-04-03T12:34:56Z');
@ -25,7 +26,7 @@ describe('DateTimeFormatter', () => {
const firstRunResult = firstRunt1 - firstRunt0; const firstRunResult = firstRunt1 - firstRunt0;
const seconddRunt0 = performance.now(); const seconddRunt0 = performance.now();
const dateTimeFormatter2 = new DateTimeFormatter('es', {}, false); const dateTimeFormatter2 = new DateTimeFormatter('es', {});
dateTimeFormatter2.dateTimeFormat(new Date()); dateTimeFormatter2.dateTimeFormat(new Date());
const seconddRunt1 = performance.now(); const seconddRunt1 = performance.now();
const secondRunResult = seconddRunt1 - seconddRunt0; const secondRunResult = seconddRunt1 - seconddRunt0;
@ -62,8 +63,8 @@ describe('DateTimeFormatter', () => {
it('should not memoize formatter instances when memoize is false', () => { it('should not memoize formatter instances when memoize is false', () => {
const spy = jest.spyOn(Intl, 'DateTimeFormat'); const spy = jest.spyOn(Intl, 'DateTimeFormat');
const formatter1 = new DateTimeFormatter('en-US', { month: 'short' }, false); const formatter1 = new DateTimeFormatter('en-US', { month: 'short' });
const formatter2 = new DateTimeFormatter('en-US', { month: 'short' }, false); const formatter2 = new DateTimeFormatter('en-US', { month: 'short' });
formatter1.dateTimeFormat(date); formatter1.dateTimeFormat(date);
formatter2.dateTimeFormat(date); formatter2.dateTimeFormat(date);
expect(spy).toHaveBeenCalledTimes(5); expect(spy).toHaveBeenCalledTimes(5);
@ -91,7 +92,7 @@ describe('DateTimeFormatter', () => {
}); });
it('should format using memorized formatter when useMemorize is true', () => { it('should format using memorized formatter when useMemorize is true', () => {
const formatter = new DateTimeFormatter('en-US',{"year":'numeric'}, true); const formatter = new DateTimeFormatter('en-US',{"year":'numeric'}, creatI18nCache());
const date = new Date(2023, 0, 1); const date = new Date(2023, 0, 1);
const formatted1 = formatter.dateTimeFormat(date); const formatted1 = formatter.dateTimeFormat(date);
const formatted2 = formatter.dateTimeFormat(date); const formatted2 = formatter.dateTimeFormat(date);

View File

@ -14,6 +14,7 @@
*/ */
import { NumberFormatter } from '../../../index'; import { NumberFormatter } from '../../../index';
import creatI18nCache from "../../../src/format/cache/cache";
describe('NumberFormatter', () => { describe('NumberFormatter', () => {
it('number formatter is memoized', async () => { it('number formatter is memoized', async () => {
@ -24,7 +25,7 @@ describe('NumberFormatter', () => {
const firstRunResult = firstRunt1 - firstRunt0; const firstRunResult = firstRunt1 - firstRunt0;
const seconddRunt0 = performance.now(); const seconddRunt0 = performance.now();
const numberFormatter = new NumberFormatter('es', {}, false); const numberFormatter = new NumberFormatter('es', {});
numberFormatter.numberFormat(10000); numberFormatter.numberFormat(10000);
const secondRunt1 = performance.now(); const secondRunt1 = performance.now();
const secondRunResult = secondRunt1 - seconddRunt0; const secondRunResult = secondRunt1 - seconddRunt0;
@ -82,7 +83,7 @@ describe('NumberFormatter', () => {
}); });
it('should format using memorized formatter when useMemorize is true', () => { it('should format using memorized formatter when useMemorize is true', () => {
const formatter = new NumberFormatter('en-US', undefined, true); const formatter = new NumberFormatter('en-US', undefined, creatI18nCache());
const number = 12345.6789; const number = 12345.6789;
const formatted1 = formatter.numberFormat(number); const formatted1 = formatter.numberFormat(number);
const formatted2 = formatter.numberFormat(number); const formatted2 = formatter.numberFormat(number);
@ -90,7 +91,7 @@ describe('NumberFormatter', () => {
}); });
it('should create a new formatter when useMemorize is false', () => { it('should create a new formatter when useMemorize is false', () => {
const formatter = new NumberFormatter('en-US', undefined, false); const formatter = new NumberFormatter('en-US', undefined);
const number = 12345.6789; const number = 12345.6789;
const formatted1 = formatter.numberFormat(number); const formatted1 = formatter.numberFormat(number);
const formatted2 = formatter.numberFormat(number); const formatted2 = formatter.numberFormat(number);

View File

@ -61,7 +61,7 @@ describe('ruleUtils test', () => {
expect(() => { expect(() => {
ruleUtils.getReg(input); ruleUtils.getReg(input);
}).toThrowError('Signs Prohibited'); }).toThrowError('prohibition sign');
}); });
it('should throw an error when input regular expression object has forbidden flags', () => { it('should throw an error when input regular expression object has forbidden flags', () => {