vue-i18n
vue-i18n copied to clipboard
`part` option for `n` fails with an error
Reporting a bug?
Using part
option for number formatter throws an error. JSfiddle below.
Example usage:
const i18n = createI18n({
locale: 'en',
legacy: false,
numberFormats: {
en: {
currency: {
style: 'currency',
currencyDisplay: 'narrowSymbol',
},
}
})
const { n } = useI18n()
const parts = n(100, { key: 'currency', part: true, currency: 'USD' })
Expected behavior
- not to throw error
- return an array of parts, so have the same return signature as Intl.NumberFormatter.prototype.formatToParts
Reproduction
https://jsfiddle.net/qagtkzxj/39/
System Info
System:
OS: macOS 12.5.1
CPU: (8) arm64 Apple M1
Memory: 80.39 MB / 8.00 GB
Shell: 5.8.1 - /bin/zsh
Binaries:
Node: 16.16.0 - ~/.nvm/versions/node/v16.16.0/bin/node
Yarn: 1.22.18 - /opt/homebrew/bin/yarn
npm: 8.11.0 - ~/.nvm/versions/node/v16.16.0/bin/npm
Browsers:
Chrome: 104.0.5112.101
Firefox: 94.0.2
Firefox Developer Edition: 105.0
Safari: 15.6.1
npmPackages:
vue: ^3.2.36 => 3.2.37
vue-chartjs: ^4.1.1 => 4.1.1
vue-i18n: ^9.2.2 => 9.2.2
vue-router: ^4.1.5 => 4.1.5
Screenshot
No response
Additional context
No response
Validations
- [X] Read the Contributing Guidelines
- [X] Read the Documentation
- [X] Check that there isn't already an issue that reports the same bug to avoid creating a duplicate.
- [X] Check that this is a concrete bug. For Q&A open a GitHub Discussion
- [X] The provided reproduction is a minimal reproducible example of the bug.
Thank you for your reporting!
We cannot use the part
option with n
.
api docs said, n
returns only string type.
- n: https://vue-i18n.intlify.dev/api/composition.html#n
- about details for some overloads: https://vue-i18n.intlify.dev/api/composition.html#composernumberformatting
if you would like to use Intl.NumberFormatter.prototype.formatToParts
, you need to use the Number format component i18n-n
.
https://vue-i18n.intlify.dev/guide/essentials/number.html#custom-formatting
I would like to know the use case why you would like to use formatToParts
and equivalent in n
.
Maybe, it’s useful for everyone else as well.
Hi, @kazupon !
Thanks for replying!
My use case is the following:
We are working with high-precision numbers in my project. Precision sometimes goes up to 18 fractional digits.
So I can have a value = 0.0123456789012345678
. JS is not capable of working with precision over 15 digits. So even declaring such value const value = ...
and then logging it console.log(value)
will log a rounded number - some precision will be lost. Something similar is actually happening when passing such precise numbers from BE to FE (or vice versa) using JSON.
We have decided that BE will provide to the FE such values as strings. And FE would have to display them to users localised. This is where i18n comes into play.
Obviously I can not pass strings to n
and passing string directly to Intl.NumberFormat
converts them to number
first under the hood. So the precision is lost again.
My idea was to do something along the lines of
const customFormatter = (value: string) => {
const asNumber = Number(value) // so precision is lost, but it's OK
const asParts = n(asNumber, { key: 'myNumberFormat', part: true })
const jsonDecimalSeparator = '.' // decimal separator used by my BE for numbers-as-string
const separatorIndex = value.indexOf(jsonDecimalSeparator) // index of a separator in the original string
const preciseInteger: string = value.slice(0, separatorIndex) // precise integer part as string
const preciseFraction: string = value.slice(separatorIndex + jsonDecimalSeparator.length, value.length) // precise fraction part as string
// here is the "clever" part - replacing parts of formatted number with their respective precise values
const asPrecisePartsFlattened = asParts.map(part => {
if (part.type === 'integer') return preciseInteger
if (part.type === 'fractions') return preciseFraction
return part.value
})
return asPrecisePartsFlattened.join('') // return a formatted string
}
This can obviously be extended to add reactivity, support for whole-integer numbers, different formats, etc.
Actually, while writing this, it got me thinking that folks working with (not-yet) supported currencies - e.g. cryptos of all sorts - could also benefit from this.
const customCurrencies = ['Crypto1, Crypto2']
const customFormat = (value: number, currency: string) => {
if (!customCurrencies.includes(currency)) return n(value, { key: 'currencyFormat', currency })
const asParts = n(value, { key: 'currencyFormat', currency: 'USD' }) // using USD to not cause Intl error
return asParts
.map(part => {
if (part.type !== 'currency') return part
return {
...part
value: currency // replacing USD to our custom currency
}
})
.map(part => part.value) // flatten - collect parts values together
.join('') // return a formatted string
}
Thanks for your detail use-case!
It helps me understand your use case.
I will try to support formatToParts
in n
.