( locale: string, formatter: Intl.NumberFormat, intlOptions: Intl.ResolvedNumberFormatOptions, originalOptions: Intl.NumberFormatOptions )
| 328 | const pluralNumbers = [0, 4, 2, 1, 11, 20, 3, 7, 100, 21, 0.1, 1.1]; |
| 329 | |
| 330 | function getSymbols( |
| 331 | locale: string, |
| 332 | formatter: Intl.NumberFormat, |
| 333 | intlOptions: Intl.ResolvedNumberFormatOptions, |
| 334 | originalOptions: Intl.NumberFormatOptions |
| 335 | ): Symbols { |
| 336 | // formatter needs access to all decimal places in order to generate the correct literal strings for the plural set |
| 337 | let symbolFormatter = new Intl.NumberFormat(locale, { |
| 338 | ...intlOptions, |
| 339 | // Resets so we get the full range of symbols |
| 340 | minimumSignificantDigits: 1, |
| 341 | maximumSignificantDigits: 21, |
| 342 | roundingIncrement: 1, |
| 343 | roundingPriority: 'auto', |
| 344 | roundingMode: 'halfExpand', |
| 345 | useGrouping: true |
| 346 | }); |
| 347 | // Note: some locale's don't add a group symbol until there is a ten thousands place |
| 348 | let allParts = symbolFormatter.formatToParts(-10000.111); |
| 349 | let posAllParts = symbolFormatter.formatToParts(10000.111); |
| 350 | let pluralParts = pluralNumbers.map(n => symbolFormatter.formatToParts(n)); |
| 351 | // if the plural parts include a unit but no integer or fraction, then we need to add the unit to the special set |
| 352 | let noNumeralUnits = pluralParts |
| 353 | .map((p, i) => { |
| 354 | let unit = p.find(p => p.type === 'unit'); |
| 355 | if (unit && !p.some(p => p.type === 'integer' || p.type === 'fraction')) { |
| 356 | return {unit: unit.value, value: pluralNumbers[i]}; |
| 357 | } |
| 358 | return null; |
| 359 | }) |
| 360 | .filter(p => !!p); |
| 361 | |
| 362 | let minusSign = allParts.find(p => p.type === 'minusSign')?.value ?? '-'; |
| 363 | let plusSign = posAllParts.find(p => p.type === 'plusSign')?.value; |
| 364 | |
| 365 | // Safari does not support the signDisplay option, but our number parser polyfills it. |
| 366 | // If no plus sign was returned, but the original options contained signDisplay, default to the '+' character. |
| 367 | if ( |
| 368 | !plusSign && |
| 369 | (originalOptions?.signDisplay === 'exceptZero' || originalOptions?.signDisplay === 'always') |
| 370 | ) { |
| 371 | plusSign = '+'; |
| 372 | } |
| 373 | |
| 374 | // If maximumSignificantDigits is 1 (the minimum) then we won't get decimal characters out of the above formatters |
| 375 | // Percent also defaults to 0 fractionDigits, so we need to make a new one that isn't percent to get an accurate decimal |
| 376 | let decimalParts = new Intl.NumberFormat(locale, { |
| 377 | ...intlOptions, |
| 378 | minimumFractionDigits: 2, |
| 379 | maximumFractionDigits: 2 |
| 380 | }).formatToParts(0.001); |
| 381 | |
| 382 | let decimal = decimalParts.find(p => p.type === 'decimal')?.value; |
| 383 | let group = allParts.find(p => p.type === 'group')?.value; |
| 384 | |
| 385 | // this set is also for a regex, it's all literals that might be in the string we want to eventually parse that |
| 386 | // don't contribute to the numerical value |
| 387 | let allPartsLiterals = allParts |
no test coverage detected