Skip to content

Commit

Permalink
⚡ improvement(numberformat): Explicit number format options (#305) by @…
Browse files Browse the repository at this point in the history
…bponomarenko

* docs: fixed documentation

* feat: add optional explicit number format options
  • Loading branch information
bponomarenko authored and kazupon committed Mar 9, 2018
1 parent acd498f commit aa07450
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 23 deletions.
38 changes: 27 additions & 11 deletions gitbook/en/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

- **Type:** `I18nOptions`

Component based localization option.
Component based localization option.

- **See also:** [`VueI18n` class constructor options](#constructor-options)

Expand Down Expand Up @@ -59,7 +59,7 @@

- **Return:** `DateTimeFormatResult`

Localize the datetime of `value` with datetime format of `key`. The datetime format of `key` need to register to `dateTimeFormats` option of `VueI18n` class, and depend on `locale` option of `VueI18n` constructor. If you will specify `locale` argument, Localized in preferentially it than `locale` option of `VueI18n` constructor.
Localize the datetime of `value` with datetime format of `key`. The datetime format of `key` need to register to `dateTimeFormats` option of `VueI18n` class, and depend on `locale` option of `VueI18n` constructor. If you will specify `locale` argument, it will have priority over `locale` option of `VueI18n` constructor.

If the datetime format of `key` not exist in `dateTimeFormats` option, fallback to depened on `fallbackLocale` option of `VueI18n` constructor.

Expand All @@ -70,14 +70,30 @@
- **Arguments:**
- `{number} value`: required
- `{Path | Object} key`: optional
- `{Locale | Object} locale`: optional
- `{Locale} locale`: optional

- **Return:** `NumberFormatResult`

Localize the number of `value` with number format of `key`. The number format of `key` need to register to `numberFormats` option of `VueI18n` class, and depend on `locale` option of `VueI18n` constructor. If you will specify `locale` argument, Localized in preferentially it than `locale` option of `VueI18n` constructor.
Localize the number of `value` with number format of `key`. The number format of `key` need to register to `numberFormats` option of `VueI18n` class, and depend on `locale` option of `VueI18n` constructor. If you will specify `locale` argument, it will have priority over `locale` option of `VueI18n` constructor.

If the number format of `key` not exist in `numberFormats` option, fallback to depened on `fallbackLocale` option of `VueI18n` constructor.

If the second `key` argument specified as an object, it should have the following properties:
- `key {Path}`: optional, number format
- `locale {Locale}`: optional, locale
- `style {string}`: optional, number format option
- `currency {string}`: optional, number format option
- `currencyDisplay {string}`: optional, number format option
- `useGrouping {string}`: optional, number format option
- `minimumIntegerDigits {string}`: optional, number format option
- `minimumFractionDigits {string}`: optional, number format option
- `maximumFractionDigits {string}`: optional, number format option
- `minimumSignificantDigits {string}`: optional, number format option
- `maximumSignificantDigits {string}`: optional, number format option
- `localeMatcher {string}`: optional, number format option
- `formatMatcher {string}`: optional, number format option

Any specified number format options will have priority over `numberFormats` of `VueI18n` constructor.

### Injected properties

Expand Down Expand Up @@ -310,7 +326,7 @@ You can specify the below some options of `I18nOptions` constructor options of [

Set the locale message of locale.

#### mergeLocaleMessage( locale, message )
#### mergeLocaleMessage( locale, message )

> 6.1+
Expand Down Expand Up @@ -385,7 +401,7 @@ You can specify the below some options of `I18nOptions` constructor options of [

Set the datetime format of locale.

#### mergeDateTimeFormat ( locale, format )
#### mergeDateTimeFormat ( locale, format )

> :new: 7.0+
Expand Down Expand Up @@ -429,7 +445,7 @@ You can specify the below some options of `I18nOptions` constructor options of [

Set the number format of locale.

#### mergeNumberFormat ( locale, format )
#### mergeNumberFormat ( locale, format )

> :new: 7.0+
Expand All @@ -446,7 +462,7 @@ You can specify the below some options of `I18nOptions` constructor options of [
- **Arguments:**
- `{number} value`: required
- `{Path | Object} key`: optional
- `{Locale | Object} locale`: optional
- `{Locale} locale`: optional

- **Return:** `NumberFormatResult`

Expand All @@ -461,7 +477,7 @@ You can specify the below some options of `I18nOptions` constructor options of [
- **Expects:** `string | Object`

- **Details:**

Update the element `textContent` that localized with locale messages. You can use string syntax or object syntax. string syntax can be specified as a keypath of locale messages.
If you can be used object syntax, you need to specify as the object key the following params:

Expand All @@ -472,10 +488,10 @@ You can specify the below some options of `I18nOptions` constructor options of [
- **Examples:**

```html
<!-- string syntax: literal -->
<!-- string syntax: literal -->
<p v-t="'foo.bar'"></p>

<!-- string syntax: binding via data or computed props -->
<!-- string syntax: binding via data or computed props -->
<p v-t="msg"></p>

<!-- object syntax: literal -->
Expand Down
56 changes: 44 additions & 12 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,20 @@ import I18nPath from './path'

import type { PathValue } from './path'

const numberFormatKeys = [
'style',
'currency',
'currencyDisplay',
'useGrouping',
'minimumIntegerDigits',
'minimumFractionDigits',
'maximumFractionDigits',
'minimumSignificantDigits',
'maximumSignificantDigits',
'localeMatcher',
'formatMatcher'
]

export default class VueI18n {
static install: () => void
static version: string
Expand Down Expand Up @@ -441,7 +455,7 @@ export default class VueI18n {
_d (value: number | Date, locale: Locale, key: ?string): DateTimeFormatResult {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !VueI18n.availabilities.dateTimeFormat) {
warn('Cannot format a Date value due to not support Intl.DateTimeFormat.')
warn('Cannot format a Date value due to not supported Intl.DateTimeFormat.')
return ''
}

Expand Down Expand Up @@ -507,7 +521,8 @@ export default class VueI18n {
locale: Locale,
fallback: Locale,
numberFormats: NumberFormats,
key: string
key: string,
options: ?NumberFormatOptions
): ?NumberFormatResult {
let _locale: Locale = locale
let formats: NumberFormat = numberFormats[_locale]
Expand All @@ -525,35 +540,43 @@ export default class VueI18n {
return null
} else {
const format: ?NumberFormatOptions = formats[key]
const id = `${_locale}__${key}`
let formatter = this._numberFormatters[id]
if (!formatter) {
formatter = this._numberFormatters[id] = new Intl.NumberFormat(_locale, format)

let formatter
if (options) {
// If options specified - create one time number formatter
formatter = new Intl.NumberFormat(_locale, Object.assign({}, format, options))
} else {
const id = `${_locale}__${key}`
formatter = this._numberFormatters[id]
if (!formatter) {
formatter = this._numberFormatters[id] = new Intl.NumberFormat(_locale, format)
}
}
return formatter.format(value)
}
}

_n (value: number, locale: Locale, key: ?string): NumberFormatResult {
_n (value: number, locale: Locale, key: ?string, options: ?NumberFormatOptions): NumberFormatResult {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && !VueI18n.availabilities.numberFormat) {
warn('Cannot format a Date value due to not support Intl.NumberFormat.')
warn('Cannot format a Number value due to not supported Intl.NumberFormat.')
return ''
}

if (!key) {
return new Intl.NumberFormat(locale).format(value)
const nf = !options ? new Intl.NumberFormat(locale) : new Intl.NumberFormat(locale, options)
return nf.format(value)
}

const ret: ?NumberFormatResult =
this._localizeNumber(value, locale, this.fallbackLocale, this._getNumberFormats(), key)
this._localizeNumber(value, locale, this.fallbackLocale, this._getNumberFormats(), key, options)
if (this._isFallbackRoot(ret)) {
if (process.env.NODE_ENV !== 'production') {
warn(`Fall back to number localization of root: key '${key}' .`)
}
/* istanbul ignore if */
if (!this._root) { throw Error('unexpected error') }
return this._root.n(value, key, locale)
return this._root.n(value, Object.assign({}, { key, locale }, options))
} else {
return ret || ''
}
Expand All @@ -562,6 +585,7 @@ export default class VueI18n {
n (value: number, ...args: any): NumberFormatResult {
let locale: Locale = this.locale
let key: ?string = null
let options: ?NumberFormatOptions = null

if (args.length === 1) {
if (typeof args[0] === 'string') {
Expand All @@ -573,6 +597,14 @@ export default class VueI18n {
if (args[0].key) {
key = args[0].key
}

// Filter out number format options only
options = Object.keys(args[0]).reduce((acc, key) => {
if (numberFormatKeys.includes(key)) {
return Object.assign({}, acc, { [key]: args[0][key] })
}
return acc
}, null)
}
} else if (args.length === 2) {
if (typeof args[0] === 'string') {
Expand All @@ -583,7 +615,7 @@ export default class VueI18n {
}
}

return this._n(value, locale, key)
return this._n(value, locale, key, options)
}
}

Expand Down
24 changes: 24 additions & 0 deletions test/unit/basic.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,30 @@ describe('basic', () => {
})
})

describe('explicit options argument', () => {
describe('without key', () => {
it('should be formatted', () => {
assert.equal(i18n.n(money, { style: 'currency', currency: 'JPY' }), '¥10,100')
})

it('should respect other number options', () => {
const options = { style: 'currency', currency: 'EUR', currencyDisplay: 'code' }
assert.equal(i18n.n(money, options), 'EUR10,100.00')
})
})

describe('with key', () => {
it('should be formatted', () => {
assert.equal(i18n.n(money, { key: 'currency', currency: 'JPY' }), '¥10,100')
})

it('should respect other number options', () => {
const options = { key: 'currency', currency: 'EUR', currencyDisplay: 'code' }
assert.equal(i18n.n(money, options), 'EUR10,100.00')
})
})
})

describe('fallback', () => {
it('should be formatted', () => {
assert.equal(i18n.n(0.9, 'percent'), '90%')
Expand Down

0 comments on commit aa07450

Please sign in to comment.