@react-aria/i18n
Advanced tools
Comparing version
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
96872
-27.58%7
40%18
-5.26%872
-30.74%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
Updated