@react-aria/i18n
Advanced tools
Comparing version 3.2.0 to 3.3.0
211
dist/main.js
var _babelRuntimeHelpersExtends = $parcel$interopDefault(require("@babel/runtime/helpers/extends")); | ||
var _intlMessageformat = $parcel$interopDefault(require("intl-messageformat")); | ||
var { | ||
NumberFormatter | ||
} = require("@internationalized/number"); | ||
var { | ||
MessageDictionary, | ||
MessageFormatter | ||
} = require("@internationalized/message"); | ||
var { | ||
useIsSSR | ||
@@ -18,3 +25,3 @@ } = require("@react-aria/ssr"); | ||
useCallback, | ||
useRef | ||
useMemo | ||
} = _react2; | ||
@@ -59,38 +66,2 @@ | ||
function $dbb62b32f79d03a795a46f9fbec514c$export$numberFormatSignDisplayPolyfill(numberFormat, signDisplay, num) { | ||
if (signDisplay === 'auto') { | ||
return numberFormat.format(num); | ||
} else if (signDisplay === 'never') { | ||
return numberFormat.format(Math.abs(num)); | ||
} else { | ||
let needsPositiveSign = false; | ||
if (signDisplay === 'always') { | ||
needsPositiveSign = num > 0 || Object.is(num, 0); | ||
} else if (signDisplay === 'exceptZero') { | ||
if (Object.is(num, -0) || Object.is(num, 0)) { | ||
num = Math.abs(num); | ||
} else { | ||
needsPositiveSign = num > 0; | ||
} | ||
} | ||
if (needsPositiveSign) { | ||
let negative = numberFormat.format(-num); | ||
let noSign = numberFormat.format(num); // ignore RTL/LTR marker character | ||
let minus = negative.replace(noSign, '').replace(/\u200e|\u061C/, ''); | ||
if ([...minus].length !== 1) { | ||
console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case'); | ||
} | ||
let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign); | ||
return positive; | ||
} else { | ||
return numberFormat.format(num); | ||
} | ||
} | ||
} | ||
/** | ||
@@ -182,3 +153,14 @@ * Gets the locale setting of the browser. | ||
exports.useLocale = useLocale; | ||
const $a5aefbc9b72193c190dce301e0eb39$var$formatterCache = new Map(); | ||
const $a5aefbc9b72193c190dce301e0eb39$var$cache = new WeakMap(); | ||
function $a5aefbc9b72193c190dce301e0eb39$var$getCachedDictionary(strings) { | ||
let dictionary = $a5aefbc9b72193c190dce301e0eb39$var$cache.get(strings); | ||
if (!dictionary) { | ||
dictionary = new MessageDictionary(strings); | ||
$a5aefbc9b72193c190dce301e0eb39$var$cache.set(strings, dictionary); | ||
} | ||
return dictionary; | ||
} | ||
/** | ||
@@ -190,78 +172,13 @@ * Handles formatting ICU Message strings to create localized strings for the current locale. | ||
function useMessageFormatter(strings) { | ||
let { | ||
locale: currentLocale | ||
} = useLocale(); // Check the cache | ||
let localeCache = $a5aefbc9b72193c190dce301e0eb39$var$formatterCache.get(strings); | ||
if (localeCache && localeCache.has(currentLocale)) { | ||
return localeCache.get(currentLocale); | ||
} // Add to the formatter cache if needed | ||
if (!localeCache) { | ||
localeCache = new Map(); | ||
$a5aefbc9b72193c190dce301e0eb39$var$formatterCache.set(strings, localeCache); | ||
} // Get the strings for the current locale | ||
let localeStrings = $a5aefbc9b72193c190dce301e0eb39$var$selectLocale(strings, currentLocale); // Create a new message formatter | ||
let cache = {}; | ||
let formatMessage = (key, variables) => { | ||
let message = cache[key + '.' + currentLocale]; | ||
if (!message) { | ||
let msg = localeStrings[key]; | ||
if (!msg) { | ||
throw new Error("Could not find intl message " + key + " in " + currentLocale + " locale"); | ||
} | ||
message = new _intlMessageformat(msg, currentLocale); | ||
cache[key] = message; | ||
} | ||
return message.format(variables); | ||
}; | ||
localeCache.set(currentLocale, formatMessage); | ||
return formatMessage; | ||
locale | ||
} = useLocale(); | ||
let dictionary = useMemo(() => $a5aefbc9b72193c190dce301e0eb39$var$getCachedDictionary(strings), [strings]); | ||
let formatter = useMemo(() => new MessageFormatter(locale, dictionary), [locale, dictionary]); | ||
return useCallback((key, variables) => formatter.format(key, variables), [formatter]); | ||
} | ||
exports.useMessageFormatter = useMessageFormatter; | ||
function $a5aefbc9b72193c190dce301e0eb39$var$selectLocale(strings, locale) { | ||
// If there is an exact match, use it. | ||
if (strings[locale]) { | ||
return strings[locale]; | ||
} // Attempt to find the closest match by language. | ||
// For example, if the locale is fr-CA (French Canadian), but there is only | ||
// an fr-FR (France) set of strings, use that. | ||
let language = $a5aefbc9b72193c190dce301e0eb39$var$getLanguage(locale); | ||
for (let key in strings) { | ||
if (key.startsWith(language + '-')) { | ||
return strings[key]; | ||
} | ||
} // Nothing close, use english. | ||
return strings['en-US']; | ||
} | ||
function $a5aefbc9b72193c190dce301e0eb39$var$getLanguage(locale) { | ||
// @ts-ignore | ||
if (Intl.Locale) { | ||
// @ts-ignore | ||
return new Intl.Locale(locale).language; | ||
} | ||
return locale.split('-')[0]; | ||
} | ||
let $bdeee39f835a1e28966186127db96579$var$formatterCache = new Map(); | ||
@@ -292,47 +209,2 @@ /** | ||
/** | ||
* Provides localized number parsing for the current locale. | ||
* Idea from https://observablehq.com/@mbostock/localized-number-parsing. | ||
*/ | ||
function useNumberParser() { | ||
let { | ||
locale | ||
} = useLocale(); | ||
const numberData = useRef({ | ||
group: null, | ||
decimal: null, | ||
numeral: null, | ||
index: null | ||
}); | ||
useEffect(() => { | ||
const parts = new Intl.NumberFormat(locale).formatToParts(12345.6); | ||
const numerals = [...new Intl.NumberFormat(locale, { | ||
useGrouping: false | ||
}).format(9876543210)].reverse(); | ||
const index = new Map(numerals.map((d, i) => [d, i])); | ||
numberData.current.group = new RegExp("[" + parts.find(d => d.type === 'group').value + "]", 'g'); | ||
numberData.current.decimal = new RegExp("[" + parts.find(d => d.type === 'decimal').value + "]"); | ||
numberData.current.numeral = new RegExp("[" + numerals.join('') + "]", 'g'); | ||
numberData.current.index = d => index.get(d); | ||
}, [locale]); | ||
const parse = useCallback(value => { | ||
value = value.trim().replace(numberData.current.group, '').replace(numberData.current.decimal, '.').replace(numberData.current.numeral, numberData.current.index); | ||
return value ? +value : NaN; | ||
}, []); | ||
return { | ||
parse | ||
}; | ||
} | ||
exports.useNumberParser = useNumberParser; | ||
let $fa77db1482937b6cdb6683d9d7eb896$var$formatterCache = new Map(); | ||
let $fa77db1482937b6cdb6683d9d7eb896$var$supportsSignDisplay = false; | ||
try { | ||
// @ts-ignore | ||
$fa77db1482937b6cdb6683d9d7eb896$var$supportsSignDisplay = new Intl.NumberFormat('de-DE', { | ||
signDisplay: 'exceptZero' | ||
}).resolvedOptions().signDisplay === 'exceptZero'; // eslint-disable-next-line no-empty | ||
} catch (e) {} | ||
/** | ||
* Provides localized number formatting for the current locale. Automatically updates when the locale changes, | ||
@@ -342,30 +214,11 @@ * and handles caching of the number formatter for performance. | ||
*/ | ||
function useNumberFormatter(options) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
function useNumberFormatter(options) { | ||
let { | ||
locale | ||
} = useLocale(); | ||
let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : ''); | ||
if ($fa77db1482937b6cdb6683d9d7eb896$var$formatterCache.has(cacheKey)) { | ||
return $fa77db1482937b6cdb6683d9d7eb896$var$formatterCache.get(cacheKey); | ||
} | ||
let numberFormatter = new Intl.NumberFormat(locale, options); // @ts-ignore | ||
let { | ||
signDisplay | ||
} = options || {}; | ||
$fa77db1482937b6cdb6683d9d7eb896$var$formatterCache.set(cacheKey, !$fa77db1482937b6cdb6683d9d7eb896$var$supportsSignDisplay && signDisplay != null ? new Proxy(numberFormatter, { | ||
get(target, property) { | ||
if (property === 'format') { | ||
return v => $dbb62b32f79d03a795a46f9fbec514c$export$numberFormatSignDisplayPolyfill(numberFormatter, signDisplay, v); | ||
} else { | ||
return target[property]; | ||
} | ||
} | ||
}) : numberFormatter); | ||
return numberFormatter; | ||
return useMemo(() => new NumberFormatter(locale, options), [locale, options]); | ||
} | ||
@@ -372,0 +225,0 @@ |
import _babelRuntimeHelpersEsmExtends from "@babel/runtime/helpers/esm/extends"; | ||
import _intlMessageformat from "intl-messageformat"; | ||
import { NumberFormatter } from "@internationalized/number"; | ||
import { MessageDictionary, MessageFormatter } from "@internationalized/message"; | ||
import { useIsSSR } from "@react-aria/ssr"; | ||
import _react, { useEffect, useState, useContext, useCallback, useRef } from "react"; | ||
import _react, { useEffect, useState, useContext, useCallback, useMemo } from "react"; | ||
@@ -39,38 +40,2 @@ /* | ||
function $d26e725ad56fbcb2c25f52b7de27$export$numberFormatSignDisplayPolyfill(numberFormat, signDisplay, num) { | ||
if (signDisplay === 'auto') { | ||
return numberFormat.format(num); | ||
} else if (signDisplay === 'never') { | ||
return numberFormat.format(Math.abs(num)); | ||
} else { | ||
let needsPositiveSign = false; | ||
if (signDisplay === 'always') { | ||
needsPositiveSign = num > 0 || Object.is(num, 0); | ||
} else if (signDisplay === 'exceptZero') { | ||
if (Object.is(num, -0) || Object.is(num, 0)) { | ||
num = Math.abs(num); | ||
} else { | ||
needsPositiveSign = num > 0; | ||
} | ||
} | ||
if (needsPositiveSign) { | ||
let negative = numberFormat.format(-num); | ||
let noSign = numberFormat.format(num); // ignore RTL/LTR marker character | ||
let minus = negative.replace(noSign, '').replace(/\u200e|\u061C/, ''); | ||
if ([...minus].length !== 1) { | ||
console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case'); | ||
} | ||
let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign); | ||
return positive; | ||
} else { | ||
return numberFormat.format(num); | ||
} | ||
} | ||
} | ||
/** | ||
@@ -157,3 +122,14 @@ * Gets the locale setting of the browser. | ||
} | ||
const $f58d206cee90f9c2bf3c03e4522c35$var$formatterCache = new Map(); | ||
const $f58d206cee90f9c2bf3c03e4522c35$var$cache = new WeakMap(); | ||
function $f58d206cee90f9c2bf3c03e4522c35$var$getCachedDictionary(strings) { | ||
let dictionary = $f58d206cee90f9c2bf3c03e4522c35$var$cache.get(strings); | ||
if (!dictionary) { | ||
dictionary = new MessageDictionary(strings); | ||
$f58d206cee90f9c2bf3c03e4522c35$var$cache.set(strings, dictionary); | ||
} | ||
return dictionary; | ||
} | ||
/** | ||
@@ -165,76 +141,11 @@ * Handles formatting ICU Message strings to create localized strings for the current locale. | ||
export function useMessageFormatter(strings) { | ||
let { | ||
locale: currentLocale | ||
} = useLocale(); // Check the cache | ||
let localeCache = $f58d206cee90f9c2bf3c03e4522c35$var$formatterCache.get(strings); | ||
if (localeCache && localeCache.has(currentLocale)) { | ||
return localeCache.get(currentLocale); | ||
} // Add to the formatter cache if needed | ||
if (!localeCache) { | ||
localeCache = new Map(); | ||
$f58d206cee90f9c2bf3c03e4522c35$var$formatterCache.set(strings, localeCache); | ||
} // Get the strings for the current locale | ||
let localeStrings = $f58d206cee90f9c2bf3c03e4522c35$var$selectLocale(strings, currentLocale); // Create a new message formatter | ||
let cache = {}; | ||
let formatMessage = (key, variables) => { | ||
let message = cache[key + '.' + currentLocale]; | ||
if (!message) { | ||
let msg = localeStrings[key]; | ||
if (!msg) { | ||
throw new Error("Could not find intl message " + key + " in " + currentLocale + " locale"); | ||
} | ||
message = new _intlMessageformat(msg, currentLocale); | ||
cache[key] = message; | ||
} | ||
return message.format(variables); | ||
}; | ||
localeCache.set(currentLocale, formatMessage); | ||
return formatMessage; | ||
locale | ||
} = useLocale(); | ||
let dictionary = useMemo(() => $f58d206cee90f9c2bf3c03e4522c35$var$getCachedDictionary(strings), [strings]); | ||
let formatter = useMemo(() => new MessageFormatter(locale, dictionary), [locale, dictionary]); | ||
return useCallback((key, variables) => formatter.format(key, variables), [formatter]); | ||
} | ||
function $f58d206cee90f9c2bf3c03e4522c35$var$selectLocale(strings, locale) { | ||
// If there is an exact match, use it. | ||
if (strings[locale]) { | ||
return strings[locale]; | ||
} // Attempt to find the closest match by language. | ||
// For example, if the locale is fr-CA (French Canadian), but there is only | ||
// an fr-FR (France) set of strings, use that. | ||
let language = $f58d206cee90f9c2bf3c03e4522c35$var$getLanguage(locale); | ||
for (let key in strings) { | ||
if (key.startsWith(language + '-')) { | ||
return strings[key]; | ||
} | ||
} // Nothing close, use english. | ||
return strings['en-US']; | ||
} | ||
function $f58d206cee90f9c2bf3c03e4522c35$var$getLanguage(locale) { | ||
// @ts-ignore | ||
if (Intl.Locale) { | ||
// @ts-ignore | ||
return new Intl.Locale(locale).language; | ||
} | ||
return locale.split('-')[0]; | ||
} | ||
let $b0007c63a64054c318efb8b6cd0053f$var$formatterCache = new Map(); | ||
@@ -263,45 +174,2 @@ /** | ||
/** | ||
* Provides localized number parsing for the current locale. | ||
* Idea from https://observablehq.com/@mbostock/localized-number-parsing. | ||
*/ | ||
export function useNumberParser() { | ||
let { | ||
locale | ||
} = useLocale(); | ||
const numberData = useRef({ | ||
group: null, | ||
decimal: null, | ||
numeral: null, | ||
index: null | ||
}); | ||
useEffect(() => { | ||
const parts = new Intl.NumberFormat(locale).formatToParts(12345.6); | ||
const numerals = [...new Intl.NumberFormat(locale, { | ||
useGrouping: false | ||
}).format(9876543210)].reverse(); | ||
const index = new Map(numerals.map((d, i) => [d, i])); | ||
numberData.current.group = new RegExp("[" + parts.find(d => d.type === 'group').value + "]", 'g'); | ||
numberData.current.decimal = new RegExp("[" + parts.find(d => d.type === 'decimal').value + "]"); | ||
numberData.current.numeral = new RegExp("[" + numerals.join('') + "]", 'g'); | ||
numberData.current.index = d => index.get(d); | ||
}, [locale]); | ||
const parse = useCallback(value => { | ||
value = value.trim().replace(numberData.current.group, '').replace(numberData.current.decimal, '.').replace(numberData.current.numeral, numberData.current.index); | ||
return value ? +value : NaN; | ||
}, []); | ||
return { | ||
parse | ||
}; | ||
} | ||
let $ece3e138e83d330f42860705a2ec18a$var$formatterCache = new Map(); | ||
let $ece3e138e83d330f42860705a2ec18a$var$supportsSignDisplay = false; | ||
try { | ||
// @ts-ignore | ||
$ece3e138e83d330f42860705a2ec18a$var$supportsSignDisplay = new Intl.NumberFormat('de-DE', { | ||
signDisplay: 'exceptZero' | ||
}).resolvedOptions().signDisplay === 'exceptZero'; // eslint-disable-next-line no-empty | ||
} catch (e) {} | ||
/** | ||
* Provides localized number formatting for the current locale. Automatically updates when the locale changes, | ||
@@ -311,30 +179,11 @@ * and handles caching of the number formatter for performance. | ||
*/ | ||
export function useNumberFormatter(options) { | ||
if (options === void 0) { | ||
options = {}; | ||
} | ||
export function useNumberFormatter(options) { | ||
let { | ||
locale | ||
} = useLocale(); | ||
let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : ''); | ||
if ($ece3e138e83d330f42860705a2ec18a$var$formatterCache.has(cacheKey)) { | ||
return $ece3e138e83d330f42860705a2ec18a$var$formatterCache.get(cacheKey); | ||
} | ||
let numberFormatter = new Intl.NumberFormat(locale, options); // @ts-ignore | ||
let { | ||
signDisplay | ||
} = options || {}; | ||
$ece3e138e83d330f42860705a2ec18a$var$formatterCache.set(cacheKey, !$ece3e138e83d330f42860705a2ec18a$var$supportsSignDisplay && signDisplay != null ? new Proxy(numberFormatter, { | ||
get(target, property) { | ||
if (property === 'format') { | ||
return v => $d26e725ad56fbcb2c25f52b7de27$export$numberFormatSignDisplayPolyfill(numberFormatter, signDisplay, v); | ||
} else { | ||
return target[property]; | ||
} | ||
} | ||
}) : numberFormatter); | ||
return numberFormatter; | ||
return useMemo(() => new NumberFormatter(locale, options), [locale, options]); | ||
} | ||
@@ -341,0 +190,0 @@ let $a4045a18d7252bf6de9312e613c4e$var$cache = new Map(); |
import { Direction } from "@react-types/shared"; | ||
import { ReactNode } from "react"; | ||
import { LocalizedStrings } from "@internationalized/message"; | ||
import { NumberFormatOptions } from "@internationalized/number"; | ||
interface Locale { | ||
@@ -23,7 +25,2 @@ /** The [BCP47](https://www.ietf.org/rfc/bcp/bcp47.txt) language code for the locale. */ | ||
export function useLocale(): Locale; | ||
type MessageFormatterStrings = { | ||
[lang: string]: { | ||
[key: string]: string; | ||
}; | ||
}; | ||
type FormatMessage = (key: string, variables?: { | ||
@@ -37,3 +34,3 @@ [key: string]: any; | ||
*/ | ||
export function useMessageFormatter(strings: MessageFormatterStrings): FormatMessage; | ||
export function useMessageFormatter(strings: LocalizedStrings): FormatMessage; | ||
/** | ||
@@ -45,11 +42,3 @@ * Provides localized date formatting for the current locale. Automatically updates when the locale changes, | ||
export function useDateFormatter(options?: Intl.DateTimeFormatOptions): Intl.DateTimeFormat; | ||
type NumberParser = { | ||
parse: (value: string) => number; | ||
}; | ||
/** | ||
* Provides localized number parsing for the current locale. | ||
* Idea from https://observablehq.com/@mbostock/localized-number-parsing. | ||
*/ | ||
export function useNumberParser(): NumberParser; | ||
/** | ||
* Provides localized number formatting for the current locale. Automatically updates when the locale changes, | ||
@@ -59,3 +48,3 @@ * and handles caching of the number formatter for performance. | ||
*/ | ||
export function useNumberFormatter(options?: Intl.NumberFormatOptions): Intl.NumberFormat; | ||
export function useNumberFormatter(options?: NumberFormatOptions): Intl.NumberFormat; | ||
/** | ||
@@ -62,0 +51,0 @@ * Provides localized string collation for the current locale. Automatically updates when the locale changes, |
{ | ||
"name": "@react-aria/i18n", | ||
"version": "3.2.0", | ||
"version": "3.3.0", | ||
"description": "Spectrum UI components in React", | ||
@@ -21,5 +21,7 @@ "license": "Apache-2.0", | ||
"@babel/runtime": "^7.6.2", | ||
"@internationalized/message": "3.0.0-alpha.0", | ||
"@internationalized/number": "3.0.0-alpha.0", | ||
"@react-aria/ssr": "^3.0.1", | ||
"@react-types/shared": "^3.3.0", | ||
"intl-messageformat": "^2.2.0" | ||
"@react-aria/utils": "^3.6.0", | ||
"@react-types/shared": "^3.4.0" | ||
}, | ||
@@ -32,3 +34,3 @@ "peerDependencies": { | ||
}, | ||
"gitHead": "f5b429ee8615248f2e3c76754bad2ece83f1c444" | ||
"gitHead": "7f9dc7fa5144679d2dc733170cb5c1f40d0c5ee5" | ||
} |
@@ -13,8 +13,9 @@ /* | ||
/// <reference types="intl-types-extension" /> | ||
export * from './context'; | ||
export * from './useMessageFormatter'; | ||
export * from './useDateFormatter'; | ||
export * from './useNumberParser'; | ||
export * from './useNumberFormatter'; | ||
export * from './useCollator'; | ||
export * from './useFilter'; |
@@ -13,15 +13,19 @@ /* | ||
import IntlMessageFormat from 'intl-messageformat'; | ||
import {LocalizedStrings, MessageDictionary, MessageFormatter} from '@internationalized/message'; | ||
import {useCallback, useMemo} from 'react'; | ||
import {useLocale} from './context'; | ||
type MessageFormatterStrings = { | ||
[lang: string]: { | ||
[key: string]: string | ||
type FormatMessage = (key: string, variables?: {[key: string]: any}) => string; | ||
const cache = new WeakMap(); | ||
function getCachedDictionary(strings: LocalizedStrings) { | ||
let dictionary = cache.get(strings); | ||
if (!dictionary) { | ||
dictionary = new MessageDictionary(strings); | ||
cache.set(strings, dictionary); | ||
} | ||
}; | ||
type FormatMessage = (key: string, variables?: {[key: string]: any}) => string; | ||
return dictionary; | ||
} | ||
const formatterCache = new Map(); | ||
/** | ||
@@ -32,69 +36,7 @@ * Handles formatting ICU Message strings to create localized strings for the current locale. | ||
*/ | ||
export function useMessageFormatter(strings: MessageFormatterStrings): FormatMessage { | ||
let {locale: currentLocale} = useLocale(); | ||
// Check the cache | ||
let localeCache = formatterCache.get(strings); | ||
if (localeCache && localeCache.has(currentLocale)) { | ||
return localeCache.get(currentLocale); | ||
} | ||
// Add to the formatter cache if needed | ||
if (!localeCache) { | ||
localeCache = new Map(); | ||
formatterCache.set(strings, localeCache); | ||
} | ||
// Get the strings for the current locale | ||
let localeStrings = selectLocale(strings, currentLocale); | ||
// Create a new message formatter | ||
let cache = {}; | ||
let formatMessage = (key, variables) => { | ||
let message = cache[key + '.' + currentLocale]; | ||
if (!message) { | ||
let msg = localeStrings[key]; | ||
if (!msg) { | ||
throw new Error(`Could not find intl message ${key} in ${currentLocale} locale`); | ||
} | ||
message = new IntlMessageFormat(msg, currentLocale); | ||
cache[key] = message; | ||
} | ||
return message.format(variables); | ||
}; | ||
localeCache.set(currentLocale, formatMessage); | ||
return formatMessage; | ||
export function useMessageFormatter(strings: LocalizedStrings): FormatMessage { | ||
let {locale} = useLocale(); | ||
let dictionary = useMemo(() => getCachedDictionary(strings), [strings]); | ||
let formatter = useMemo(() => new MessageFormatter(locale, dictionary), [locale, dictionary]); | ||
return useCallback((key, variables) => formatter.format(key, variables), [formatter]); | ||
} | ||
function selectLocale(strings, locale) { | ||
// If there is an exact match, use it. | ||
if (strings[locale]) { | ||
return strings[locale]; | ||
} | ||
// Attempt to find the closest match by language. | ||
// For example, if the locale is fr-CA (French Canadian), but there is only | ||
// an fr-FR (France) set of strings, use that. | ||
let language = getLanguage(locale); | ||
for (let key in strings) { | ||
if (key.startsWith(language + '-')) { | ||
return strings[key]; | ||
} | ||
} | ||
// Nothing close, use english. | ||
return strings['en-US']; | ||
} | ||
function getLanguage(locale) { | ||
// @ts-ignore | ||
if (Intl.Locale) { | ||
// @ts-ignore | ||
return new Intl.Locale(locale).language; | ||
} | ||
return locale.split('-')[0]; | ||
} |
@@ -13,14 +13,6 @@ /* | ||
import {numberFormatSignDisplayPolyfill} from './utils'; | ||
import {NumberFormatOptions, NumberFormatter} from '@internationalized/number'; | ||
import {useLocale} from './context'; | ||
import {useMemo} from 'react'; | ||
let formatterCache = new Map<string, Intl.NumberFormat>(); | ||
let supportsSignDisplay = false; | ||
try { | ||
// @ts-ignore | ||
supportsSignDisplay = (new Intl.NumberFormat('de-DE', {signDisplay: 'exceptZero'})).resolvedOptions().signDisplay === 'exceptZero'; | ||
// eslint-disable-next-line no-empty | ||
} catch (e) {} | ||
/** | ||
@@ -31,23 +23,5 @@ * Provides localized number formatting for the current locale. Automatically updates when the locale changes, | ||
*/ | ||
export function useNumberFormatter(options?: Intl.NumberFormatOptions): Intl.NumberFormat { | ||
export function useNumberFormatter(options: NumberFormatOptions = {}): Intl.NumberFormat { | ||
let {locale} = useLocale(); | ||
let cacheKey = locale + (options ? Object.entries(options).sort((a, b) => a[0] < b[0] ? -1 : 1).join() : ''); | ||
if (formatterCache.has(cacheKey)) { | ||
return formatterCache.get(cacheKey); | ||
} | ||
let numberFormatter = new Intl.NumberFormat(locale, options); | ||
// @ts-ignore | ||
let {signDisplay} = options || {}; | ||
formatterCache.set(cacheKey, (!supportsSignDisplay && signDisplay != null) ? new Proxy(numberFormatter, { | ||
get(target, property) { | ||
if (property === 'format') { | ||
return (v) => numberFormatSignDisplayPolyfill(numberFormatter, signDisplay, v); | ||
} else { | ||
return target[property]; | ||
} | ||
} | ||
}) : numberFormatter); | ||
return numberFormatter; | ||
return useMemo(() => new NumberFormatter(locale, options), [locale, options]); | ||
} |
@@ -34,34 +34,1 @@ /* | ||
} | ||
export function numberFormatSignDisplayPolyfill(numberFormat: Intl.NumberFormat, signDisplay: 'always' | 'exceptZero' | 'auto' | 'never', num: number) { | ||
if (signDisplay === 'auto') { | ||
return numberFormat.format(num); | ||
} else if (signDisplay === 'never') { | ||
return numberFormat.format(Math.abs(num)); | ||
} else { | ||
let needsPositiveSign = false; | ||
if (signDisplay === 'always') { | ||
needsPositiveSign = num > 0 || Object.is(num, 0); | ||
} else if (signDisplay === 'exceptZero') { | ||
if (Object.is(num, -0) || Object.is(num, 0)) { | ||
num = Math.abs(num); | ||
} else { | ||
needsPositiveSign = num > 0; | ||
} | ||
} | ||
if (needsPositiveSign) { | ||
let negative = numberFormat.format(-num); | ||
let noSign = numberFormat.format(num); | ||
// ignore RTL/LTR marker character | ||
let minus = negative.replace(noSign, '').replace(/\u200e|\u061C/, ''); | ||
if ([...minus].length !== 1) { | ||
console.warn('@react-aria/i18n polyfill for NumberFormat signDisplay: Unsupported case'); | ||
} | ||
let positive = negative.replace(noSign, '!!!').replace(minus, '+').replace('!!!', noSign); | ||
return positive; | ||
} else { | ||
return numberFormat.format(num); | ||
} | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
96872
7
18
872
+ Added@react-aria/utils@^3.6.0
+ Added@internationalized/message@3.0.0-alpha.0(transitive)
+ Added@internationalized/number@3.0.0-alpha.0(transitive)
+ Added@react-aria/utils@3.25.3(transitive)
+ Added@react-stately/utils@3.10.4(transitive)
+ Addedclsx@2.1.1(transitive)
- Removedintl-messageformat@^2.2.0
Updated@react-types/shared@^3.4.0