Is there a way to achieve what d3 can do with precisionPrefix in the vue-i18n ecosystem?
There is an open issue here.
And I found an old issue for Intl
object here.
Thanks for your help.
Is there a way to achieve what d3 can do with precisionPrefix in the vue-i18n ecosystem?
There is an open issue here.
And I found an old issue for Intl
object here.
Thanks for your help.
One hacky way will be replace VueI18n.n
with your own handler.
add custom property=abbreviate to VueI18n.numberFormats
in order to determinate if apply special style.
save origial VueI18n.n
to VueI18n.n1
(we will still use VueI18n.n1
for other styles)
uses your own handler to replace VueI18n.n
, then inside the handler, check if numberFormatter.abbreviate
is true, if yes, apply your special style (At below demo, simply uses regex expression to implement it).
Like below simple demo:
PS: below I uses one simple regex expression to apply the styles, for some special number format, it may not work, you need to improve it by yourself.
Vue.use(VueI18n)
const numberFormats = {
'en-US': {
currency: {
style: 'currency', currency: 'USD', currencyDisplay: 'symbol', useGrouping: false
}
},
'ja-JP': {
currency: {
style: 'currency', currency: 'JPY', currencyDisplay: 'name',
abbreviate: true, // custom property to determinate whether apply special styles
maximumSignificantDigits: 4, useGrouping: true
}
}
}
const i18n = new VueI18n({
numberFormats
})
i18n.n1 = i18n.n // save default i18n.n to i18n.n1
i18n.n= function (nValue, nStyle) {
let numberFormatter = this.getNumberFormat(this.locale) // get NumberFormat Based on locale
if (numberFormatter[nStyle].abbreviate) { // if custom property is true
let newValue = Math.round(nValue/1000000) // divide 10^6 for millions, divide 10^3 for K .etc
return this.n1(newValue, nStyle).replace(/(\d[\d|,]*)(\.\d+)?/, '$1 $2M')
}
return this.n1(nValue, nStyle) // for others , use default i18n.n to process.
}
Vue.config.productionTip = false
app = new Vue({
el: "#app",
i18n,
data: {
test: 1234567890,
language: 'en-US'
},
computed: {
computedTest: function () {
return this.$n(this.test, 'currency')
}
},
methods: {
toggleLanguage: function () {
this.language = this.language === 'en-US' ? 'ja-JP' : 'en-US'
this.$i18n.locale = this.language
}
}
})
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-i18n/7.8.0/vue-i18n.js"></script>
<div id="app">
<button @click="toggleLanguage()">Language </button>
<p>Language: [{{language}}]</p>
<p>Org: {{test}}</p>
<p>localed: {{computedTest}}</p>
</div>
Edit: another approach: uses D3-format
Vue.use(VueI18n)
const numberFormats = {
'en-US': {
currency: {
style: 'currency', currency: 'USD', currencyDisplay: 'symbol', useGrouping: false
}
},
'ja-JP': {
currency: {
style: 'currency', currency: 'JPY', currencyDisplay: 'name',
abbreviate: true, // custom property to determinate whether apply special styles
maximumSignificantDigits: 4, useGrouping: true
}
}
}
const i18n = new VueI18n({
numberFormats
})
let d3Locales = {}
axios.get('https://unpkg.com/d3-format@1/locale/ja-JP.json')
.then(function (response) {
d3Locales['ja-JP'] = response.data
})
.catch(function (error) {
console.log(error);
});
axios.get('https://unpkg.com/d3-format@1/locale/en-US.json')
.then(function (response) {
d3Locales['en-US'] = response.data
})
.catch(function (error) {
console.log(error);
});
i18n.n1 = i18n.n // save default i18n.n to i18n.n1
i18n.n= function (nValue, nStyle) {
let numberFormatter = this.getNumberFormat(this.locale) // get NumberFormat Based on locale
if (numberFormatter[nStyle].abbreviate) { // if custom property is true
d3.formatDefaultLocale(d3Locales[this.locale])
let p = d3.precisionPrefix(1e4, 1e6),
f = d3.formatPrefix("$." + p, 1e6)
return f(nValue);
}
return this.n1(nValue, nStyle) // for others , use default i18n.n to process.
}
Vue.config.productionTip = false
app = new Vue({
el: "#app",
i18n,
data: {
test: 1234567890,
language: 'en-US'
},
computed: {
computedTest: function () {
return this.$n(this.test, 'currency')
}
},
methods: {
toggleLanguage: function () {
this.language = this.language === 'en-US' ? 'ja-JP' : 'en-US'
this.$i18n.locale = this.language
}
}
})
<script src="https://unpkg.com/vue@2.5.16/dist/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-i18n/7.8.0/vue-i18n.js"></script>
<script src="https://d3js.org/d3-format.v1.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<div id="app">
<button @click="toggleLanguage()">Language </button>
<p>Language: [{{language}}]</p>
<p>Org: {{test}}</p>
<p>localed: {{computedTest}}</p>
</div>
After digging around for a while, I decided to write my own helper methods as the price displaying on my site is quite big so abbreviation is a must. @Sphinx solution seems to be too much effort just for making the number shorter.
I created a utils file and import i18n into it. The idea is from how to convert numbers to million in javascript
//Utils.js
import { i18n } from 'boot/i18n.ts'
export const CURRENCY_CALCULATOR = (price) => {
let abbreviatedPrice = price
if (i18n.locale === 'en-us') {
abbreviatedPrice = Math.abs(Number(price)) >= 1.0e+6
? Math.abs(Number(price)) / 1.0e+6 + "M"
: Math.abs(Number(price)) >= 1.0e+3
? Math.abs(Number(price)) / 1.0e+3 + "K"
: Math.abs(Number(price));
} else {
// Other languages uses different units
abbreviatedPrice = Math.abs(Number(price)) >= 1.0e+4
? Math.abs(Number(price)) / 1.0e+4 + i18n.t('sorting.tenThousands')
: Math.abs(Number(price));
}
// setup currency symbol by yourself, because I use the same symbol for both
return `$ ${abbreviatedPrice}`
}
In your component
<template>
<div class="col-auto">
{{ calculateCurrency(item.price) }}
</div>
</template>
<script>
import { CURRENCY_CALCULATOR } from '../constants/Utils'
export default {
name: '<<component name here>>',
props: ['<<your props here>>']
methods: {
calculateCurrency (price) {
return CURRENCY_CALCULATOR(price)
}
}
}
</script>