Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Explicit number format options #305

Merged
merged 2 commits into from
Mar 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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