Skip to content

Commit d7ee2cc

Browse files
committed
refactor(use-i18n): use @formatjs/fast-memoize instead of deprecated intl-format-cache
1 parent 8d54d13 commit d7ee2cc

File tree

5 files changed

+97
-24
lines changed

5 files changed

+97
-24
lines changed

packages/use-i18n/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
},
2828
"license": "MIT",
2929
"dependencies": {
30+
"@formatjs/fast-memoize": "^1.1.2",
3031
"date-fns": "^2.19.0",
3132
"filesize": "^7.0.0",
3233
"intl-format-cache": "^4.3.1",

packages/use-i18n/src/formatUnit.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import filesize from 'filesize'
22
import { Options } from 'intl-messageformat'
3+
import formatters from './formatters'
34

45
// We are on base 10, so we should use IEC standard here ...
56
const exponents = [
@@ -72,7 +73,7 @@ const formatShortUnit = (locale: string, exponent: Exponent, unit: Unit, compoun
7273
}`
7374
}
7475

75-
const formatLongUnit = (locale: string, exponent: Exponent, unit: Unit, amount: number, messageFormat: FormatPlural) => {
76+
const formatLongUnit = (locale: string, exponent: Exponent, unit: Unit, amount: number) => {
7677
let translation = symbols.long[unit]
7778

7879
if (
@@ -82,14 +83,14 @@ const formatLongUnit = (locale: string, exponent: Exponent, unit: Unit, amount:
8283
translation = localesWhoFavorOctetOverByte[locale as keyof typeof localesWhoFavorOctetOverByte]
8384
}
8485

85-
return `${exponent.name}${messageFormat(
86+
return `${exponent.name}${formatters.getTranslationFormat(
8687
`{amount, plural,
8788
=0 {${translation.singular}}
8889
=1 {${translation.singular}}
8990
other {${translation.plural}}
9091
}`,
9192
locale,
92-
).format({ amount })}`
93+
).format({ amount }) as string}`
9394
}
9495

9596
const format =
@@ -103,7 +104,6 @@ const format =
103104
locale: string,
104105
amount: number,
105106
{ maximumFractionDigits, minimumFractionDigits, short = true }: { maximumFractionDigits?: number, minimumFractionDigits?: number, short?: boolean },
106-
messageFormat: FormatPlural,
107107
): string => {
108108
let computedExponent = exponent
109109
let computedValue = amount
@@ -141,7 +141,6 @@ const format =
141141
computedExponent as Exponent,
142142
unit,
143143
computedValue,
144-
messageFormat,
145144
)
146145
}`
147146
}
@@ -199,7 +198,7 @@ export interface FormatUnitOptions {
199198
short?: boolean
200199
}
201200

202-
const formatUnit = (locale: string, number: number, { unit, ...options }: FormatUnitOptions, messageFormat: FormatPlural): string =>
203-
supportedUnits?.[unit]?.(locale, number, options, messageFormat) ?? ''
201+
const formatUnit = (locale: string, number: number, { unit, ...options }: FormatUnitOptions): string =>
202+
supportedUnits?.[unit]?.(locale, number, options) ?? ''
204203

205204
export default formatUnit

packages/use-i18n/src/formatters.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import memoize, { Cache, strategies } from '@formatjs/fast-memoize'
2+
import IntlTranslationFormat from 'intl-messageformat'
3+
4+
// Deeply inspired by https://github.com/formatjs/formatjs/blob/7406e526a9c5666cee22cc2316dad1fa1d88697c/packages/intl-messageformat/src/core.ts
5+
6+
interface BaseFormatters {
7+
getNumberFormat(
8+
...args: ConstructorParameters<typeof Intl.NumberFormat>
9+
): Intl.NumberFormat
10+
getDateTimeFormat(
11+
...args: ConstructorParameters<typeof Intl.DateTimeFormat>
12+
): Intl.DateTimeFormat
13+
getPluralRules(
14+
...args: ConstructorParameters<typeof Intl.PluralRules>
15+
): Intl.PluralRules
16+
getListFormat(
17+
...args: ConstructorParameters<typeof Intl.ListFormat>
18+
): Intl.ListFormat
19+
}
20+
21+
function createFastMemoizeCache<V>(): Cache<string, V> {
22+
const store: Record<string, V> = {}
23+
24+
return {
25+
create() {
26+
return {
27+
get(key) {
28+
return store[key]
29+
},
30+
// Can be removed once https://github.com/formatjs/formatjs/pull/3102 is merged
31+
has(key) {
32+
return key in store
33+
},
34+
set(key, value) {
35+
store[key] = value
36+
},
37+
}
38+
},
39+
}
40+
}
41+
42+
const baseFormatters: BaseFormatters = {
43+
getDateTimeFormat: memoize((...args) => new Intl.DateTimeFormat(...args), {
44+
cache: createFastMemoizeCache<Intl.DateTimeFormat>(),
45+
strategy: strategies.variadic,
46+
}),
47+
getListFormat: memoize((...args) => new Intl.ListFormat(...args), {
48+
cache: createFastMemoizeCache<Intl.ListFormat>(),
49+
strategy: strategies.variadic,
50+
}),
51+
getNumberFormat: memoize((...args) => new Intl.NumberFormat(...args), {
52+
cache: createFastMemoizeCache<Intl.NumberFormat>(),
53+
strategy: strategies.variadic,
54+
}),
55+
getPluralRules: memoize((...args) => new Intl.PluralRules(...args), {
56+
cache: createFastMemoizeCache<Intl.PluralRules>(),
57+
strategy: strategies.variadic,
58+
}),
59+
}
60+
61+
type Formatters = BaseFormatters & {
62+
getTranslationFormat(
63+
...args: ConstructorParameters<typeof IntlTranslationFormat>
64+
): IntlTranslationFormat
65+
}
66+
67+
type TranslationFormatParameter = ConstructorParameters<typeof IntlTranslationFormat>
68+
69+
const formatters: Formatters = {
70+
...baseFormatters,
71+
getTranslationFormat: memoize((message: TranslationFormatParameter[0], locales: TranslationFormatParameter[1], overrideFormats: TranslationFormatParameter[2], opts: TranslationFormatParameter[3]) => new IntlTranslationFormat(message, locales, overrideFormats, {
72+
formatters: baseFormatters,
73+
...opts,
74+
}), {
75+
cache: createFastMemoizeCache<IntlTranslationFormat>(),
76+
strategy: strategies.variadic,
77+
}),
78+
}
79+
80+
export default formatters

packages/use-i18n/src/usei18n.tsx

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
import { Locale, formatDistanceToNow, formatDistanceToNowStrict } from 'date-fns'
2-
import memoizeIntlConstructor from 'intl-format-cache'
3-
import IntlTranslationFormat from 'intl-messageformat'
42
import PropTypes from 'prop-types'
53
import React, {
64
ReactElement,
@@ -16,6 +14,7 @@ import ReactDOM from 'react-dom'
1614
import 'intl-pluralrules'
1715
import dateFormat, { FormatDateOptions } from './formatDate'
1816
import unitFormat, { FormatUnitOptions } from './formatUnit'
17+
import formatters from './formatters'
1918

2019
const LOCALE_ITEM_STORAGE = 'locale'
2120

@@ -60,7 +59,7 @@ interface Context {
6059
dateFnsLocale?: Locale,
6160
datetime?: (date: Date | number, options?: Intl.DateTimeFormatOptions) => string,
6261
formatDate?: (value: Date | number | string, options: FormatDateOptions) => string,
63-
formatList?: (listFormat: string[], options?: Intl.ListFormatOptions) => string,
62+
formatList?: (listFormat: [string | undefined], options?: Intl.ListFormatOptions) => string,
6463
formatNumber?: (numb: number, options?: Intl.NumberFormatOptions) => string,
6564
formatUnit?: (value: number, options: FormatUnitOptions) => string,
6665
loadTranslations?: (namespace: string, load?: LoadTranslationsFn) => Promise<string>,
@@ -114,12 +113,6 @@ export const useTranslation = (namespaces: string[] = [], load: LoadTranslations
114113
return { ...context, isLoaded }
115114
}
116115

117-
// https://formatjs.io/docs/intl-messageformat/
118-
const getTranslationFormat = memoizeIntlConstructor(IntlTranslationFormat)
119-
const getNumberFormat = memoizeIntlConstructor(Intl.NumberFormat)
120-
const getDateTimeFormat = memoizeIntlConstructor(Intl.DateTimeFormat)
121-
const getListFormat = memoizeIntlConstructor(Intl.ListFormat)
122-
123116
type LoadTranslationsFn = ({ namespace, locale }: { namespace: string, locale: string}) => Promise<{ default: Translations}>
124117
type LoadLocaleFn = (locale: string) => Promise<Locale>
125118

@@ -218,15 +211,15 @@ const I18nContextProvider = ({
218211
const formatNumber = useCallback(
219212
// intl-format-chache does not forwrad return types
220213
// eslint-disable-next-line
221-
(numb: number, options?: Intl.NumberFormatOptions) => getNumberFormat(currentLocale, options).format(numb),
214+
(numb: number, options?: Intl.NumberFormatOptions) => formatters.getNumberFormat(currentLocale, options).format(numb),
222215
[currentLocale],
223216
)
224217

225218
const formatList = useCallback(
226-
(listFormat: string[], options?: Intl.ListFormatOptions) =>
219+
(listFormat: [string | undefined], options?: Intl.ListFormatOptions) =>
227220
// intl-format-chache does not forwrad return types
228221
// eslint-disable-next-line
229-
getListFormat(currentLocale, options).format(listFormat),
222+
formatters.getListFormat(currentLocale, options).format(listFormat),
230223
[currentLocale],
231224
)
232225

@@ -235,7 +228,7 @@ const I18nContextProvider = ({
235228
// be able to use formatNumber directly
236229
const formatUnit = useCallback(
237230
(value: number, options: FormatUnitOptions) =>
238-
unitFormat(currentLocale, value, options, getTranslationFormat),
231+
unitFormat(currentLocale, value, options),
239232
[currentLocale],
240233
)
241234

@@ -248,7 +241,7 @@ const I18nContextProvider = ({
248241
const datetime = useCallback(
249242
// intl-format-chache does not forwrad return types
250243
// eslint-disable-next-line
251-
(date: Date | number, options?: Intl.DateTimeFormatOptions): string => getDateTimeFormat(currentLocale, options).format(date),
244+
(date: Date | number, options?: Intl.DateTimeFormatOptions): string => formatters.getDateTimeFormat(currentLocale, options).format(date),
252245
[currentLocale],
253246
)
254247

@@ -283,7 +276,7 @@ const I18nContextProvider = ({
283276
[dateFnsLocale],
284277
)
285278

286-
const translate = useCallback(
279+
const translate = useCallback<TranslateFn>(
287280
(key: string, context?: Record<string, PrimitiveType>) => {
288281
const value = translations[currentLocale]?.[key]
289282
if (!value) {
@@ -296,7 +289,7 @@ const I18nContextProvider = ({
296289
if (context) {
297290
// intl-format-chache does not forwrad return types
298291
// eslint-disable-next-line
299-
return getTranslationFormat(value, currentLocale).format(context)
292+
return formatters.getTranslationFormat(value, currentLocale).format(context) as string
300293
}
301294

302295
return value

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1209,7 +1209,7 @@
12091209
"@formatjs/intl-localematcher" "0.2.19"
12101210
tslib "^2.1.0"
12111211

1212-
"@formatjs/[email protected]":
1212+
"@formatjs/[email protected]", "@formatjs/fast-memoize@^1.1.2":
12131213
version "1.1.2"
12141214
resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.1.2.tgz#09c8771484095c07c752b824b142d6c2e2c8264f"
12151215
integrity sha512-HfN6D9yd9vhypWwTVpJHqoSb50KFuoxZ2ZS6AM1XNSyihWk7JJXjZ3mgvboJU4eNSsdxAWwR1ke5KIOobEVwBA==

0 commit comments

Comments
 (0)