Skip to content

Commit

Permalink
fix: deprecate named interpolation with modulo syntax (#1795)
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon committed Apr 12, 2024
1 parent f7686dd commit 74e9b2d
Show file tree
Hide file tree
Showing 19 changed files with 332 additions and 82 deletions.
25 changes: 24 additions & 1 deletion packages/core-base/src/compilation.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { warn, format, isObject, isBoolean, isString } from '@intlify/shared'
import {
baseCompile as baseCompileCore,
CompileWarnCodes,
defaultOnError,
detectHtmlTag
} from '@intlify/message-compiler'
Expand All @@ -11,7 +12,8 @@ import type {
CompileOptions,
CompileError,
CompilerResult,
ResourceNode
ResourceNode,
CompileWarn
} from '@intlify/message-compiler'
import type { MessageFunction, MessageFunctions } from './runtime'
import type { MessageCompilerContext } from './context'
Expand All @@ -27,6 +29,17 @@ function checkHtmlMessage(source: string, warnHtmlMessage?: boolean): void {
const defaultOnCacheKey = (message: string): string => message
let compileCache: unknown = Object.create(null)

function onCompileWarn(_warn: CompileWarn): void {
if (_warn.code === CompileWarnCodes.USE_MODULO_SYNTAX) {
warn(
`The use of named interpolation with modulo syntax is deprecated. ` +
`It will be removed in v10.\n` +
`reference: https://vue-i18n.intlify.dev/guide/essentials/syntax#rails-i18n-format \n` +
`(message compiler warning message: ${_warn.message})`
)
}
}

export function clearCompileCache(): void {
compileCache = Object.create(null)
}
Expand Down Expand Up @@ -64,6 +77,11 @@ export const compileToFunction = <
throw createCoreError(CoreErrorCodes.NOT_SUPPORT_NON_STRING_MESSAGE)
}

// set onWarn
if (__DEV__) {
context.onWarn = onCompileWarn
}

if (__RUNTIME__) {
__DEV__ &&
warn(
Expand Down Expand Up @@ -107,6 +125,11 @@ export function compile<
message: MessageSource,
context: MessageCompilerContext
): MessageFunction<Message> {
// set onWarn
if (__DEV__) {
context.onWarn = onCompileWarn
}

if (
(__ESM_BROWSER__ ||
__NODE_JS__ ||
Expand Down
90 changes: 45 additions & 45 deletions packages/core-base/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ export type LocaleMessageValue<Message = string> =
export type LocaleMessageType<T, Message = string> = T extends string
? string
: T extends () => Promise<infer P>
? LocaleMessageDictionary<P, Message>
: T extends (...args: infer Arguments) => any
? (...args: Arguments) => ReturnType<T>
: T extends Record<string, unknown>
? LocaleMessageDictionary<T, Message>
: T extends Array<T>
? { [K in keyof T]: T[K] }
: T
? LocaleMessageDictionary<P, Message>
: T extends (...args: infer Arguments) => any
? (...args: Arguments) => ReturnType<T>
: T extends Record<string, unknown>
? LocaleMessageDictionary<T, Message>
: T extends Array<T>
? { [K in keyof T]: T[K] }
: T

/** @VueI18nGeneral */
export type LocaleMessageDictionary<T, Message = string> = {
Expand Down Expand Up @@ -145,7 +145,7 @@ export type PostTranslationHandler<Message = string> = (
*/
export type MessageCompilerContext = Pick<
CompileOptions,
'onError' | 'onCacheKey'
'onError' | 'onCacheKey' | 'onWarn'
> & {
/**
* Whether to allow the use locale messages of HTML formatting.
Expand Down Expand Up @@ -183,37 +183,37 @@ export type MessageCompiler<
export interface CoreOptions<
Message = string,
Schema extends
{
message?: unknown
datetime?: unknown
number?: unknown
} = {
message: DefaultCoreLocaleMessageSchema,
datetime: DateTimeFormat,
number: NumberFormat
},
{
message?: unknown
datetime?: unknown
number?: unknown
} = {
message: DefaultCoreLocaleMessageSchema,
datetime: DateTimeFormat,
number: NumberFormat
},
Locales extends
| {
messages: unknown
datetimeFormats: unknown
numberFormats: unknown
}
| string = Locale,
| {
messages: unknown
datetimeFormats: unknown
numberFormats: unknown
}
| string = Locale,
MessagesLocales = Locales extends { messages: infer M }
? M
: Locales extends string
? Locales
: Locale,
? M
: Locales extends string
? Locales
: Locale,
DateTimeFormatsLocales = Locales extends { datetimeFormats: infer D }
? D
: Locales extends string
? Locales
: Locale,
? D
: Locales extends string
? Locales
: Locale,
NumberFormatsLocales = Locales extends { numberFormats: infer N }
? N
: Locales extends string
? Locales
: Locale,
? N
: Locales extends string
? Locales
: Locale,
MessageSchema = Schema extends { message: infer M } ? M : DefaultCoreLocaleMessageSchema,
DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat,
NumberSchema = Schema extends { number: infer N } ? N : NumberFormat,
Expand Down Expand Up @@ -300,14 +300,14 @@ export type CoreContext<
NumberFormats = {},
LocaleType = Locale,
ResourceLocales =
| PickupLocales<NonNullable<Messages>>
| PickupLocales<NonNullable<DateTimeFormats>>
| PickupLocales<NonNullable<NumberFormats>>,
| PickupLocales<NonNullable<Messages>>
| PickupLocales<NonNullable<DateTimeFormats>>
| PickupLocales<NonNullable<NumberFormats>>,
Locales = IsNever<ResourceLocales> extends true
? LocaleType extends LocaleDetector | Locale
? LocaleType
: Locale
: ResourceLocales
? LocaleType extends LocaleDetector | Locale
? LocaleType
: Locale
: ResourceLocales
> = CoreCommonContext<Message, Locales> &
CoreTranslationContext<NonNullable<Messages>, Message> &
CoreDateTimeContext<NonNullable<DateTimeFormats>> &
Expand Down Expand Up @@ -355,7 +355,7 @@ function getDefaultLinkedModifiers<
return type === 'text' && isString(val)
? val.toUpperCase()
: type === 'vnode' && isObject(val) && '__v_isVNode' in val
? (val as any).children.toUpperCase()
? (val as any).children.toUpperCase()
: val
},
lower: (val: Message, type: string): MessageType<Message> => {
Expand All @@ -371,7 +371,7 @@ function getDefaultLinkedModifiers<
return (type === 'text' && isString(val)
? capitalize(val)
: type === 'vnode' && isObject(val) && '__v_isVNode' in val
? capitalize( (val as any).children)
? capitalize((val as any).children)
: val) as MessageType<Message>
}
}
Expand Down
16 changes: 8 additions & 8 deletions packages/core-base/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ const code = CompileErrorCodes.__EXTEND_POINT__
const inc = incrementer(code)

export const CoreErrorCodes = {
INVALID_ARGUMENT: code, // 18
INVALID_DATE_ARGUMENT: inc(), // 19
INVALID_ISO_DATE_ARGUMENT: inc(), // 20
NOT_SUPPORT_NON_STRING_MESSAGE: inc(), // 21
NOT_SUPPORT_LOCALE_PROMISE_VALUE: inc(), // 22
NOT_SUPPORT_LOCALE_ASYNC_FUNCTION: inc(), // 23
NOT_SUPPORT_LOCALE_TYPE: inc(), // 24
__EXTEND_POINT__: inc() // 25
INVALID_ARGUMENT: code, // 17
INVALID_DATE_ARGUMENT: inc(), // 18
INVALID_ISO_DATE_ARGUMENT: inc(), // 19
NOT_SUPPORT_NON_STRING_MESSAGE: inc(), // 20
NOT_SUPPORT_LOCALE_PROMISE_VALUE: inc(), // 21
NOT_SUPPORT_LOCALE_ASYNC_FUNCTION: inc(), // 22
NOT_SUPPORT_LOCALE_TYPE: inc(), // 23
__EXTEND_POINT__: inc() // 24
} as const

export type CoreErrorCodes =
Expand Down
22 changes: 13 additions & 9 deletions packages/core-base/src/warnings.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import { format } from '@intlify/shared'
import { format, incrementer } from '@intlify/shared'
import { CompileWarnCodes } from '@intlify/message-compiler'

const code = CompileWarnCodes.__EXTEND_POINT__
const inc = incrementer(code)

export const CoreWarnCodes = {
NOT_FOUND_KEY: 1,
FALLBACK_TO_TRANSLATE: 2,
CANNOT_FORMAT_NUMBER: 3,
FALLBACK_TO_NUMBER_FORMAT: 4,
CANNOT_FORMAT_DATE: 5,
FALLBACK_TO_DATE_FORMAT: 6,
EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: 7,
__EXTEND_POINT__: 8
NOT_FOUND_KEY: code, // 2
FALLBACK_TO_TRANSLATE: inc(), // 3
CANNOT_FORMAT_NUMBER: inc(), // 4
FALLBACK_TO_NUMBER_FORMAT: inc(), // 5
CANNOT_FORMAT_DATE: inc(), // 6
FALLBACK_TO_DATE_FORMAT: inc(), // 7
EXPERIMENTAL_CUSTOM_MESSAGE_COMPILER: inc(), // 8
__EXTEND_POINT__: inc() // 9
} as const

export type CoreWarnCodes = (typeof CoreWarnCodes)[keyof typeof CoreWarnCodes]
Expand Down
36 changes: 35 additions & 1 deletion packages/core-base/test/compilation.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
// utils
import * as shared from '@intlify/shared'
vi.mock('@intlify/shared', async () => {
const actual = await vi.importActual<object>('@intlify/shared')
return {
...actual,
warn: vi.fn()
}
})

import { baseCompile } from '@intlify/message-compiler'
import {
compileToFunction,
Expand All @@ -9,7 +19,7 @@ import { createMessageContext as context } from '../src/runtime'

const DEFAULT_CONTEXT = { locale: 'en', key: 'key' }

beforeAll(() => {
beforeEach(() => {
clearCompileCache()
})

Expand Down Expand Up @@ -50,6 +60,19 @@ describe('compileToFunction', () => {
})
expect(occured).toBe(true)
})

test('modulo syntax warning', () => {
const mockWarn = vi.spyOn(shared, 'warn')
mockWarn.mockImplementation(() => {})

compileToFunction('hello %{name}!', {
...DEFAULT_CONTEXT
})
expect(mockWarn).toHaveBeenCalledTimes(1)
expect(mockWarn.mock.calls[0][0]).includes(
`The use of named interpolation with modulo syntax is deprecated. It will be removed in v10.`
)
})
})

describe('compile', () => {
Expand Down Expand Up @@ -109,4 +132,15 @@ describe('compile', () => {
})
expect(occured).toBe(true)
})

test('modulo syntax warning', () => {
const mockWarn = vi.spyOn(shared, 'warn')
mockWarn.mockImplementation(() => {})

compile('%{msg} world!', DEFAULT_CONTEXT)
expect(mockWarn).toHaveBeenCalledTimes(1)
expect(mockWarn.mock.calls[0][0]).includes(
`The use of named interpolation with modulo syntax is deprecated. It will be removed in v10.`
)
})
})
5 changes: 5 additions & 0 deletions packages/core-base/test/errors.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CoreErrorCodes } from '../src/errors'

test('CoreErrorCodes', () => {
expect(CoreErrorCodes.INVALID_ARGUMENT).toBe(17)
})
5 changes: 5 additions & 0 deletions packages/core-base/test/warnings.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { CoreWarnCodes } from '../src/warnings'

test('CoreWarnCodes', () => {
expect(CoreWarnCodes.NOT_FOUND_KEY).toBe(2)
})
1 change: 1 addition & 0 deletions packages/message-compiler/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export * from './location'
export * from './nodes'
export * from './options'
export * from './warnings'
export * from './errors'
export * from './helpers'
export * from './parser'
Expand Down
1 change: 1 addition & 0 deletions packages/message-compiler/src/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ export interface TextNode extends Node {
export interface NamedNode extends Node {
type: NodeTypes.Named
key: Identifier
modulo?: boolean
/**
* @internal `key` alias
*/
Expand Down
5 changes: 5 additions & 0 deletions packages/message-compiler/src/options.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import type { CompileError } from './errors'
import type { CompileWarn } from './warnings'

export type CompileWarnHandler = (warn: CompileWarn) => void
export type CompileErrorHandler = (error: CompileError) => void
export type CacheKeyHandler = (source: string) => string

Expand All @@ -11,10 +13,12 @@ export interface TokenizeOptions {
export interface ParserOptions {
location?: boolean // default true
onCacheKey?: (source: string) => string
onWarn?: CompileWarnHandler
onError?: CompileErrorHandler
}

export interface TransformOptions {
onWarn?: CompileWarnHandler
onError?: CompileErrorHandler
}

Expand All @@ -23,6 +27,7 @@ export interface CodeGenOptions {
mode?: 'normal' | 'arrow' // default normal
breakLineCode?: '\n' | ';' // default newline
needIndent?: boolean // default true
onWarn?: CompileWarnHandler
onError?: CompileErrorHandler
// Generate source map?
// - Default: false
Expand Down
Loading

0 comments on commit 74e9b2d

Please sign in to comment.