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

fix: bring bug fixes from v9.2.0-beta.11 #720

Merged
merged 2 commits into from
Oct 4, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 7 additions & 12 deletions packages/message-compiler/src/tokenizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,45 +438,40 @@ export function createTokenizer(
}

function readText(scnr: Scanner): string {
const fn = (buf: string): string => {
let buf = ''
while (true) {
const ch = scnr.currentChar()
if (
ch === TokenChars.BraceLeft ||
ch === TokenChars.BraceRight ||
ch === TokenChars.LinkedAlias ||
ch === TokenChars.Pipe ||
!ch
) {
return buf
break
} else if (ch === TokenChars.Modulo) {
if (isTextStart(scnr)) {
buf += ch
scnr.next()
return fn(buf)
} else {
return buf
break
}
} else if (ch === TokenChars.Pipe) {
return buf
} else if (ch === SPACE || ch === NEW_LINE) {
if (isTextStart(scnr)) {
buf += ch
scnr.next()
return fn(buf)
} else if (isPluralStart(scnr)) {
return buf
break
} else {
buf += ch
scnr.next()
return fn(buf)
}
} else {
buf += ch
scnr.next()
return fn(buf)
}
}

return fn('')
return buf
}

function readNamedIdentifier(scnr: Scanner): string {
Expand Down

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions packages/message-compiler/test/tokenizer.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { parse } from '../src/tokenizer'
import { TokenizeOptions } from '../src/options'
import { CompileError } from '../src/errors'
import path from 'path'
import { promises as fs } from 'fs'

test('token analysis', () => {
const cases = [
Expand Down Expand Up @@ -98,3 +100,20 @@ test('token analysis', () => {
}
}
})

describe('edge cases', () => {
test('long text', async () => {
const data = await fs.readFile(
path.join(__dirname, './fixtures/20_newsgroups_alt_atheism_51060.txt'),
'utf8'
)
let err = null
try {
parse(data)
} catch (e) {
console.error(e)
err = e
}
expect(err).toEqual(null)
})
})
3 changes: 2 additions & 1 deletion packages/vue-i18n/src/components/DatetimeFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ export const DatetimeFormat = {
setup(props: DatetimeFormatProps, context: SetupContext): RenderFunction {
const i18n =
props.i18n ||
(useI18n({ useScope: 'parent' }) as Composer & ComposerInternal)
(useI18n({ useScope: 'parent', __useComponent: true }) as Composer &
ComposerInternal)

return renderFormatter<
FormattableProps<number | Date, Intl.DateTimeFormatOptions>,
Expand Down
3 changes: 2 additions & 1 deletion packages/vue-i18n/src/components/NumberFormat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ export const NumberFormat = {
setup(props: NumberFormatProps, context: SetupContext): RenderFunction {
const i18n =
props.i18n ||
(useI18n({ useScope: 'parent' }) as Composer & ComposerInternal)
(useI18n({ useScope: 'parent', __useComponent: true }) as Composer &
ComposerInternal)

return renderFormatter<
FormattableProps<number, Intl.NumberFormatOptions>,
Expand Down
5 changes: 4 additions & 1 deletion packages/vue-i18n/src/components/Translation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ export const Translation = {
const { slots, attrs } = context
const i18n =
props.i18n ||
(useI18n({ useScope: props.scope }) as Composer & ComposerInternal)
(useI18n({
useScope: props.scope as 'global' | 'parent',
__useComponent: true
}) as Composer & ComposerInternal)
const keys = Object.keys(slots).filter(key => key !== '_')

return (): VNodeChild => {
Expand Down
5 changes: 4 additions & 1 deletion packages/vue-i18n/src/composer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ export const EnableEmitter = makeSymbol('__enableEmitter')
export const DisableEmitter = makeSymbol('__disableEmitter')
export const SetPluralRulesSymbol = makeSymbol('__setPluralRules')
export const DevToolsMetaSymbol = makeSymbol('__intlifyMeta')
export const InejctWithOption = makeSymbol('__injectWithOption')

/** @VueI18nComposition */
export type VueMessageType = string | VNode
Expand Down Expand Up @@ -326,6 +327,7 @@ export interface ComposerInternalOptions<
__i18n?: CustomBlocks<Message>
__i18nGlobal?: CustomBlocks<Message>
__root?: Composer<Messages, DateTimeFormats, NumberFormats, Message>
__injectWithOption?: boolean
}

/**
Expand Down Expand Up @@ -1862,7 +1864,8 @@ export function createComposer<
[TransrateVNodeSymbol]: transrateVNode,
[NumberPartsSymbol]: numberParts,
[DatetimePartsSymbol]: datetimeParts,
[SetPluralRulesSymbol]: setPluralRules
[SetPluralRulesSymbol]: setPluralRules,
[InejctWithOption]: (options as any).__injectWithOption // eslint-disable-line @typescript-eslint/no-explicit-any
}

// for vue-devtools timeline event
Expand Down
13 changes: 10 additions & 3 deletions packages/vue-i18n/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import {
getLocaleMessages,
createComposer,
EnableEmitter,
DisableEmitter
DisableEmitter,
InejctWithOption
} from './composer'
import { createVueI18n } from './legacy'
import { I18nWarnCodes, getWarnMessage } from './warnings'
Expand Down Expand Up @@ -598,7 +599,8 @@ export function useI18n<
}

if (scope === 'parent') {
let composer = getComposer(i18n, instance)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let composer = getComposer(i18n, instance, (options as any).__useComponent)
if (composer == null) {
if (__DEV__) {
warn(getWarnMessage(I18nWarnCodes.NOT_FOUND_PARENT_SCOPE))
Expand Down Expand Up @@ -666,7 +668,8 @@ function getComposer<
Legacy extends boolean
>(
i18n: I18n<Messages, DateTimeFormats, NumberFormats, Legacy>,
target: ComponentInternalInstance
target: ComponentInternalInstance,
useComponent = false
): Composer<Messages, DateTimeFormats, NumberFormats> | null {
let composer: Composer<Messages, DateTimeFormats, NumberFormats> | null = null
const root = target.root
Expand Down Expand Up @@ -696,6 +699,10 @@ function getComposer<
VueI18nInternal<Messages, DateTimeFormats, NumberFormats>)
.__composer as Composer<Messages, DateTimeFormats, NumberFormats>
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
if (useComponent && !(composer as any)[InejctWithOption]) {
composer = null
}
}
if (composer != null) {
break
Expand Down
5 changes: 3 additions & 2 deletions packages/vue-i18n/src/legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,7 @@ function convertComposerOptions<
return messages
}, (messages || {}) as LocaleMessages<VueMessageType>) as typeof options.messages
}
const { __i18n, __root } = options
const { __i18n, __root, __injectWithOption } = options

const datetimeFormats = options.datetimeFormats
const numberFormats = options.numberFormats
Expand All @@ -1138,7 +1138,8 @@ function convertComposerOptions<
escapeParameter,
inheritLocale,
__i18n,
__root
__root,
__injectWithOption
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/vue-i18n/src/mixin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export function defineMixin<Messages, DateTimeFormats, NumberFormats>(
if (this === this.$root) {
this.$i18n = mergeToRoot(vuei18n, optionsI18n)
} else {
optionsI18n.__injectWithOption = true
this.$i18n = createVueI18n(optionsI18n)
}
} else if (options.__i18n) {
Expand All @@ -60,6 +61,7 @@ export function defineMixin<Messages, DateTimeFormats, NumberFormats>(
} else {
this.$i18n = createVueI18n({
__i18n: (options as ComposerInternalOptions<Messages>).__i18n,
__injectWithOption: true,
__root: composer
} as VueI18nOptions)
}
Expand Down
77 changes: 77 additions & 0 deletions packages/vue-i18n/test/i18n.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -883,3 +883,80 @@ test('Intlify devtools hooking', () => {
expect(fnI18nInit).toHaveBeenCalled()
expect(fnTranslate).toHaveBeenCalled()
})

test('issue #708', async () => {
const messages = {
en: {
message: {
language: 'English',
quantity: 'Quantity',
list: 'hello, {0}!',
named: 'hello, {name}!',
linked: '@:message.named How are you?',
plural: 'no bananas | {n} banana | {n} bananas'
}
},
ja: {
message: {
language: '日本語',
list: 'こんにちは、{0}!',
named: 'こんにちは、{name}!',
linked: '@:message.named ごきげんいかが?'
}
}
}

const i18n = createI18n({
legacy: true,
locale: 'en',
messages
})

const C2 = defineComponent({
template: `<div>C2 slot: <slot></slot></div>`
})

const C1 = defineComponent({
components: {
C2
},
template: `<div>
C1:
<div>{{ $t("hello", { world: $t("world") }) }}</div>
<i18n-t keypath="hello" tag="div">
<template #world>
<strong>{{ $t("world") }}</strong>
</template>
</i18n-t>
<br />
<C2>
<div>{{ $t("hello", { world: $t("world") }) }}</div>
<i18n-t keypath="hello" tag="div">
<template #world>
<strong>{{ $t("world") }}</strong>
</template>
</i18n-t>
</C2>
</div>`,
i18n: {
messages: {
en: {
hello: 'Hello {world}',
world: 'world!'
}
}
}
})

const App = defineComponent({
components: {
C1
},
template: `<C1 />`
})
const wrapper = await mount(App, i18n)

expect(wrapper.html()).toEqual(
`<div> C1: <div>Hello world!</div><div>Hello <strong>world!</strong></div><br><div>C2 slot: <div>Hello world!</div><div>Hello <strong>world!</strong></div></div></div>`
)
})