diff --git a/packages/vue-i18n-core/src/composer.ts b/packages/vue-i18n-core/src/composer.ts index f696e53aa..8256be2bc 100644 --- a/packages/vue-i18n-core/src/composer.ts +++ b/packages/vue-i18n-core/src/composer.ts @@ -1207,7 +1207,7 @@ export interface ComposerNumberFormatting< | Key | ResourceKeys | NumberOptions - ): string + ): string | Intl.NumberFormatPart[] /** * Number Formatting * @@ -1229,7 +1229,7 @@ export interface ComposerNumberFormatting< | ResourceKeys | NumberOptions, locale: Locales - ): string + ): string | Intl.NumberFormatPart[] } /** @@ -2290,14 +2290,14 @@ export function createComposer(options: any = {}): any { } // n - function n(...args: unknown[]): string { - return wrapWithDeps<{}, string>( - context => Reflect.apply(number, null, [context, ...args]) as string, + function n(...args: unknown[]): string | Intl.NumberFormatPart[] { + return wrapWithDeps<{}, string | Intl.NumberFormatPart[]>( + context => Reflect.apply(number, null, [context, ...args]), () => parseNumberArgs(...args), 'number format', root => Reflect.apply(root.n, root, [...args]), () => MISSING_RESOLVE_VALUE, - val => isString(val) + val => isString(val) || isArray(val) ) } diff --git a/packages/vue-i18n-core/test/composer.test-d.ts b/packages/vue-i18n-core/test/composer.test-d.ts index 1e05f5461..97d0f156a 100644 --- a/packages/vue-i18n-core/test/composer.test-d.ts +++ b/packages/vue-i18n-core/test/composer.test-d.ts @@ -353,15 +353,15 @@ test('strict composer with direct options', () => { strictDirectComposer.d(new Date(), 'custom' as any) ).toEqualTypeOf() expectTypeOf(strictDirectComposer.n(1)).toEqualTypeOf() - expectTypeOf( - strictDirectComposer.n(1, 'currency', 'zh') - ).toEqualTypeOf() + expectTypeOf(strictDirectComposer.n(1, 'currency', 'zh')).toEqualTypeOf< + string | Intl.NumberFormatPart[] + >() expectTypeOf( strictDirectComposer.n(1, { key: 'currency', locale: 'en' }) - ).toEqualTypeOf() - expectTypeOf( - strictDirectComposer.n(1, 'custom' as any) - ).toEqualTypeOf() + ).toEqualTypeOf() + expectTypeOf(strictDirectComposer.n(1, 'custom' as any)).toEqualTypeOf< + string | Intl.NumberFormatPart[] + >() // const noOptionsComposer = createComposer({ missingWarn: true }) const noOptionsComposer = createComposer({ locale: 'en' }) diff --git a/packages/vue-i18n-core/test/composer.test.ts b/packages/vue-i18n-core/test/composer.test.ts index 59ff15c30..b7a712bf8 100644 --- a/packages/vue-i18n-core/test/composer.test.ts +++ b/packages/vue-i18n-core/test/composer.test.ts @@ -1213,6 +1213,83 @@ describe('n', () => { }) expect(n(0.99, { key: 'percent' })).toEqual('') }) + + test('part formatting with n', () => { + const { n } = createComposer({ + locale: 'en-US', + fallbackLocale: ['ja-JP'], + numberFormats: { + 'en-US': { + currency: { + style: 'currency', + currency: 'USD', + currencyDisplay: 'symbol' + }, + decimal: { + style: 'decimal', + useGrouping: true + } + }, + 'ja-JP': { + currency: { + style: 'currency', + currency: 'JPY' /*, currencyDisplay: 'symbol'*/ + }, + numeric: { + style: 'decimal', + useGrouping: false + }, + percent: { + style: 'percent', + useGrouping: true + } + } + } + }) + expect(n(0.99, { key: 'currency', part: true })).toEqual([ + { type: 'currency', value: '$' }, + { type: 'integer', value: '0' }, + { type: 'decimal', value: '.' }, + { type: 'fraction', value: '99' } + ]) + expect( + n(10100, { + key: 'currency', + locale: 'ja-JP', + currency: 'EUR', + part: true + }) + ).toEqual([ + { type: 'currency', value: '€' }, + { type: 'integer', value: '10' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '100' }, + { type: 'decimal', value: '.' }, + { type: 'fraction', value: '00' } + ]) + // expect(n(12145281111, 'decimal', 'ja-JP')).toEqual([]) + expect(n(12145281000, { key: 'percent', part: true })).toEqual([ + { type: 'integer', value: '1' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '214' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '528' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '100' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '000' }, + { type: 'percentSign', value: '%' } + ]) + expect(n(12145281111, { key: 'decimal', part: true })).toEqual([ + { type: 'integer', value: '12' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '145' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '281' }, + { type: 'group', value: ',' }, + { type: 'integer', value: '111' } + ]) + }) }) describe('tm', () => { diff --git a/packages/vue-i18n/src/vue.d.ts b/packages/vue-i18n/src/vue.d.ts index c3a53f405..2fe1a8722 100644 --- a/packages/vue-i18n/src/vue.d.ts +++ b/packages/vue-i18n/src/vue.d.ts @@ -846,7 +846,10 @@ declare module 'vue' { * * @returns formatted value */ - $n(value: number, options: NumberOptions): string + $n( + value: number, + options: OptionsType + ): OptionsType['part'] extends true ? Intl.NumberFormatPart[] : string /** * Locale messages getter *