Skip to content

Commit

Permalink
⚡ improvement(format): Add the path as argument to the custom formatt…
Browse files Browse the repository at this point in the history
…er (#489) by @Raiondesu

* ⚡improvement(types): typed autocomplete in date and number format options

Replace Number and Date format options with standard TS `Intl` types, while also adding guiding TS autocomplete to them.

This change exterminates the confusion of which types to follow, while preserving backwards-compatibility for types and adding optional autocomplete.

* ⚡improvement(types/test): add type constraints to format options

It's useful to check static variables types whenever possible.

* ⚡new(formatter): add path to the formatter arguments
and allow optional formatting

* ⚡improvement(types): backward-compatibility for #484

* 📃docs(formatter): add case for the undefined return type

* ⚡improvement(types): include the possible undefined return type

* ✅tests(issues): make formatter return undefined in test for #484

* update(formatter): change default foramtter invocation
from undefined to null
  • Loading branch information
Raiondesu authored and kazupon committed Dec 21, 2018
1 parent 439ed69 commit b9437ea
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 8 deletions.
2 changes: 1 addition & 1 deletion decls/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,5 +110,5 @@ declare interface I18n {
};

declare interface Formatter {
interpolate (message: string, values?: any): Array<any>
interpolate (message: string, values: any, path: string): (Array<any> | null)
};
7 changes: 6 additions & 1 deletion gitbook/en/formatting.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,12 +157,17 @@ class CustomFormatter {
// -> passed values: Array (included VNode):
// `[VNode{ tag: 'p', text: 'kazupon', ...}, VNode{ tag: 'p', text: 'how are you?', ...}]`
//
// @param {string} path
// a path to the message, as passed into the $t/t() functions.
// - $t('hello.louis') -> path === 'hello.louis'
//
// @return {Array<any>}
// interpolated values. you need to return the following:
// - array of string, when is using `$t` or `$tc`.
// - array included VNode object, when is using `i18n` functional component.
// - null - if you want the default vue-i18n formatter to handle the case
//
interpolate (message, values) {
interpolate (message, values, path) {
// implement interpolation logic here
// ...

Expand Down
18 changes: 13 additions & 5 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const formatters = {
'lower': (str) => str.toLocaleLowerCase()
}

const defaultFormatter = new BaseFormatter()

export default class VueI18n {
static install: () => void
static version: string
Expand Down Expand Up @@ -76,7 +78,7 @@ export default class VueI18n {
const numberFormats = options.numberFormats || {}

this._vm = null
this._formatter = options.formatter || new BaseFormatter()
this._formatter = options.formatter || defaultFormatter
this._missing = options.missing || null
this._root = options.root || null
this._sync = options.sync === undefined ? true : !!options.sync
Expand Down Expand Up @@ -246,7 +248,7 @@ export default class VueI18n {
ret = this._link(locale, message, ret, host, interpolateMode, values, visitedLinkStack)
}

return this._render(ret, interpolateMode, values)
return this._render(ret, interpolateMode, values, key)
}

_link (
Expand Down Expand Up @@ -322,9 +324,15 @@ export default class VueI18n {
return ret
}

_render (message: string, interpolateMode: string, values: any): any {
const ret = this._formatter.interpolate(message, values)
// if interpolateMode is **not** 'string' ('raw'),
_render (message: string, interpolateMode: string, values: any, path: string): any {
let ret = this._formatter.interpolate(message, values, path)

// If the custom formatter refuses to work - apply the default one
if (!ret) {
ret = defaultFormatter.interpolate(message, values, path)
}

// if interpolateMode is **not** 'string' ('row'),
// return the compiled data (e.g. ['foo', VNode, 'bar']) with formatter
return interpolateMode === 'string' ? ret.join('') : ret
}
Expand Down
28 changes: 28 additions & 0 deletions test/unit/issues.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -630,4 +630,32 @@ describe('issues', () => {
VueI18n.prototype.getChoiceIndex = defaultImpl
})
})

describe('#484', () => {
it('passes path to the formatter', () => {
const testPath = 'test.deep.message'

i18n = new VueI18n({
locale: 'en',
messages: {
en: {
test: {
deep: {
message: 'Hello!'
}
}
}
},
formatter: {
interpolate (message, values, path) {
assert(path, testPath)

return null // pass the case to the default formatter
}
}
})

assert(i18n.t(testPath), 'Hello!')
})
})
})
2 changes: 1 addition & 1 deletion types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ declare namespace VueI18n {
};

interface Formatter {
interpolate(message: string, values?: Values): any[];
interpolate(message: string, values: Values | undefined, path: string): (any[] | null);
}

type MissingHandler = (locale: Locale, key: Path, vm?: Vue) => string | void;
Expand Down

0 comments on commit b9437ea

Please sign in to comment.