Skip to content

Commit

Permalink
🐛 bug(index): Add warning for circular reference in linked message (#438
Browse files Browse the repository at this point in the history
) by @exoego

* Add warning for circular reference in linked message.

* Allow non-ascii chars including numbers.

* Circular reference warnings should tell us chain of reference.
  • Loading branch information
TATSUNO Yasuhiro authored and kazupon committed Oct 13, 2018
1 parent acfc458 commit 7583485
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,8 @@ export default class VueI18n {
key: Path,
host: any,
interpolateMode: string,
values: any
values: any,
visitedLinkStack: Array<string>
): any {
if (!message) { return null }

Expand Down Expand Up @@ -234,7 +235,7 @@ export default class VueI18n {

// Check for the existance of links within the translated string
if (ret.indexOf('@:') >= 0) {
ret = this._link(locale, message, ret, host, interpolateMode, values)
ret = this._link(locale, message, ret, host, interpolateMode, values, visitedLinkStack)
}

return this._render(ret, interpolateMode, values)
Expand All @@ -246,7 +247,8 @@ export default class VueI18n {
str: string,
host: any,
interpolateMode: string,
values: any
values: any,
visitedLinkStack: Array<string>
): any {
let ret: string = str

Expand All @@ -263,11 +265,19 @@ export default class VueI18n {
const link: string = matches[idx]
// Remove the leading @: and the brackets
const linkPlaceholder: string = link.substr(2).replace(bracketsMatcher, '')

if (visitedLinkStack.includes(linkPlaceholder)) {
warn(`Circular reference found. "${link}" is already visited in the chain of ${visitedLinkStack.reverse().join(' <- ')}`)
return ret
}
visitedLinkStack.push(linkPlaceholder)

// Translate the link
let translated: any = this._interpolate(
locale, message, linkPlaceholder, host,
interpolateMode === 'raw' ? 'string' : interpolateMode,
interpolateMode === 'raw' ? undefined : values
interpolateMode === 'raw' ? undefined : values,
visitedLinkStack
)

if (this._isFallbackRoot(translated)) {
Expand All @@ -287,6 +297,8 @@ export default class VueI18n {
Array.isArray(values) ? values : [values]
)

visitedLinkStack.pop()

// Replace the link with the translated
ret = !translated ? ret : ret.replace(link, translated)
}
Expand All @@ -311,10 +323,10 @@ export default class VueI18n {
args: any
): any {
let res: any =
this._interpolate(locale, messages[locale], key, host, interpolateMode, args)
this._interpolate(locale, messages[locale], key, host, interpolateMode, args, [key])
if (!isNull(res)) { return res }

res = this._interpolate(fallback, messages[fallback], key, host, interpolateMode, args)
res = this._interpolate(fallback, messages[fallback], key, host, interpolateMode, args, [key])
if (!isNull(res)) {
if (process.env.NODE_ENV !== 'production' && !this._silentTranslationWarn) {
warn(`Fall back to translate the keypath '${key}' with '${fallback}' locale.`)
Expand Down
4 changes: 4 additions & 0 deletions test/unit/fixture/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ export default {
linkHyphen: '@:hyphen-hello',
linkUnderscore: '@:underscore_hello',
linkList: '@:message.hello: {0} {1}',
circular1: 'Foo @:message.circular2',
circular2: 'Bar @:message.circular3',
circular3: 'Buz @:message.circular1',
linkTwice: '@:message.hello: @:message.hello',
'hyphen-locale': 'hello hyphen',
'1234': 'Number-based keys are found',
'1mixedKey': 'Mixed keys are not found.'
Expand Down
18 changes: 18 additions & 0 deletions test/unit/issues.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,24 @@ describe('issues', () => {
})
})

describe('#247', () => {
it('should be warned if circular reference in linked locale message', () => {
const spy = sinon.spy(console, 'warn')
assert.strictEqual(vm.$i18n.t('message.circular1'), 'Foo Bar Buz @:message.circular1')
assert(spy.notCalled === false)
assert(spy.callCount === 1)
spy.restore()
})

it('should not be warned if same non-circular link used repeatedly', () => {
const spy = sinon.spy(console, 'warn')
assert.strictEqual(vm.$i18n.t('message.linkTwice'), 'the world: the world')
assert(spy.notCalled === true)
assert(spy.callCount === 0)
spy.restore()
})
})

describe('#377', () => {
it('should be destroyed', done => {
const el = document.createElement('div')
Expand Down

0 comments on commit 7583485

Please sign in to comment.