From bae5feec8b35759a60bda6a265de3e45f08af796 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Sun, 2 May 2021 21:20:57 +0900 Subject: [PATCH 01/24] improvement: more type safe --- packages/core-base/src/context.ts | 272 ++++++++++++++++------ packages/core-base/src/datetime.ts | 95 +++++--- packages/core-base/src/index.ts | 2 +- packages/core-base/src/number.ts | 86 ++++--- packages/core-base/src/translate.ts | 201 +++++++++------- packages/core-base/src/types.ts | 79 ------- packages/core-base/test/context.test.ts | 2 +- packages/core-base/test/datetime.test.ts | 18 +- packages/core-base/test/number.test.ts | 20 +- packages/core-base/test/translate.test.ts | 84 ++++--- test-d/core-base/context.test-d.ts | 185 +++++++++++++++ 11 files changed, 712 insertions(+), 332 deletions(-) delete mode 100644 packages/core-base/src/types.ts create mode 100644 test-d/core-base/context.test-d.ts diff --git a/packages/core-base/src/context.ts b/packages/core-base/src/context.ts index a455a25cd..1919a9aa3 100644 --- a/packages/core-base/src/context.ts +++ b/packages/core-base/src/context.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + import { warn, isString, @@ -28,41 +30,65 @@ import type { } from '@intlify/runtime' import type { VueDevToolsEmitter } from '@intlify/vue-devtools' import type { - MetaInfo, + UnionToTuple, + LocaleRecord, + IsUnion, + First, NumberFormat, DateTimeFormat, DateTimeFormats as DateTimeFormatsType, NumberFormats as NumberFormatsType -} from './types' +} from './types/index' + +export interface MetaInfo { + [field: string]: unknown +} /** @VueI18nGeneral */ export type LocaleMessageValue = + | LocaleMessageDictionary | string - | MessageFunction - | LocaleMessageDictionary - | LocaleMessageArray +// prettier-ignore /** @VueI18nGeneral */ -export type LocaleMessageDictionary = { - [property: string]: LocaleMessageValue -} +export type LocaleMessageType = T extends string + ? string + : T extends () => Promise + ? LocaleMessageDictionary + : T extends (...args: infer Arguments) => any + ? (...args: Arguments) => ReturnType + : T extends Record + ? LocaleMessageDictionary + : T extends Array + ? { [K in keyof T]: T[K] } + : T + /** @VueI18nGeneral */ -// eslint-disable-next-line @typescript-eslint/no-empty-interface -export interface LocaleMessageArray - extends Array> {} +export type LocaleMessageDictionary = { + [K in keyof T]: LocaleMessageType +} + /** @VueI18nGeneral */ -export type LocaleMessages = Record< - Locale, - LocaleMessageDictionary +export type LocaleMessage = Record< + string, + LocaleMessageValue > +/** @VueI18nGeneral */ +export type LocaleMessages< + Schema, + Locales = Locale, + Message = string // eslint-disable-line @typescript-eslint/no-unused-vars +> = LocaleRecord, Schema> + export type CoreMissingHandler = ( - context: CoreCommonContext, + context: CoreContext, locale: Locale, key: Path, type: CoreMissingType, ...values: unknown[] ) => string | void + /** @VueI18nGeneral */ export type PostTranslationHandler = ( translated: MessageType @@ -73,13 +99,60 @@ export type MessageCompiler = ( options?: CompileOptions ) => MessageFunction -export interface CoreOptions { +// prettier-ignore +export interface CoreOptions< + Message = string, + // Schema = LocaleMessage, + Schema extends + { + message?: unknown + datetime?: unknown + number?: unknown + } = { + message: LocaleMessage, + datetime: DateTimeFormat, + number: NumberFormat + }, + Locales extends + | { + messages: unknown + datetimeFormats: unknown + numberFormats: unknown + } + | string = Locale, + MessagesLocales = Locales extends { messages: infer M } + ? M + : Locales extends string + ? Locales + : Locale, + DateTimeFormatsLocales = Locales extends { datetimeFormats: infer D } + ? D + : Locales extends string + ? Locales + : Locale, + NumberFormatsLocales = Locales extends { numberFormats: infer N } + ? N + : Locales extends string + ? Locales + : Locale, + // MessageSchema = Schema, + MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, + DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, + NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, + Messages extends LocaleMessages< + MessageSchema, + MessagesLocales, + Message + > = LocaleMessages, + DateTimeFormats extends DateTimeFormatsType = DateTimeFormatsType, + NumberFormats extends NumberFormatsType = NumberFormatsType, +> { version?: string locale?: Locale fallbackLocale?: FallbackLocale - messages?: LocaleMessages - datetimeFormats?: DateTimeFormatsType - numberFormats?: NumberFormatsType + messages?: { [T in keyof Messages]: MessageSchema } + datetimeFormats?: { [K in keyof DateTimeFormats]: DateTimeSchema } + numberFormats?: { [K in keyof NumberFormats]: NumberSchema } modifiers?: LinkedModifiers pluralRules?: PluralizationRules missing?: CoreMissingHandler @@ -103,11 +176,19 @@ export interface CoreInternalOptions { __meta?: MetaInfo } -export interface CoreCommonContext { +export type PickupFallbackLocales = T[number] | `${T[number]}!` + +export interface CoreCommonContext { cid: number version: string - locale: Locale - fallbackLocale: FallbackLocale + locale: Locales + fallbackLocale: + | Locales + | Array + | { + [locale in string]: Array>> + } + | false missing: CoreMissingHandler | null missingWarn: boolean | RegExp fallbackWarn: boolean | RegExp @@ -116,9 +197,10 @@ export interface CoreCommonContext { onWarn(msg: string, err?: Error): void } -export interface CoreTranslationContext - extends CoreCommonContext { - messages: Messages +export interface CoreTranslationContext { + messages: { + [K in keyof Messages]: Messages[K] + } modifiers: LinkedModifiers pluralRules?: PluralizationRules postTranslation: PostTranslationHandler | null @@ -129,24 +211,32 @@ export interface CoreTranslationContext messageResolver: MessageResolver } -export interface CoreDateTimeContext - extends CoreCommonContext { - datetimeFormats: DateTimeFormats +export interface CoreDateTimeContext { + datetimeFormats: { [K in keyof DateTimeFormats]: DateTimeFormats[K] } } -export interface CoreNumberContext - extends CoreCommonContext { - numberFormats: NumberFormats +export interface CoreNumberContext { + numberFormats: { [K in keyof NumberFormats]: NumberFormats[K] } } -export interface CoreContext< +type PickupLocales< + T extends Record, + K = keyof T +> = K extends string ? K : never + +export type CoreContext< + Message = string, Messages = {}, DateTimeFormats = {}, NumberFormats = {}, - Message = string -> extends CoreTranslationContext, - CoreDateTimeContext, - CoreNumberContext {} + Locales = + | PickupLocales> + | PickupLocales> + | PickupLocales> +> = CoreCommonContext & + CoreTranslationContext, Message> & + CoreDateTimeContext> & + CoreNumberContext> export interface CoreInternalContext { __datetimeFormatters: Map @@ -205,29 +295,79 @@ export const getAdditionalMeta = /* #__PURE__*/ (): MetaInfo | null => // ID for CoreContext let _cid = 0 +// prettier-ignore +type LocaleParamsType = T extends IsUnion + ? T + : T extends string + ? T + : R + +// prettier-ignore +export type SchemaParams = T extends readonly any[] + ? { message: First, datetime: DateTimeFormat, number: NumberFormat } + : T extends { message?: infer M, datetime?: infer D, number?: infer N } + ? { + message: M extends LocaleMessage ? M : LocaleMessage, + datetime: D extends DateTimeFormat ? D : DateTimeFormat, + number: N extends NumberFormat ? N : NumberFormat + } + : { + message: LocaleMessage, + datetime: DateTimeFormat, + number: NumberFormat + } + +// prettier-ignore +export type LocaleParams = T extends IsUnion + ? { messages: T, datetimeFormats: T, numberFormats: T } + : T extends { messages?: infer M, datetimeFormats?: infer D, numberFormats?: infer N } + ? { + messages: LocaleParamsType, + datetimeFormats: LocaleParamsType, + numberFormats: LocaleParamsType + } + : T extends string + ? { messages: T, datetimeFormats: T, numberFormats: T } + : { messages: Default, datetimeFormats: Default, numberFormats: Default } + export function createCoreContext< Message = string, - Options extends CoreOptions = object, - Messages extends Record< - keyof Options['messages'], - LocaleMessageDictionary - > = Record>, - DateTimeFormats extends Record< - keyof Options['datetimeFormats'], - DateTimeFormat - > = Record, - NumberFormats extends Record< - keyof Options['numberFormats'], - NumberFormat - > = Record + Options extends CoreOptions = CoreOptions >( - options: Options = {} as Options + options: Options ): CoreContext< + Message, Options['messages'], Options['datetimeFormats'], - Options['numberFormats'], - Message -> { + Options['numberFormats'] +> + +export function createCoreContext< + Schema = LocaleMessage, + // Schema extends LocaleMessage = LocaleMessage, + Locales = 'en-US', + Message = string, + Options extends CoreOptions< + Message, + // Schema, + SchemaParams, + LocaleParams + > = CoreOptions< + Message, + // Schema, + SchemaParams, + LocaleParams + > +>( + options: Options +): CoreContext< + Message, + Options['messages'], + Options['datetimeFormats'], + Options['numberFormats'] +> + +export function createCoreContext(options: any = {}): any { // setup options const version = isString(options.version) ? options.version : VERSION const locale = isString(options.locale) ? options.locale : 'en-US' @@ -240,16 +380,16 @@ export function createCoreContext< : locale const messages = isPlainObject(options.messages) ? options.messages - : ({ [locale]: {} } as Messages) + : { [locale]: {} } const datetimeFormats = isPlainObject(options.datetimeFormats) ? options.datetimeFormats - : ({ [locale]: {} } as DateTimeFormats) + : { [locale]: {} } const numberFormats = isPlainObject(options.numberFormats) ? options.numberFormats - : ({ [locale]: {} } as NumberFormats) + : { [locale]: {} } const modifiers = assign( - {} as LinkedModifiers, - options.modifiers || ({} as LinkedModifiers), + {}, + options.modifiers || {}, getDefaultLinkedModifiers() ) const pluralRules = options.pluralRules || {} @@ -317,12 +457,12 @@ export function createCoreContext< __datetimeFormatters, __numberFormatters, __meta - } as CoreContext< + } /* as CoreContext< Options['messages'], Options['datetimeFormats'], Options['numberFormats'], Message - > + >*/ // for vue-devtools timeline event if (__DEV__) { @@ -358,7 +498,7 @@ export function isTranslateMissingWarn( /** @internal */ export function handleMissing( - context: CoreCommonContext, + context: CoreContext, key: Path, locale: Locale, missingWarn: boolean | RegExp, @@ -380,7 +520,7 @@ export function handleMissing( } if (missing !== null) { - const ret = missing(context, locale, key, type) + const ret = missing(context as any, locale, key, type) return isString(ret) ? ret : key } else { if (__DEV__ && isTranslateMissingWarn(missingWarn, key)) { @@ -392,7 +532,7 @@ export function handleMissing( /** @internal */ export function getLocaleChain( - ctx: CoreCommonContext, + ctx: CoreContext, fallback: FallbackLocale, start: Locale ): Locale[] { @@ -489,11 +629,13 @@ function appendItemToChain( /** @internal */ export function updateFallbackLocale( - ctx: CoreCommonContext, + ctx: CoreContext, locale: Locale, fallback: FallbackLocale ): void { const context = (ctx as unknown) as CoreInternalContext context.__localeChainCache = new Map() - getLocaleChain(ctx, fallback, locale) + getLocaleChain(ctx, fallback, locale) } + +/* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/packages/core-base/src/datetime.ts b/packages/core-base/src/datetime.ts index 2607db05a..09ef05868 100644 --- a/packages/core-base/src/datetime.ts +++ b/packages/core-base/src/datetime.ts @@ -19,13 +19,14 @@ import { CoreErrorCodes, createCoreError } from './errors' import { VueDevToolsTimelineEvents } from '@intlify/vue-devtools' import { Availabilities } from './intl' -import type { Locale } from '@intlify/runtime' +import type { Locale, FallbackLocale } from '@intlify/runtime' import type { DateTimeFormat, DateTimeFormats as DateTimeFormatsType, - DateTimeFormatOptions -} from './types' -import type { CoreDateTimeContext, CoreInternalContext } from './context' + DateTimeFormatOptions, + PickupKeys +} from './types/index' +import type { CoreContext, CoreInternalContext } from './context' /** * # datetime @@ -75,17 +76,17 @@ import type { CoreDateTimeContext, CoreInternalContext } from './context' * * @VueI18nGeneral */ -export interface DateTimeOptions { +export interface DateTimeOptions { /** * @remarks * The target format key */ - key?: string + key?: Key /** * @remarks * The locale of localization */ - locale?: Locale + locale?: Locales /** * @remarks * Whether suppress warnings outputted when localization fails @@ -104,34 +105,60 @@ export interface DateTimeOptions { } // `datetime` function overloads -export function datetime( - context: CoreDateTimeContext, - value: number | Date +export function datetime< + Context extends CoreContext, + Message = string +>( + context: Context, + value: number | string | Date ): string | number | Intl.DateTimeFormatPart[] -export function datetime( - context: CoreDateTimeContext, - value: number | Date, - key: string +export function datetime< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + value: number | string | Date, + keyOrOptions: Key | DateTimeOptions ): string | number | Intl.DateTimeFormatPart[] -export function datetime( - context: CoreDateTimeContext, - value: number | Date, - key: string, - locale: Locale +export function datetime< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + value: number | string | Date, + keyOrOptions: Key | DateTimeOptions, + locale: Context['locale'] ): string | number | Intl.DateTimeFormatPart[] -export function datetime( - context: CoreDateTimeContext, - value: number | Date, - options: DateTimeOptions +export function datetime< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + value: number | string | Date, + keyOrOptions: Key | DateTimeOptions, + override: Intl.DateTimeFormatOptions +): string | number | Intl.DateTimeFormatPart[] +export function datetime< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + value: number | string | Date, + keyOrOptions: Key | DateTimeOptions, + locale: Context['locale'], + override: Intl.DateTimeFormatOptions ): string | number | Intl.DateTimeFormatPart[] -export function datetime( - context: CoreDateTimeContext, - ...args: unknown[] -): string | number | Intl.DateTimeFormatPart[] // for internal // implementation of `datetime` function -export function datetime( - context: CoreDateTimeContext, +export function datetime< + Context extends CoreContext, + Message = string +>( + context: Context, ...args: unknown[] ): string | number | Intl.DateTimeFormatPart[] { const { datetimeFormats, unresolving, fallbackLocale, onWarn } = context @@ -151,7 +178,11 @@ export function datetime( : context.fallbackWarn const part = !!options.part const locale = isString(options.locale) ? options.locale : context.locale - const locales = getLocaleChain(context, fallbackLocale, locale) + const locales = getLocaleChain( + context as any, // eslint-disable-line @typescript-eslint/no-explicit-any + fallbackLocale as FallbackLocale, + locale + ) if (!isString(key) || key === '') { return new Intl.DateTimeFormat(locale).format(value) @@ -199,7 +230,7 @@ export function datetime( format = datetimeFormat[key] if (isPlainObject(format)) break - handleMissing(context, key, targetLocale, missingWarn, type) + handleMissing(context as any, key, targetLocale, missingWarn, type) // eslint-disable-line @typescript-eslint/no-explicit-any from = to } @@ -279,7 +310,7 @@ export function parseDateTimeArgs( /** @internal */ export function clearDateTimeFormat( - ctx: CoreDateTimeContext, + ctx: CoreContext, locale: Locale, format: DateTimeFormat ): void { diff --git a/packages/core-base/src/index.ts b/packages/core-base/src/index.ts index eb59ab78c..505b6721e 100644 --- a/packages/core-base/src/index.ts +++ b/packages/core-base/src/index.ts @@ -12,5 +12,5 @@ export * from './datetime' export * from './number' export { getWarnMessage, CoreWarnCodes } from './warnings' export { CoreError, CoreErrorCodes, createCoreError } from './errors' -export * from './types' +export * from './types/intl' export * from './devtools' diff --git a/packages/core-base/src/number.ts b/packages/core-base/src/number.ts index aca35072f..8eee801ee 100644 --- a/packages/core-base/src/number.ts +++ b/packages/core-base/src/number.ts @@ -18,13 +18,14 @@ import { CoreErrorCodes, createCoreError } from './errors' import { VueDevToolsTimelineEvents } from '@intlify/vue-devtools' import { Availabilities } from './intl' -import type { Locale } from '@intlify/runtime' +import type { Locale, FallbackLocale } from '@intlify/runtime' import type { NumberFormat, NumberFormats as NumberFormatsType, - NumberFormatOptions -} from './types' -import type { CoreNumberContext, CoreInternalContext } from './context' + NumberFormatOptions, + PickupKeys +} from './types/index' +import type { CoreContext, CoreInternalContext } from './context' /** * # number @@ -73,17 +74,17 @@ import type { CoreNumberContext, CoreInternalContext } from './context' * * @VueI18nGeneral */ -export interface NumberOptions { +export interface NumberOptions { /** * @remarks * The target format key */ - key?: string + key?: Key /** * @remarks * The locale of localization */ - locale?: Locale + locale?: Locales /** * @remarks * Whether suppress warnings outputted when localization fails @@ -102,34 +103,57 @@ export interface NumberOptions { } // `number` function overloads -export function number( - context: CoreNumberContext, - value: number +export function number< + Context extends CoreContext, + Message = string +>(context: Context, value: number): string | number | Intl.NumberFormatPart[] +export function number< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + value: number, + keyOrOptions: Key | NumberOptions ): string | number | Intl.NumberFormatPart[] -export function number( - context: CoreNumberContext, +export function number< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, value: number, - key: string + keyOrOptions: Key | NumberOptions, + locale: Context['locale'] ): string | number | Intl.NumberFormatPart[] -export function number( - context: CoreNumberContext, +export function number< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, value: number, - key: string, - locale: Locale + keyOrOptions: Key | NumberOptions, + override: Intl.NumberFormatOptions ): string | number | Intl.NumberFormatPart[] -export function number( - context: CoreNumberContext, +export function number< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, value: number, - options: NumberOptions + keyOrOptions: Key | NumberOptions, + locale: Context['locale'], + override: Intl.NumberFormatOptions ): string | number | Intl.NumberFormatPart[] -export function number( - context: CoreNumberContext, - ...args: unknown[] -): string | number | Intl.NumberFormatPart[] // for internal // implementation of `number` function -export function number( - context: CoreNumberContext, +export function number< + Context extends CoreContext, + Message = string +>( + context: Context, ...args: unknown[] ): string | number | Intl.NumberFormatPart[] { const { numberFormats, unresolving, fallbackLocale, onWarn } = context @@ -149,7 +173,11 @@ export function number( : context.fallbackWarn const part = !!options.part const locale = isString(options.locale) ? options.locale : context.locale - const locales = getLocaleChain(context, fallbackLocale, locale) + const locales = getLocaleChain( + context as any, // eslint-disable-line @typescript-eslint/no-explicit-any + fallbackLocale as FallbackLocale, + locale + ) if (!isString(key) || key === '') { return new Intl.NumberFormat(locale).format(value) @@ -197,7 +225,7 @@ export function number( format = numberFormat[key] if (isPlainObject(format)) break - handleMissing(context, key, targetLocale, missingWarn, type) + handleMissing(context as any, key, targetLocale, missingWarn, type) // eslint-disable-line @typescript-eslint/no-explicit-any from = to } @@ -256,7 +284,7 @@ export function parseNumberArgs( /** @internal */ export function clearNumberFormat( - ctx: CoreNumberContext, + ctx: CoreContext, locale: Locale, format: NumberFormat ): void { diff --git a/packages/core-base/src/translate.ts b/packages/core-base/src/translate.ts index 708ae2a5e..dda4fda27 100644 --- a/packages/core-base/src/translate.ts +++ b/packages/core-base/src/translate.ts @@ -22,7 +22,8 @@ import { handleMissing, getLocaleChain, NOT_REOSLVED, - getAdditionalMeta + getAdditionalMeta, + CoreContext } from './context' import { CoreWarnCodes, getWarnMessage } from './warnings' import { CoreErrorCodes, createCoreError } from './errors' @@ -45,9 +46,9 @@ import type { AdditionalPayloads } from '@intlify/devtools-if' import type { LocaleMessages, LocaleMessageValue, - CoreInternalContext, - CoreTranslationContext + CoreInternalContext } from './context' +import type { PickupKeys } from './types/index' const NOOP_MESSAGE_FUNCTION = () => '' export const isMessageFunction = (val: unknown): val is MessageFunction => @@ -105,7 +106,7 @@ export const isMessageFunction = (val: unknown): val is MessageFunction => * * @VueI18nGeneral */ -export interface TranslateOptions { +export interface TranslateOptions { /** * @remarks * List interpolation @@ -130,7 +131,7 @@ export interface TranslateOptions { * @remarks * The locale of localization */ - locale?: Locale + locale?: Locales /** * @remarks * Whether suppress warnings outputted when localization fails @@ -154,106 +155,136 @@ export interface TranslateOptions { } // `translate` function overloads -export function translate( - context: CoreTranslationContext, - key: Path | number +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, plural: number ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, plural: number, - options: TranslateOptions -): MessageType | number -export function translate( - context: CoreTranslationContext, - message: MessageFunction | string, - plural: number, - options: TranslateOptions + options: TranslateOptions ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, defaultMsg: string ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, defaultMsg: string, - options: TranslateOptions + options: TranslateOptions ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, list: unknown[] ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, list: unknown[], plural: number ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, list: unknown[], defaultMsg: string ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, - list: unknown[], - options: TranslateOptions -): MessageType | number -export function translate( - context: CoreTranslationContext, - message: MessageFunction | string, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, list: unknown[], - options: TranslateOptions + options: TranslateOptions ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, named: NamedValue ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, named: NamedValue, plural: number ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, named: NamedValue, defaultMsg: string ): MessageType | number -export function translate( - context: CoreTranslationContext, - key: Path | number, - named: NamedValue, - options: TranslateOptions -): MessageType | number -export function translate( - context: CoreTranslationContext, - message: MessageFunction | string, +export function translate< + Context extends CoreContext, + Key extends PickupKeys, + Message = string +>( + context: Context, + key: Key | number | MessageFunction, named: NamedValue, - options: TranslateOptions + options: TranslateOptions ): MessageType | number -export function translate( - context: CoreTranslationContext, - ...args: unknown[] -): MessageType | number // for internal // implementation of `translate` function -export function translate( - context: CoreTranslationContext, - ...args: unknown[] -): MessageType | number { +export function translate< + Context extends CoreContext, + Message = string +>(context: Context, ...args: unknown[]): MessageType | number { const { fallbackFormat, postTranslation, @@ -303,7 +334,7 @@ export function translate( context, key as string, locale, - fallbackLocale, + fallbackLocale as FallbackLocale, fallbackWarn, missingWarn ) @@ -368,14 +399,14 @@ export function translate( } // evaluate message with context - const ctxOptions = getMessageContextOptions( + const ctxOptions = getMessageContextOptions( context, targetLocale!, message, options ) const msgContext = createMessageContext(ctxOptions) - const messaged = evaluateMessage( + const messaged = evaluateMessage( context, msg as MessageFunction, msgContext @@ -431,7 +462,7 @@ function escapeParams(options: TranslateOptions) { } function resolveMessageFormat( - context: CoreTranslationContext, + context: CoreContext, key: string, locale: Locale, fallbackLocale: FallbackLocale, @@ -439,7 +470,7 @@ function resolveMessageFormat( missingWarn: boolean | RegExp ): [PathValue, Locale | undefined, LocaleMessageValue] { const { messages, onWarn, messageResolver: resolveValue } = context - const locales = getLocaleChain(context, fallbackLocale, locale) + const locales = getLocaleChain(context as any, fallbackLocale, locale) // eslint-disable-line @typescript-eslint/no-explicit-any let message: LocaleMessageValue = {} let targetLocale: Locale | undefined @@ -517,8 +548,8 @@ function resolveMessageFormat( } if (isString(format) || isFunction(format)) break - const missingRet = handleMissing( - context, + const missingRet = handleMissing( + context as any, // eslint-disable-line @typescript-eslint/no-explicit-any key, targetLocale, missingWarn, @@ -534,7 +565,7 @@ function resolveMessageFormat( } function compileMessageFormat( - context: CoreTranslationContext, + context: CoreContext, key: string, targetLocale: string, format: PathValue, @@ -599,7 +630,7 @@ function compileMessageFormat( } function evaluateMessage( - context: CoreTranslationContext, + context: CoreContext, msg: MessageFunction, msgCtx: MessageContext ): MessageType { @@ -677,7 +708,7 @@ export function parseTranslateArgs( } function getCompileOptions( - context: CoreTranslationContext, + context: CoreContext, locale: Locale, key: string, source: string, @@ -719,7 +750,7 @@ function getCompileOptions( } function getMessageContextOptions( - context: CoreTranslationContext, + context: CoreContext, locale: Locale, message: LocaleMessageValue, options: TranslateOptions diff --git a/packages/core-base/src/types.ts b/packages/core-base/src/types.ts deleted file mode 100644 index 0252d4ca5..000000000 --- a/packages/core-base/src/types.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * datetime - */ - -export type DateTimeHumanReadable = 'long' | 'short' | 'narrow' -export type DateTimeDigital = 'numeric' | '2-digit' -export type LocaleMatcher = 'lookup' | 'best fit' -export type FormatMatcher = 'basic' | 'best fit' - -export interface SpecificDateTimeFormatOptions - extends Intl.DateTimeFormatOptions { - year?: DateTimeDigital - month?: DateTimeDigital | DateTimeHumanReadable - day?: DateTimeDigital - hour?: DateTimeDigital - minute?: DateTimeDigital - second?: DateTimeDigital - weekday?: DateTimeHumanReadable - era?: DateTimeHumanReadable - timeZoneName?: 'long' | 'short' - localeMatcher?: LocaleMatcher - formatMatcher?: FormatMatcher -} -export type DateTimeFormatOptions = - | Intl.DateTimeFormatOptions - | SpecificDateTimeFormatOptions -export type DateTimeFormat = { [key: string]: DateTimeFormatOptions } -export type DateTimeFormats = { [locale: string]: DateTimeFormat } - -/** - * number - */ - -export type CurrencyDisplay = 'symbol' | 'code' | 'name' - -export interface SpecificNumberFormatOptions extends Intl.NumberFormatOptions { - style?: 'decimal' | 'percent' - currency?: string - currencyDisplay?: CurrencyDisplay - localeMatcher?: LocaleMatcher - formatMatcher?: FormatMatcher -} - -export interface CurrencyNumberFormatOptions extends Intl.NumberFormatOptions { - style: 'currency' - currency: string // Obligatory if style is 'currency' - currencyDisplay?: CurrencyDisplay - localeMatcher?: LocaleMatcher - formatMatcher?: FormatMatcher -} - -export type NumberFormatOptions = - | Intl.NumberFormatOptions - | SpecificNumberFormatOptions - | CurrencyNumberFormatOptions -export type NumberFormat = { [key: string]: NumberFormatOptions } -export type NumberFormats = { [locale: string]: NumberFormat } - -export type FormattedNumberPartType = - | 'currency' - | 'decimal' - | 'fraction' - | 'group' - | 'infinity' - | 'integer' - | 'literal' - | 'minusSign' - | 'nan' - | 'plusSign' - | 'percentSign' - -export type FormattedNumberPart = { - type: FormattedNumberPartType - value: string -} -export type NumberFormatToPartsResult = { [index: number]: FormattedNumberPart } -export interface MetaInfo { - [field: string]: unknown -} diff --git a/packages/core-base/test/context.test.ts b/packages/core-base/test/context.test.ts index 0aca2baa5..2a6ef8d85 100644 --- a/packages/core-base/test/context.test.ts +++ b/packages/core-base/test/context.test.ts @@ -176,7 +176,7 @@ describe('escapeParameter', () => { }) describe('getLocaleChain', () => { - let ctx: CoreContext + let ctx: CoreContext beforeEach(() => { ctx = context({}) }) diff --git a/packages/core-base/test/datetime.test.ts b/packages/core-base/test/datetime.test.ts index 30dffd111..54fbbed45 100644 --- a/packages/core-base/test/datetime.test.ts +++ b/packages/core-base/test/datetime.test.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/no-empty-function, @typescript-eslint/no-explicit-any */ // utils jest.mock('@intlify/shared', () => ({ @@ -20,9 +20,15 @@ import { CoreErrorCodes, errorMessages } from '../src/errors' import { registerMessageCompiler } from '../src/context' import { compileToFunction } from '../src/compile' -import type { DateTimeFormats } from '../src/types' +import type { DateTimeFormats } from '../src/types/index' -const datetimeFormats: DateTimeFormats = { +type MyDateTimeSchema = { + short: {} // loose schema + long: {} // loose schema +} + +const datetimeFormats: DateTimeFormats = { + // @ts-ignore NOTE: checking fallback tests 'en-US': { short: { // DD/MM/YYYY, hh:mm (AM|PM) @@ -267,7 +273,7 @@ describe('context unresolving option', () => { datetimeFormats }) - expect(datetime(ctx, dt, 'custom')).toEqual(NOT_REOSLVED) + expect(datetime(ctx, dt, 'custom' as any)).toEqual(NOT_REOSLVED) expect(mockWarn).not.toHaveBeenCalled() }) }) @@ -339,7 +345,7 @@ describe('error', () => { }).toThrowError(errorMessages[CoreErrorCodes.INVALID_ISO_DATE_ARGUMENT]) expect(() => { - datetime(ctx, { someObject: true }) + datetime(ctx, { someObject: true } as any) }).toThrowError(errorMessages[CoreErrorCodes.INVALID_ARGUMENT]) expect(() => { @@ -348,4 +354,4 @@ describe('error', () => { }) }) -/* eslint-enable @typescript-eslint/no-empty-function */ +/* eslint-enable @typescript-eslint/no-empty-function, @typescript-eslint/no-explicit-any */ diff --git a/packages/core-base/test/number.test.ts b/packages/core-base/test/number.test.ts index c31c270c0..d65555498 100644 --- a/packages/core-base/test/number.test.ts +++ b/packages/core-base/test/number.test.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/no-empty-function, @typescript-eslint/no-explicit-any */ // utils jest.mock('@intlify/shared', () => ({ @@ -19,8 +19,17 @@ import { number } from '../src/number' import { CoreErrorCodes, errorMessages } from '../src/errors' import { registerMessageCompiler } from '../src/context' import { compileToFunction } from '../src/compile' +import { NumberFormats } from '../src/types/index' -const numberFormats = { +type MyNumberSchema = { + currency: {} // loose schema + decimal: {} // loose schema + percent: {} // loose schema + numeric: {} // loose schema +} + +const numberFormats: NumberFormats = { + // @ts-ignore NOTE: checking fallback tests 'en-US': { currency: { style: 'currency', @@ -32,6 +41,7 @@ const numberFormats = { useGrouping: false } }, + // @ts-ignore NOTE: checking fallback tests 'ja-JP': { currency: { style: 'currency', @@ -246,7 +256,7 @@ describe('context unresolving option', () => { numberFormats }) - expect(number(ctx, 123456789, 'custom')).toEqual(NOT_REOSLVED) + expect(number(ctx, 123456789, 'custom' as any)).toEqual(NOT_REOSLVED) expect(mockWarn).not.toHaveBeenCalled() }) }) @@ -305,9 +315,9 @@ describe('error', () => { numberFormats }) expect(() => { - number(ctx, '111') + number(ctx, '111' as any) }).toThrowError(errorMessages[CoreErrorCodes.INVALID_ARGUMENT]) }) }) -/* eslint-enable @typescript-eslint/no-empty-function */ +/* eslint-enable @typescript-eslint/no-empty-function, @typescript-eslint/no-explicit-any */ diff --git a/packages/core-base/test/translate.test.ts b/packages/core-base/test/translate.test.ts index af311ae38..e47f6adf9 100644 --- a/packages/core-base/test/translate.test.ts +++ b/packages/core-base/test/translate.test.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/no-empty-function */ +/* eslint-disable @typescript-eslint/no-empty-function, @typescript-eslint/no-explicit-any */ // utils jest.mock('@intlify/shared', () => ({ @@ -34,7 +34,7 @@ describe('features', () => { const ctx = context({ locale: 'en', messages: { - en: { hi: 'hi {0} !' } + en: { hi: 'hi {0} !', nest: { foo: '' } } } }) expect(translate(ctx, 'hi', ['kazupon'])).toEqual('hi kazupon !') @@ -100,7 +100,7 @@ describe('default option', () => { en: {} } }) - expect(translate(ctx, 'hello', 'hello, default message!')).toEqual( + expect(translate(ctx, 'hello' as any, 'hello, default message!')).toEqual( 'hello, default message!' ) }) @@ -113,7 +113,12 @@ describe('default option', () => { } }) expect( - translate(ctx, 'hi {name}!', { name: 'kazupon' }, { default: true }) + translate( + ctx, + 'hi {name}!' as any, + { name: 'kazupon' }, + { default: true } + ) ).toEqual('hi kazupon!') }) }) @@ -131,7 +136,7 @@ describe('context fallbackLocale option', () => { } }) - expect(translate(ctx, 'hello')).toEqual('hello') + expect(translate(ctx, 'hello' as any)).toEqual('hello') expect(mockWarn.mock.calls[0][0]).toEqual( `Not found 'hello' key in 'en' locale messages.` ) @@ -192,7 +197,7 @@ describe('context missing option', () => { } }) - expect(translate(ctx, 'hello')).toEqual('hello') + expect(translate(ctx, 'hello' as any)).toEqual('hello') expect(mockWarn.mock.calls[0][0]).toEqual( `Not found 'hello' key in 'en' locale messages.` ) @@ -214,7 +219,7 @@ describe('context missing option', () => { en: {} } }) - expect(translate(ctx, 'hello')).toEqual('HELLO') + expect(translate(ctx, 'hello' as any)).toEqual('HELLO') expect(mockWarn).not.toHaveBeenCalled() }) }) @@ -233,7 +238,7 @@ describe('context missingWarn option', () => { } }) - expect(translate(ctx, 'hello')).toEqual('hello') + expect(translate(ctx, 'hello' as any)).toEqual('hello') expect(mockWarn).not.toHaveBeenCalled() }) @@ -250,8 +255,8 @@ describe('context missingWarn option', () => { } }) - expect(translate(ctx, 'hi kazupon!')).toEqual('hi kazupon!') - expect(translate(ctx, 'hello')).toEqual('hello') + expect(translate(ctx, 'hi kazupon!' as any)).toEqual('hi kazupon!') + expect(translate(ctx, 'hello' as any)).toEqual('hello') expect(mockWarn).toHaveBeenCalledTimes(1) expect(mockWarn.mock.calls[0][0]).not.toEqual( `Not found 'hello' key in 'en' locale messages.` @@ -270,7 +275,9 @@ describe('context missingWarn option', () => { } }) - expect(translate(ctx, 'hello', {}, { missingWarn: false })).toEqual('hello') + expect(translate(ctx, 'hello' as any, {}, { missingWarn: false })).toEqual( + 'hello' + ) expect(mockWarn).not.toHaveBeenCalled() }) }) @@ -288,7 +295,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello')).toEqual('hello') + expect(translate(ctx, 'hello' as any)).toEqual('hello') expect(mockWarn).not.toHaveBeenCalled() }) @@ -329,7 +336,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello.world')).toEqual('hello.world') + expect(translate(ctx, 'hello.world' as any)).toEqual('hello.world') expect(mockWarn).toHaveBeenCalledTimes(2) expect(mockWarn.mock.calls[0][0]).toEqual( `Fall back to translate 'hello.world' key with 'ja' locale.` @@ -354,7 +361,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello.world')).toEqual('hello.world') + expect(translate(ctx, 'hello.world' as any)).toEqual('hello.world') expect(mockWarn).toHaveBeenCalledTimes(0) }) @@ -373,7 +380,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello.world')).toEqual('hello.world') + expect(translate(ctx, 'hello.world' as any)).toEqual('hello.world') expect(mockWarn).toHaveBeenCalledTimes(2) }) @@ -394,7 +401,9 @@ describe('context fallbackWarn option', () => { }) expect(translate(ctx, 'hello')).toEqual('こんにちは!') - expect(translate(ctx, 'hi', {}, { fallbackWarn: false })).toEqual('hi') + expect(translate(ctx, 'hi' as any, {}, { fallbackWarn: false })).toEqual( + 'hi' + ) expect(mockWarn).toHaveBeenCalledTimes(1) }) }) @@ -415,7 +424,7 @@ describe('context fallbackFormat option', () => { } }) - expect(translate(ctx, 'hi, {name}!', { name: 'kazupon' })).toEqual( + expect(translate(ctx, 'hi, {name}!' as any, { name: 'kazupon' })).toEqual( 'hi, kazupon!' ) expect(mockWarn).toHaveBeenCalledTimes(5) @@ -452,7 +461,12 @@ describe('context fallbackFormat option', () => { }) expect( - translate(ctx, 'hi, {name}!', { name: 'kazupon' }, 'hello, {name}!') + translate( + ctx, + 'hi, {name}!' as any, + { name: 'kazupon' }, + 'hello, {name}!' + ) ).toEqual('hello, kazupon!') expect(mockWarn).toHaveBeenCalledTimes(5) expect(mockWarn.mock.calls[0][0]).toEqual( @@ -485,7 +499,12 @@ describe('context fallbackFormat option', () => { }) expect( - translate(ctx, 'hi, {name}!', { name: 'kazupon' }, 'hello, {name}!') + translate( + ctx, + 'hi, {name}!' as any, + { name: 'kazupon' }, + 'hello, {name}!' + ) ).toEqual('hello, kazupon!') expect(mockWarn).toHaveBeenCalledTimes(1) expect(mockWarn.mock.calls[0][0]).toEqual( @@ -507,7 +526,7 @@ describe('context unresolving option', () => { ja: {} } }) - expect(translate(ctx, 'hello.world')).toEqual(NOT_REOSLVED) + expect(translate(ctx, 'hello.world' as any)).toEqual(NOT_REOSLVED) }) test('fallbackWarn is false', () => { @@ -522,7 +541,7 @@ describe('context unresolving option', () => { ja: {} } }) - expect(translate(ctx, 'hello.world')).toEqual(NOT_REOSLVED) + expect(translate(ctx, 'hello.world' as any)).toEqual(NOT_REOSLVED) }) test('fallbackFormat is true', () => { @@ -539,7 +558,7 @@ describe('context unresolving option', () => { ja: {} } }) - expect(translate(ctx, 'hi, {name}!', { name: 'kazupon' })).toEqual( + expect(translate(ctx, 'hi, {name}!' as any, { name: 'kazupon' })).toEqual( 'hi, kazupon!' ) }) @@ -662,7 +681,7 @@ describe('error', () => { } }) expect(() => { - translate(ctx, {}) + translate(ctx, {} as any) }).toThrowError(errorMessages[CoreErrorCodes.INVALID_ARGUMENT]) }) }) @@ -674,22 +693,29 @@ test('resolvedMessage', () => { en: {} } }) - expect(translate(ctx, 'car', 1, { resolvedMessage: true })).toEqual('car') + expect(translate(ctx, 'car' as any, 1, { resolvedMessage: true })).toEqual( + 'car' + ) expect( translate(ctx, () => 'hello!', 1, { resolvedMessage: true }) ).toEqual('hello!') - expect(translate(ctx, 'list {0}', [1], { resolvedMessage: true })).toEqual( - 'list 1' - ) + expect( + translate(ctx, 'list {0}' as any, [1], { resolvedMessage: true }) + ).toEqual('list 1') expect( translate(ctx, (ctx: MessageContext) => `list ${ctx.list(0)}`, [1], { resolvedMessage: true }) ).toEqual('list 1') expect( - translate(ctx, 'named {name}', { name: 'dio' }, { resolvedMessage: true }) + translate( + ctx, + 'named {name}' as any, + { name: 'dio' }, + { resolvedMessage: true } + ) ).toEqual('named dio') expect( translate( @@ -745,4 +771,4 @@ describe('edge cases', () => { }) }) -/* eslint-enable @typescript-eslint/no-empty-function */ +/* eslint-enable @typescript-eslint/no-empty-function, @typescript-eslint/no-explicit-any */ diff --git a/test-d/core-base/context.test-d.ts b/test-d/core-base/context.test-d.ts new file mode 100644 index 000000000..ebf57dacb --- /dev/null +++ b/test-d/core-base/context.test-d.ts @@ -0,0 +1,185 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { expectType } from '../index' + +import { + CoreOptions, + PickupFallbackLocales, + createCoreContext +} from '../../packages/core-base/src/context' + +type ResourceSchema = { + foo: string + nest: { + bar: string + } + errors: string[] +} +type MyDatetimeScehma = { + short: { + hour: 'numeric' + } +} +type MyNumberSchema = { + currency: { + style: 'symbol' + } +} + +// loose options +const looseOptions = { + locale: 'en', + fallbackLocale: { + ja: ['en'] + }, + messages: { + en: { + foo: 'foo', + nest: { + bar: 'bar' + } + }, + ja: { + bar: 'foo', + nest: { + bar: 'bar' + } + } + }, + datetimeFormats: { + 'en-US': { + short: {} + } + }, + numberFormats: { + 'ja-JP': { + currency: {} + } + } +} + +// strict options +const strictOptions = { + locale: 'en', + fallbackLocale: { + ja: ['en'] + }, + messages: { + en: { + foo: 'foo', + nest: { + bar: 'bar' + }, + errors: ['error1'] + }, + ja: { + // bar: 'foo', // TODO: + foo: 'foo', + nest: { + bar: 'bar' + }, + errors: ['error2'] + } + } +} + +expectType(looseOptions) +expectType>(strictOptions) + +// check loose context +const looseCtx = createCoreContext(looseOptions) +expectType<'en' | 'ja' | 'en-US' | 'ja-JP'>(looseCtx.locale) +expectType< + | 'en' + | 'ja' + | 'en-US' + | 'ja-JP' + | ('en' | 'ja' | 'en-US' | 'ja-JP')[] + | { + [x in string]: PickupFallbackLocales<['en' | 'ja' | 'en-US' | 'ja-JP']>[] + } + | false +>(looseCtx.fallbackLocale) +expectType<{ + en: { + foo: string + nest: { + bar: string + } + } + ja: { + bar: string + nest: { + bar: string + } + } +}>(looseCtx.messages) +expectType<{ 'en-US': { short: {} } }>(looseCtx.datetimeFormats) +expectType<{ 'ja-JP': { currency: {} } }>(looseCtx.numberFormats) + +// check strict context +const strictCtx = createCoreContext<[ResourceSchema], 'en' | 'ja'>( + strictOptions +) +expectType<'en' | 'ja'>(strictCtx.locale) +expectType< + | 'en' + | 'ja' + | ('en' | 'ja')[] + | { [x in string]: PickupFallbackLocales<['en' | 'ja']>[] } + | false +>(strictCtx.fallbackLocale) +expectType<{ en: ResourceSchema; ja: ResourceSchema }>(strictCtx.messages) +expectType<{ en: {}; ja: {} }>(strictCtx.datetimeFormats) +expectType<{ en: {}; ja: {} }>(strictCtx.numberFormats) + +// check strict context with direct options +const strictDirectCtx = createCoreContext< + { + message: ResourceSchema + datetime: MyDatetimeScehma + number: MyNumberSchema + }, + { messages: 'en'; datetimeFormats: 'ja-JP' | 'zh'; numberFormats: 'ca' } +>({ + messages: { + en: { + foo: '', + nest: { + bar: '' + }, + errors: [''] + } + }, + datetimeFormats: { + zh: { + short: { + hour: 'numeric' + } + }, + 'ja-JP': { + short: { + hour: 'numeric' + } + } + }, + numberFormats: { + ca: { + currency: { style: 'symbol' } + } + } +}) +expectType<'en' | 'zh' | 'ca' | 'ja-JP'>(strictDirectCtx.locale) +expectType< + | 'en' + | 'zh' + | 'ca' + | 'ja-JP' + | ('en' | 'zh' | 'ca' | 'ja-JP')[] + | { [x in string]: PickupFallbackLocales<['en' | 'zh' | 'ca' | 'ja-JP']>[] } + | false +>(strictDirectCtx.fallbackLocale) +expectType<{ en: ResourceSchema }>(strictDirectCtx.messages) +expectType<{ zh: {}; 'ja-JP': { short: {} } }>(strictDirectCtx.datetimeFormats) +expectType<{ ca: { currency: {} } }>(strictDirectCtx.numberFormats) + +/* eslint-enable @typescript-eslint/no-explicit-any */ From 52d2b4a4841fb5c9bae730860812130cca7a4c25 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Wed, 5 May 2021 01:07:22 +0900 Subject: [PATCH 02/24] WIP: build passing --- packages/core-base/src/context.ts | 38 +++------ packages/core-base/src/index.ts | 2 +- packages/vue-i18n/src/composer.ts | 122 +++++++++++++++-------------- packages/vue-i18n/src/i18n.ts | 47 +++++++---- packages/vue-i18n/src/index.ts | 2 +- packages/vue-i18n/src/legacy.ts | 27 +++++-- packages/vue-i18n/src/mixin.ts | 20 +++-- packages/vue-i18n/src/runtime.ts | 2 +- test-d/core-base/context.test-d.ts | 17 +++- 9 files changed, 160 insertions(+), 117 deletions(-) diff --git a/packages/core-base/src/context.ts b/packages/core-base/src/context.ts index 1919a9aa3..435c5817b 100644 --- a/packages/core-base/src/context.ts +++ b/packages/core-base/src/context.ts @@ -102,7 +102,6 @@ export type MessageCompiler = ( // prettier-ignore export interface CoreOptions< Message = string, - // Schema = LocaleMessage, Schema extends { message?: unknown @@ -135,7 +134,6 @@ export interface CoreOptions< : Locales extends string ? Locales : Locale, - // MessageSchema = Schema, MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, @@ -150,7 +148,7 @@ export interface CoreOptions< version?: string locale?: Locale fallbackLocale?: FallbackLocale - messages?: { [T in keyof Messages]: MessageSchema } + messages?: { [K in keyof Messages]: MessageSchema } datetimeFormats?: { [K in keyof DateTimeFormats]: DateTimeSchema } numberFormats?: { [K in keyof NumberFormats]: NumberSchema } modifiers?: LinkedModifiers @@ -178,17 +176,19 @@ export interface CoreInternalOptions { export type PickupFallbackLocales = T[number] | `${T[number]}!` +export type FallbackLocales = + | Locales + | Array + | { + [locale in string]: Array>> + } + | false + export interface CoreCommonContext { cid: number version: string locale: Locales - fallbackLocale: - | Locales - | Array - | { - [locale in string]: Array>> - } - | false + fallbackLocale: FallbackLocales missing: CoreMissingHandler | null missingWarn: boolean | RegExp fallbackWarn: boolean | RegExp @@ -219,7 +219,7 @@ export interface CoreNumberContext { numberFormats: { [K in keyof NumberFormats]: NumberFormats[K] } } -type PickupLocales< +export type PickupLocales< T extends Record, K = keyof T > = K extends string ? K : never @@ -344,20 +344,13 @@ export function createCoreContext< export function createCoreContext< Schema = LocaleMessage, - // Schema extends LocaleMessage = LocaleMessage, Locales = 'en-US', Message = string, Options extends CoreOptions< Message, - // Schema, SchemaParams, LocaleParams - > = CoreOptions< - Message, - // Schema, - SchemaParams, - LocaleParams - > + > = CoreOptions, LocaleParams> >( options: Options ): CoreContext< @@ -457,12 +450,7 @@ export function createCoreContext(options: any = {}): any { __datetimeFormatters, __numberFormatters, __meta - } /* as CoreContext< - Options['messages'], - Options['datetimeFormats'], - Options['numberFormats'], - Message - >*/ + } // for vue-devtools timeline event if (__DEV__) { diff --git a/packages/core-base/src/index.ts b/packages/core-base/src/index.ts index 505b6721e..94b2e22a1 100644 --- a/packages/core-base/src/index.ts +++ b/packages/core-base/src/index.ts @@ -12,5 +12,5 @@ export * from './datetime' export * from './number' export { getWarnMessage, CoreWarnCodes } from './warnings' export { CoreError, CoreErrorCodes, createCoreError } from './errors' -export * from './types/intl' +export * from './types/index' export * from './devtools' diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index 9736e2326..bcf0251d4 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ import { ref, computed, @@ -62,10 +63,8 @@ import type { CoreContext, CoreCommonContext, CoreTranslationContext, - CoreDateTimeContext, - CoreNumberContext, CoreMissingHandler, - CoreOptions, + LocaleMessage, LocaleMessageDictionary, PostTranslationHandler, FallbackLocale, @@ -1210,7 +1209,7 @@ export function getLocaleMessages( } } - return ret + return ret as any } const isNotObjectOrIsArray = (val: unknown) => !isObject(val) || isArray(val) @@ -1254,8 +1253,8 @@ export function createComposer< Options extends ComposerOptions = object, Messages extends Record< keyof Options['messages'], - LocaleMessageDictionary - > = Record>, + LocaleMessage + > = Record>, DateTimeFormats extends Record< keyof Options['datetimeFormats'], DateTimeFormat @@ -1376,15 +1375,20 @@ export function createComposer< // runtime context // eslint-disable-next-line prefer-const - let _context: CoreContext + let _context: CoreContext< + Message, + LocaleMessages, Message>, + DateTimeFormatsType, + NumberFormatsType + > function getCoreContext(): CoreContext< - Messages, - DateTimeFormats, - NumberFormats, - Message + Message, + LocaleMessages, Message>, + DateTimeFormatsType, + NumberFormatsType > { - return createCoreContext({ + const ctxOptions = { version: VERSION, locale: _locale.value, fallbackLocale: _fallbackLocale.value, @@ -1412,16 +1416,21 @@ export function createComposer< ? ((_context as unknown) as CoreInternalContext).__v_emitter : undefined, __meta: { framework: 'vue' } - } as CoreOptions) as CoreContext< - Messages, - DateTimeFormats, - NumberFormats, - Message + } as any + return createCoreContext(ctxOptions) as CoreContext< + Message, + LocaleMessages, Message>, + DateTimeFormatsType, + NumberFormatsType > } _context = getCoreContext() - updateFallbackLocale(_context, _locale.value, _fallbackLocale.value) + updateFallbackLocale( + _context as any, + _locale.value, + _fallbackLocale.value + ) // track reactivity function trackReactivityValues() { @@ -1448,8 +1457,8 @@ export function createComposer< get: () => _fallbackLocale.value, set: val => { _fallbackLocale.value = val - _context.fallbackLocale = _fallbackLocale.value - updateFallbackLocale(_context, _locale.value, val) + _context.fallbackLocale = _fallbackLocale.value as any + updateFallbackLocale(_context as any, _locale.value, val) } }) @@ -1570,11 +1579,7 @@ export function createComposer< // t function t(...args: unknown[]): string { return wrapWithDeps( - context => - translate( - context as CoreTranslationContext, - ...args - ), + context => Reflect.apply(translate, null, [context, ...args]) as string, () => parseTranslateArgs(...args), 'translate', root => root.t(...args), @@ -1595,11 +1600,7 @@ export function createComposer< // d function d(...args: unknown[]): string { return wrapWithDeps( - context => - datetime( - context as CoreDateTimeContext, - ...args - ), + context => Reflect.apply(datetime, null, [context, ...args]) as string, () => parseDateTimeArgs(...args), 'datetime format', root => root.d(...args), @@ -1611,11 +1612,7 @@ export function createComposer< // n function n(...args: unknown[]): string { return wrapWithDeps( - context => - number( - context as CoreNumberContext, - ...args - ), + context => Reflect.apply(number, null, [context, ...args]) as string, () => parseNumberArgs(...args), 'number format', root => root.n(...args), @@ -1647,7 +1644,7 @@ export function createComposer< const _context = context as CoreTranslationContext try { _context.processor = processor - ret = translate(_context, ...args) + ret = Reflect.apply(translate, null, [_context, ...args]) } finally { _context.processor = null } @@ -1665,7 +1662,7 @@ export function createComposer< // numberParts, using for `i18n-n` component function numberParts(...args: unknown[]): string | Intl.NumberFormatPart[] { return wrapWithDeps( - context => number(context as CoreContext, ...args), + context => Reflect.apply(number, null, [context, ...args]), () => parseNumberArgs(...args), 'number format', // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -1680,7 +1677,7 @@ export function createComposer< ...args: unknown[] ): string | Intl.DateTimeFormatPart[] { return wrapWithDeps( - context => datetime(context as CoreContext, ...args), + context => Reflect.apply(datetime, null, [context, ...args]), () => parseDateTimeArgs(...args), 'datetime format', // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -1705,7 +1702,7 @@ export function createComposer< function resolveMessages(key: Path): LocaleMessageValue | null { let messages: LocaleMessageValue | null = null const locales = getLocaleChain( - _context, + _context as any, _fallbackLocale.value, _locale.value ) @@ -1732,27 +1729,24 @@ export function createComposer< } // getLocaleMessage - function getLocaleMessage(locale: Locale): LocaleMessageDictionary { - return (_messages.value[locale] || {}) as LocaleMessageDictionary + function getLocaleMessage(locale: Locale): LocaleMessage { + return (_messages.value[locale] || {}) as LocaleMessage } // setLocaleMessage - function setLocaleMessage( - locale: Locale, - message: LocaleMessageDictionary - ) { - _messages.value[locale] = message - _context.messages = _messages.value as typeof _context.messages + function setLocaleMessage(locale: Locale, message: LocaleMessage) { + _messages.value[locale] = message as any + _context.messages = _messages.value as any } // mergeLocaleMessage function mergeLocaleMessage( locale: Locale, - message: LocaleMessageDictionary + message: LocaleMessage ): void { - _messages.value[locale] = _messages.value[locale] || {} + _messages.value[locale] = _messages.value[locale] || ({} as any) deepCopy(message, _messages.value[locale]) - _context.messages = _messages.value as typeof _context.messages + _context.messages = _messages.value as any } // getDateTimeFormat @@ -1764,7 +1758,11 @@ export function createComposer< function setDateTimeFormat(locale: Locale, format: DateTimeFormat): void { _datetimeFormats.value[locale] = format _context.datetimeFormats = _datetimeFormats.value as typeof _context.datetimeFormats - clearDateTimeFormat(_context, locale, format) + clearDateTimeFormat( + _context as any, + locale, + format + ) } // mergeDateTimeFormat @@ -1774,7 +1772,11 @@ export function createComposer< format ) _context.datetimeFormats = _datetimeFormats.value as typeof _context.datetimeFormats - clearDateTimeFormat(_context, locale, format) + clearDateTimeFormat( + _context as any, + locale, + format + ) } // getNumberFormat @@ -1786,7 +1788,7 @@ export function createComposer< function setNumberFormat(locale: Locale, format: NumberFormat): void { _numberFormats.value[locale] = format _context.numberFormats = _numberFormats.value as typeof _context.numberFormats - clearNumberFormat(_context, locale, format) + clearNumberFormat(_context as any, locale, format) } // mergeNumberFormat @@ -1796,7 +1798,7 @@ export function createComposer< format ) _context.numberFormats = _numberFormats.value as typeof _context.numberFormats - clearNumberFormat(_context, locale, format) + clearNumberFormat(_context as any, locale, format) } // for debug @@ -1809,7 +1811,7 @@ export function createComposer< _locale.value = val _context.locale = val updateFallbackLocale( - _context, + _context as any, _locale.value, _fallbackLocale.value ) @@ -1818,9 +1820,9 @@ export function createComposer< watch(__root.fallbackLocale, (val: FallbackLocale) => { if (_inheritLocale) { _fallbackLocale.value = val - _context.fallbackLocale = val + _context.fallbackLocale = val as any updateFallbackLocale( - _context, + _context as any, _locale.value, _fallbackLocale.value ) @@ -1842,7 +1844,7 @@ export function createComposer< _locale.value = __root.locale.value _fallbackLocale.value = __root.fallbackLocale.value updateFallbackLocale( - _context, + _context as any, _locale.value, _fallbackLocale.value ) @@ -1941,5 +1943,7 @@ export function createComposer< } } - return composer + return composer as any } + +/* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/packages/vue-i18n/src/i18n.ts b/packages/vue-i18n/src/i18n.ts index 250254f68..13c3d03b1 100644 --- a/packages/vue-i18n/src/i18n.ts +++ b/packages/vue-i18n/src/i18n.ts @@ -32,7 +32,7 @@ import type { ComponentInternalInstance, ComponentOptions, App } from 'vue' import type { Locale, FallbackLocale, - LocaleMessageDictionary, + LocaleMessage, DateTimeFormat, NumberFormat } from '@intlify/core-base' @@ -299,11 +299,8 @@ export function createI18n< Options extends I18nOptions = {}, Messages extends Record< keyof Options['messages'], - LocaleMessageDictionary - > = Record< - keyof Options['messages'], - LocaleMessageDictionary - >, + LocaleMessage + > = Record>, DateTimeFormats extends Record< keyof Options['datetimeFormats'], DateTimeFormat @@ -442,7 +439,8 @@ export function createI18n< } } - return i18n as I18n + // TODO: return i18n as I18n + return i18n as any } /** @@ -499,11 +497,8 @@ export function useI18n< Options extends UseI18nOptions = object, Messages extends Record< keyof Options['messages'], - LocaleMessageDictionary - > = Record< - keyof Options['messages'], - LocaleMessageDictionary - >, + LocaleMessage + > = Record>, DateTimeFormats extends Record< keyof Options['datetimeFormats'], DateTimeFormat @@ -568,7 +563,7 @@ export function useI18n< const locales = Object.keys(messages) if (locales.length) { locales.forEach(locale => { - global.mergeLocaleMessage(locale, messages![locale]) + global.mergeLocaleMessage(locale, messages![locale] as any) }) } // merge datetime formats @@ -589,7 +584,7 @@ export function useI18n< }) } } - return global + return global as any } if (scope === 'parent') { @@ -619,19 +614,21 @@ export function useI18n< const type = instance.type as ComponentOptions const composerOptions: ComposerOptions & ComposerInternalOptions< + VueMessageType, Messages, DateTimeFormats, NumberFormats > = assign({}, options) if (type.__i18n) { - composerOptions.__i18n = type.__i18n + composerOptions.__i18n = type.__i18n as any } if (global) { - composerOptions.__root = global + composerOptions.__root = global as any } + /* composer = createComposer(composerOptions) as Composer< Messages, DateTimeFormats, @@ -649,9 +646,25 @@ export function useI18n< NumberFormats, Composer >(instance, composer) + */ + composer = createComposer(composerOptions) as any + setupLifeCycle( + i18nInternal, + instance, + composer as any + ) + + i18nInternal.__setInstance< + Messages, + DateTimeFormats, + NumberFormats, + Composer + >(instance, composer as any) } - return composer as Composer + // TODO: + // return composer as Composer + return composer as any } function getComposer< diff --git a/packages/vue-i18n/src/index.ts b/packages/vue-i18n/src/index.ts index 4230311e4..a11d2aa82 100644 --- a/packages/vue-i18n/src/index.ts +++ b/packages/vue-i18n/src/index.ts @@ -14,7 +14,7 @@ export { FallbackLocale, LocaleMessageValue, LocaleMessageDictionary, - LocaleMessageArray, + LocaleMessageType, LocaleMessages, NumberFormat as IntlNumberFormat, DateTimeFormat as IntlDateTimeFormat, diff --git a/packages/vue-i18n/src/legacy.ts b/packages/vue-i18n/src/legacy.ts index e8930ded1..656e5842b 100644 --- a/packages/vue-i18n/src/legacy.ts +++ b/packages/vue-i18n/src/legacy.ts @@ -405,7 +405,7 @@ export interface VueI18n< * * @VueI18nSee [Getting Started](../guide/) */ - readonly messages: Messages + readonly messages: LocaleMessages /** * @remarks * The datetime formats of localization. @@ -1122,9 +1122,19 @@ function convertComposerOptions< NumberFormats = {} >( options: VueI18nOptions & - ComposerInternalOptions + ComposerInternalOptions< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + > ): ComposerOptions & - ComposerInternalOptions { + ComposerInternalOptions< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + > { const locale = isString(options.locale) ? options.locale : 'en-US' const fallbackLocale = isString(options.fallbackLocale) || @@ -1169,10 +1179,13 @@ function convertComposerOptions< let messages = options.messages if (isPlainObject(options.sharedMessages)) { - const sharedMessages = options.sharedMessages as LocaleMessages + const sharedMessages = options.sharedMessages as Record< + Locale, + LocaleMessageValue + > const locales: Locale[] = Object.keys(sharedMessages) messages = locales.reduce((messages, locale) => { - const message = messages[locale] || (messages[locale] = {}) + const message = messages[locale] || (messages[locale] = {} as any) assign(message, sharedMessages[locale]) return messages }, (messages || {}) as LocaleMessages) as typeof options.messages @@ -1538,7 +1551,7 @@ export function createVueI18n< __onComponentInstanceCreated(target: VueI18n): void { const { componentInstanceCreatedListener } = options if (componentInstanceCreatedListener) { - componentInstanceCreatedListener(target, vueI18n) + componentInstanceCreatedListener(target, vueI18n as any) } } } @@ -1559,5 +1572,5 @@ export function createVueI18n< } } - return vueI18n + return vueI18n as any } diff --git a/packages/vue-i18n/src/mixin.ts b/packages/vue-i18n/src/mixin.ts index c379f60d2..ac8f5fd7c 100644 --- a/packages/vue-i18n/src/mixin.ts +++ b/packages/vue-i18n/src/mixin.ts @@ -44,11 +44,16 @@ export function defineMixin( const options = this.$options if (options.i18n) { const optionsI18n = options.i18n as VueI18nOptions & - ComposerInternalOptions + ComposerInternalOptions< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + > if (options.__i18n) { optionsI18n.__i18n = options.__i18n } - optionsI18n.__root = composer + optionsI18n.__root = composer as any if (this === this.$root) { this.$i18n = mergeToRoot(vuei18n, optionsI18n) } else { @@ -151,7 +156,12 @@ export function defineMixin( function mergeToRoot( root: VueI18n, options: VueI18nOptions & - ComposerInternalOptions + ComposerInternalOptions< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + > ): VueI18n { root.locale = options.locale || root.locale root.fallbackLocale = options.fallbackLocale || root.fallbackLocale @@ -173,10 +183,10 @@ function mergeToRoot( ) const messages = getLocaleMessages(root.locale, { messages: options.messages, - __i18n: options.__i18n + __i18n: options.__i18n as any }) Object.keys(messages).forEach(locale => - root.mergeLocaleMessage(locale, messages[locale]) + root.mergeLocaleMessage(locale, messages[locale] as any) ) if (options.datetimeFormats) { Object.keys(options.datetimeFormats).forEach(locale => diff --git a/packages/vue-i18n/src/runtime.ts b/packages/vue-i18n/src/runtime.ts index c6655e478..0cfb4f9f5 100644 --- a/packages/vue-i18n/src/runtime.ts +++ b/packages/vue-i18n/src/runtime.ts @@ -10,7 +10,7 @@ export { FallbackLocale, LocaleMessageValue, LocaleMessageDictionary, - LocaleMessageArray, + LocaleMessageType, LocaleMessages, NumberFormat as IntlNumberFormat, DateTimeFormat as IntlDateTimeFormat, diff --git a/test-d/core-base/context.test-d.ts b/test-d/core-base/context.test-d.ts index ebf57dacb..2e3b47d31 100644 --- a/test-d/core-base/context.test-d.ts +++ b/test-d/core-base/context.test-d.ts @@ -3,6 +3,8 @@ import { expectType } from '../index' import { CoreOptions, + SchemaParams, + LocaleParams, PickupFallbackLocales, createCoreContext } from '../../packages/core-base/src/context' @@ -83,7 +85,20 @@ const strictOptions = { } expectType(looseOptions) -expectType>(strictOptions) +expectType< + CoreOptions< + string, + SchemaParams< + { + message: ResourceSchema + datetime: MyDatetimeScehma + number: MyNumberSchema + }, + string + >, + LocaleParams<'en' | 'ja'> + > +>(strictOptions) // check loose context const looseCtx = createCoreContext(looseOptions) From 2511c525165f38ae7de4b2f1beb15de2c4d6c716 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Fri, 7 May 2021 02:56:08 +0900 Subject: [PATCH 03/24] WIP: composer type-safe implementation --- packages/vue-i18n/src/composer.ts | 817 ++++++++++++++++-------- packages/vue-i18n/src/devtools.ts | 10 +- packages/vue-i18n/src/directive.ts | 6 +- packages/vue-i18n/src/i18n.ts | 22 +- packages/vue-i18n/src/legacy.ts | 73 ++- packages/vue-i18n/src/mixin.ts | 6 +- packages/vue-i18n/test/composer.test.ts | 26 +- 7 files changed, 639 insertions(+), 321 deletions(-) diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index bcf0251d4..2b1155571 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -39,7 +39,8 @@ import { NOT_REOSLVED, handleFlatJson, MessageFunction, - setAdditionalMeta + setAdditionalMeta, + IsUnion } from '@intlify/core-base' import { VueDevToolsTimelineEvents } from '@intlify/vue-devtools' import { I18nWarnCodes, getWarnMessage } from './warnings' @@ -47,7 +48,7 @@ import { I18nErrorCodes, createI18nError } from './errors' import { VERSION } from './misc' import type { ComponentInternalInstance, VNode, VNodeArrayChildren } from 'vue' -import type { WritableComputedRef, ComputedRef } from '@vue/reactivity' +import type { Ref, WritableComputedRef, ComputedRef } from '@vue/reactivity' import type { Path, MessageResolver, @@ -59,12 +60,10 @@ import type { MessageType, Locale, LocaleMessageValue, + LocaleMessage, LocaleMessages, CoreContext, - CoreCommonContext, - CoreTranslationContext, CoreMissingHandler, - LocaleMessage, LocaleMessageDictionary, PostTranslationHandler, FallbackLocale, @@ -76,7 +75,12 @@ import type { NumberFormats as NumberFormatsType, DateTimeFormat, NumberFormat, - MetaInfo + MetaInfo, + PickupLocales, + PickupKeys, + FallbackLocales, + SchemaParams, + LocaleParams } from '@intlify/core-base' import type { VueDevToolsEmitter } from '@intlify/vue-devtools' @@ -120,6 +124,7 @@ export interface CustomBlock { export type CustomBlocks = Array> +// prettier-ignore /** * Composer Options * @@ -128,7 +133,56 @@ export type CustomBlocks = Array> * * @VueI18nComposition */ -export interface ComposerOptions { +export interface ComposerOptions< + Message = VueMessageType, + Schema extends { + message?: unknown + datetime?: unknown + number?: unknown + } = { + message: LocaleMessage + datetime: DateTimeFormat + number: NumberFormat + }, + Locales extends + | { + messages: unknown + datetimeFormats: unknown + numberFormats: unknown + } + | string = Locale, + MessagesLocales = Locales extends { messages: infer M } + ? M + : Locales extends string + ? Locales + : Locale, + DateTimeFormatsLocales = Locales extends { datetimeFormats: infer D } + ? D + : Locales extends string + ? Locales + : Locale, + NumberFormatsLocales = Locales extends { numberFormats: infer N } + ? N + : Locales extends string + ? Locales + : Locale, + MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, + DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, + NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, + Messages extends LocaleMessages< + MessageSchema, + MessagesLocales, + Message + > = LocaleMessages, + DateTimeFormats extends DateTimeFormatsType< + DateTimeSchema, + DateTimeFormatsLocales + > = DateTimeFormatsType, + NumberFormats extends NumberFormatsType< + NumberSchema, + NumberFormatsLocales + > = NumberFormatsType +> { /** * @remarks * The locale of localization. @@ -170,7 +224,7 @@ export interface ComposerOptions { * * @defaultValue `{}` */ - messages?: LocaleMessages + messages?: { [K in keyof Messages]: MessageSchema } /** * @remarks * Allow use flat json messages or not @@ -186,7 +240,7 @@ export interface ComposerOptions { * * @defaultValue `{}` */ - datetimeFormats?: DateTimeFormatsType + datetimeFormats?: { [K in keyof DateTimeFormats]: DateTimeSchema } /** * @remarks * The number formats of localization. @@ -195,7 +249,7 @@ export interface ComposerOptions { * * @defaultValue `{}` */ - numberFormats?: NumberFormatsType + numberFormats?: { [K in keyof NumberFormats]: NumberSchema } /** * @remarks * Custom Modifiers for linked messages. @@ -379,150 +433,25 @@ export interface ComposerOptions { * @internal */ export interface ComposerInternalOptions< + Message = VueMessageType, Messages = {}, DateTimeFormats = {}, - NumberFormats = {}, - Message = VueMessageType + NumberFormats = {} > { __i18n?: CustomBlocks __i18nGlobal?: CustomBlocks - __root?: Composer + __root?: Composer } /** - * Composer interfaces + * Locale message translation functions * * @remarks - * This is the interface for being used for Vue 3 Composition API. + * This is the interface for {@link Composer} * * @VueI18nComposition */ -export interface Composer< - Messages = {}, - DateTimeFormats = {}, - NumberFormats = {}, - Message = VueMessageType -> { - /** - * @remarks - * Instance ID. - */ - id: number - /** - * @remarks - * The current locale this Composer instance is using. - * - * If the locale contains a territory and a dialect, this locale contains an implicit fallback. - * - * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) - */ - locale: WritableComputedRef - /** - * @remarks - * The current fallback locales this Composer instance is using. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - fallbackLocale: WritableComputedRef - /** - * @remarks - * Whether inherit the root level locale to the component localization locale. - * - * @VueI18nSee [Local Scope](../guide/essentials/scope#local-scope-2) - */ - inheritLocale: boolean - /** - * @remarks - * The list of available locales in `messages` in lexical order. - */ - readonly availableLocales: Locale[] - /** - * @remarks - * The locale messages of localization. - * - * @VueI18nSee [Getting Started](../guide/) - */ - readonly messages: ComputedRef - /** - * @remarks - * The datetime formats of localization. - * - * @VueI18nSee [Datetime Formatting](../guide/essentials/datetime) - */ - readonly datetimeFormats: ComputedRef - /** - * @remarks - * The number formats of localization. - * - * @VueI18nSee [Number Formatting](../guide/essentials/number) - */ - readonly numberFormats: ComputedRef - /** - * @remarks - * Custom Modifiers for linked messages. - * - * @VueI18nSee [Custom Modifiers](../guide/essentials/syntax#custom-modifiers) - */ - readonly modifiers: LinkedModifiers - /** - * @remarks - * A set of rules for word pluralization - * - * @VueI18nSee [Custom Pluralization](../guide/essentials/pluralization#custom-pluralization) - */ - readonly pluralRules: PluralizationRules - /** - * @remarks - * Whether this composer instance is global or not - */ - readonly isGlobal: boolean - /** - * @remarks - * Whether suppress warnings outputted when localization fails. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - missingWarn: boolean | RegExp - /** - * @remarks - * Whether suppress fall back warnings when localization fails. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - fallbackWarn: boolean | RegExp - /** - * @remarks - * Whether to fall back to root level (global scope) localization when localization fails. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - fallbackRoot: boolean - /** - * @remarks - * Whether suppress warnings when falling back to either `fallbackLocale` or root. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - fallbackFormat: boolean - /** - * @remarks - * Whether to allow the use locale messages of HTML formatting. - * - * If you set `false`, will check the locale messages on the Composer instance. - * - * If you are specified `true`, a warning will be output at console. - * - * @VueI18nSee [HTML Message](../guide/essentials/syntax#html-message) - * @VueI18nSee [Change `warnHtmlInMessage` option default value](../guide/migration/breaking#change-warnhtmlinmessage-option-default-value) - */ - warnHtmlMessage: boolean - /** - * @remarks - * Whether interpolation parameters are escaped before the message is translated. - * - * @VueI18nSee [HTML Message](../guide/essentials/syntax#html-message) - */ - escapeParameter: boolean +export interface ComposerTranslation { /** * Locale message translation * @@ -539,7 +468,9 @@ export interface Composer< * * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) */ - t(key: Path | number): string + = PickupKeys>( + key: Key | number + ): string /** * Locale message translation for plurals * @@ -560,7 +491,11 @@ export interface Composer< * * @VueI18nSee [Pluralization](../guide/essentials/pluralization) */ - t(key: Path | number, plural: number, options?: TranslateOptions): string + = PickupKeys>( + key: Key | number, + plural: number, + options?: TranslateOptions + ): string /** * Locale message translation for missing default message * @@ -579,7 +514,11 @@ export interface Composer< * * @returns Translated message */ - t(key: Path | number, defaultMsg: string, options?: TranslateOptions): string + = PickupKeys>( + key: Key | number, + defaultMsg: string, + options?: TranslateOptions + ): string /** * Locale message translation for list interpolations * @@ -600,7 +539,11 @@ export interface Composer< * * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - t(key: Path | number, list: unknown[], options?: TranslateOptions): string + = PickupKeys>( + key: Key | number, + list: unknown[], + options?: TranslateOptions + ): string /** * Locale message translation for list interpolations and plurals * @@ -618,7 +561,11 @@ export interface Composer< * @VueI18nSee [Pluralization](../guide/essentials/pluralization) * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - t(key: Path | number, list: unknown[], plural: number): string + = PickupKeys>( + key: Key | number, + list: unknown[], + plural: number + ): string /** * Locale message translation for list interpolations and missing default message * @@ -635,7 +582,11 @@ export interface Composer< * * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - t(key: Path | number, list: unknown[], defaultMsg: string): string + = PickupKeys>( + key: Key | number, + list: unknown[], + defaultMsg: string + ): string /** * Locale message translation for named interpolations * @@ -656,7 +607,11 @@ export interface Composer< * * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - t(key: Path | number, named: NamedValue, options?: TranslateOptions): string + = PickupKeys>( + key: Key | number, + named: NamedValue, + options?: TranslateOptions + ): string /** * Locale message translation for named interpolations and plurals * @@ -674,7 +629,11 @@ export interface Composer< * @VueI18nSee [Pluralization](../guide/essentials/pluralization) * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - t(key: Path | number, named: NamedValue, plural: number): string + = PickupKeys>( + key: Key | number, + named: NamedValue, + plural: number + ): string /** * Locale message translation for named interpolations and plurals * @@ -691,9 +650,25 @@ export interface Composer< * * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - t(key: Path | number, named: NamedValue, defaultMsg: string): string - /** @internal */ - t(...args: unknown[]): string + = PickupKeys>( + key: Key | number, + named: NamedValue, + defaultMsg: string + ): string +} + +/** + * Resolve locale message translation functions + * + * @remarks + * This is the interface for {@link Composer} + * + * @VueI18nComposition + */ +export interface ComposerResolveLocaleMessageTranslation< + Message, + Locales = 'en-US' +> { /** * Resolve locale message translation * @@ -716,7 +691,7 @@ export interface Composer< * * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) */ - rt(message: MessageFunction | Message): string + (message: MessageFunction | Message): string /** * Resolve locale message translation for plurals * @@ -739,10 +714,10 @@ export interface Composer< * * @VueI18nSee [Pluralization](../guide/essentials/pluralization) */ - rt( + ( message: MessageFunction | Message, plural: number, - options?: TranslateOptions + options?: TranslateOptions ): string /** * Resolve locale message translation for list interpolations @@ -766,10 +741,10 @@ export interface Composer< * * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - rt( + ( message: MessageFunction | Message, list: unknown[], - options?: TranslateOptions + options?: TranslateOptions ): string /** * Resolve locale message translation for named interpolations @@ -793,13 +768,25 @@ export interface Composer< * * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - rt( + ( message: MessageFunction | Message, named: NamedValue, - options?: TranslateOptions + options?: TranslateOptions ): string - /** @internal */ - rt(...args: unknown[]): string +} + +/** + * Datetime formatting functions + * + * @remarks + * This is the interface for {@link Composer} + * + * @VueI18nComposition + */ +export interface ComposerDateTimeFormatting< + DateTimeFormats = {}, + Locales = 'en-US' +> { /** * Datetime formatting * @@ -816,7 +803,9 @@ export interface Composer< * * @VueI18nSee [Datetime formatting](../guide/essentials/datetime) */ - d(value: number | Date | string): string + = PickupKeys>( + value: number | Date | string + ): string /** * Datetime formatting * @@ -826,11 +815,14 @@ export interface Composer< * In this overloaded `d`, format in datetime format for a key registered in datetime formats. * * @param value - A value, timestamp number or `Date` instance or ISO 8601 string - * @param key - A key of datetime formats + * @param keyOrOptions - A key of datetime formats, or additional {@link DateTimeOptions | options} for datetime formatting * * @returns Formatted value */ - d(value: number | Date | string, key: string): string + = PickupKeys>( + value: number | Date | string, + keyOrOptions: Key | DateTimeOptions + ): string /** * Datetime formatting * @@ -840,30 +832,30 @@ export interface Composer< * In this overloaded `d`, format in datetime format for a key registered in datetime formats at target locale * * @param value - A value, timestamp number or `Date` instance or ISO 8601 string - * @param key - A key of datetime formats + * @param keyOrOptions - A key of datetime formats, or additional {@link DateTimeOptions | options} for datetime formatting * @param locale - A locale, it will be used over than global scope or local scope. * * @returns Formatted value */ - d(value: number | Date | string, key: string, locale: Locale): string - /** - * Datetime formatting - * - * @remarks - * Overloaded `d`. About details, see the [d](composition#d-value) details. - * - * You can also suppress the warning, when the formatting missing according to the options. - * - * About details of options, see the {@link DateTimeOptions}. - * - * @param value - A value, timestamp number or `Date` instance or ISO 8601 string - * @param options - Additional {@link DateTimeOptions | options} for datetime formatting - * - * @returns Formatted value - */ - d(value: number | Date | string, options: DateTimeOptions): string - /** @internal */ - d(...args: unknown[]): string + = PickupKeys>( + value: number | Date | string, + keyOrOptions: Key | DateTimeOptions, + locale: Locales + ): string +} + +/** + * Number formatting functions + * + * @remarks + * This is the interface for {@link Composer} + * + * @VueI18nComposition + */ +export interface ComposerNumberFormatting< + NumberFormats = {}, + Locales = 'en-US' +> { /** * Number Formatting * @@ -880,7 +872,7 @@ export interface Composer< * * @VueI18nSee [Number formatting](../guide/essentials/number) */ - n(value: number): string + (value: number): string /** * Number Formatting * @@ -890,11 +882,14 @@ export interface Composer< * In this overloaded `n`, format in number format for a key registered in number formats. * * @param value - A number value - * @param key - A key of number formats + * @param keyOrOptions - A key of number formats, or additional {@link NumberOptions | options} for number formatting * * @returns Formatted value */ - n(value: number, key: string): string + = PickupKeys>( + value: number, + keyOrOptions: Key | NumberOptions + ): string /** * Number Formatting * @@ -904,31 +899,244 @@ export interface Composer< * In this overloaded `n`, format in number format for a key registered in number formats at target locale. * * @param value - A number value - * @param key - A key of number formats + * @param keyOrOptions - A key of number formats, or additional {@link NumberOptions | options} for number formatting * @param locale - A locale, it will be used over than global scope or local scope. * * @returns Formatted value */ - n(value: number, key: string, locale: Locale): string + = PickupKeys>( + value: number, + keyOrOptions: Key | NumberOptions, + locale: Locales + ): string +} + +/** + * Composer interfaces + * + * @remarks + * This is the interface for being used for Vue 3 Composition API. + * + * @VueI18nComposition + */ +export interface Composer< + Message = VueMessageType, + Messages = {}, + DateTimeFormats = {}, + NumberFormats = {}, + OptionLocale = unknown, + Schema extends { + message?: unknown + datetime?: unknown + number?: unknown + } = { + message: LocaleMessage + datetime: DateTimeFormat + number: NumberFormat + }, + SchemaLocales extends + | { + messages: unknown + datetimeFormats: unknown + numberFormats: unknown + } + | string = Locale, + MessagesLocales = SchemaLocales extends { messages: infer M } + ? M + : SchemaLocales extends string + ? SchemaLocales + : Locale, + DateTimeFormatsLocales = SchemaLocales extends { datetimeFormats: infer D } + ? D + : SchemaLocales extends string + ? SchemaLocales + : SchemaLocales, + NumberFormatsLocales = SchemaLocales extends { numberFormats: infer N } + ? N + : SchemaLocales extends string + ? SchemaLocales + : Locale, + MessageSchema = Schema extends { message: infer M } + ? M + : LocaleMessage, + DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, + NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, + MessagesEntity extends LocaleMessages< + MessageSchema, + MessagesLocales, + Message + > = LocaleMessages, + DateTimeFormatsEntity extends DateTimeFormatsType< + DateTimeSchema, + DateTimeFormatsLocales + > = DateTimeFormatsType, + NumberFormatsEntity extends NumberFormatsType< + NumberSchema, + NumberFormatsLocales + > = NumberFormatsType, + M = { [K in keyof Messages]: Messages[K] }, + ResourceLocales = + | PickupLocales> + | PickupLocales> + | PickupLocales>, + Locales = OptionLocale extends string + ? [ResourceLocales] extends [never] + ? string + : ResourceLocales + : OptionLocale | ResourceLocales +> { + /** + * @remarks + * Instance ID. + */ + id: number /** + * @remarks + * The current locale this Composer instance is using. * - * Number Formatting + * If the locale contains a territory and a dialect, this locale contains an implicit fallback. * + * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) + */ + locale: WritableComputedRef + /** * @remarks - * Overloaded `n`. About details, see the [n](composition#n-value) details. + * The current fallback locales this Composer instance is using. * - * You can also suppress the warning, when the formatting missing according to the options. + * @VueI18nSee [Fallbacking](../guide/essentials/fallback) + */ + fallbackLocale: WritableComputedRef> + /** + * @remarks + * Whether inherit the root level locale to the component localization locale. * - * About details of options, see the {@link NumberOptions}. + * @VueI18nSee [Local Scope](../guide/essentials/scope#local-scope-2) + */ + inheritLocale: boolean + /** + * @remarks + * The list of available locales in `messages` in lexical order. + */ + readonly availableLocales: Locales[] + /** + * @remarks + * The locale messages of localization. * - * @param value - A number value - * @param options - Additional {@link NumberOptions | options} for number formatting + * @VueI18nSee [Getting Started](../guide/) + */ + readonly messages: ComputedRef<{ [K in keyof Messages]: Messages[K] }> + /** + * @remarks + * The datetime formats of localization. * - * @returns Formatted value + * @VueI18nSee [Datetime Formatting](../guide/essentials/datetime) */ - n(value: number, options: NumberOptions): string - /** @internal */ - n(...args: unknown[]): string + readonly datetimeFormats: ComputedRef< + { [K in keyof DateTimeFormats]: DateTimeFormats[K] } + > + /** + * @remarks + * The number formats of localization. + * + * @VueI18nSee [Number Formatting](../guide/essentials/number) + */ + readonly numberFormats: ComputedRef< + { [K in keyof NumberFormats]: NumberFormats[K] } + > + /** + * @remarks + * Custom Modifiers for linked messages. + * + * @VueI18nSee [Custom Modifiers](../guide/essentials/syntax#custom-modifiers) + */ + readonly modifiers: LinkedModifiers + /** + * @remarks + * A set of rules for word pluralization + * + * @VueI18nSee [Custom Pluralization](../guide/essentials/pluralization#custom-pluralization) + */ + readonly pluralRules: PluralizationRules + /** + * @remarks + * Whether this composer instance is global or not + */ + readonly isGlobal: boolean + /** + * @remarks + * Whether suppress warnings outputted when localization fails. + * + * @VueI18nSee [Fallbacking](../guide/essentials/fallback) + */ + missingWarn: boolean | RegExp + /** + * @remarks + * Whether suppress fall back warnings when localization fails. + * + * @VueI18nSee [Fallbacking](../guide/essentials/fallback) + */ + fallbackWarn: boolean | RegExp + /** + * @remarks + * Whether to fall back to root level (global scope) localization when localization fails. + * + * @VueI18nSee [Fallbacking](../guide/essentials/fallback) + */ + fallbackRoot: boolean + /** + * @remarks + * Whether suppress warnings when falling back to either `fallbackLocale` or root. + * + * @VueI18nSee [Fallbacking](../guide/essentials/fallback) + */ + fallbackFormat: boolean + /** + * @remarks + * Whether to allow the use locale messages of HTML formatting. + * + * If you set `false`, will check the locale messages on the Composer instance. + * + * If you are specified `true`, a warning will be output at console. + * + * @VueI18nSee [HTML Message](../guide/essentials/syntax#html-message) + * @VueI18nSee [Change `warnHtmlInMessage` option default value](../guide/migration/breaking#change-warnhtmlinmessage-option-default-value) + */ + warnHtmlMessage: boolean + /** + * @remarks + * Whether interpolation parameters are escaped before the message is translated. + * + * @VueI18nSee [HTML Message](../guide/essentials/syntax#html-message) + */ + escapeParameter: boolean + /** + * Locale message translation + * + * @remarks + * About details functions, See the {@link ComposerTranslation} + */ + t: ComposerTranslation + /** + * Resolve locale message translation + * + * @remarks + * About details functions, See the {@link ComposerResolveLocaleMessageTranslation} + */ + rt: ComposerResolveLocaleMessageTranslation + /** + * Datetime formatting + * + * @remarks + * About details functions, See the {@link ComposerDateTimeFormatting} + */ + d: ComposerDateTimeFormatting + /** + * Number Formatting + * + * @remarks + * About details functions, See the {@link ComposerNumberFormatting} + */ + n: ComposerNumberFormatting /** * Translation locale message exist * @@ -942,7 +1150,10 @@ export interface Composer< * * @returns If found locale message, `true`, else `false` */ - te(key: Path, locale?: Locale): boolean + te = PickupKeys>( + key: Key, + locale?: Locales + ): boolean /** * Locale messages getter * @@ -1003,7 +1214,9 @@ export interface Composer< * * @return Locale messages */ - tm(key: Path): LocaleMessageValue | {} + tm = PickupKeys>( + key: Key | string // TODO: dynamic type! + ): LocaleMessageValue /** * Get locale message * @@ -1014,7 +1227,15 @@ export interface Composer< * * @returns Locale messages */ - getLocaleMessage(locale: Locale): LocaleMessageDictionary + getLocaleMessage< + LocaleSchema extends string = never, + MessageSchema extends LocaleMessage = {}, + Locale extends PickupLocales> = PickupLocales< + NonNullable + > + >( + locale: LocaleSchema | Locale + ): Ref[Locale]> // TODO: dynamic type ! /** * Set locale message * @@ -1024,9 +1245,15 @@ export interface Composer< * @param locale - A target locale * @param message - A message */ - setLocaleMessage( - locale: Locale, - message: LocaleMessageDictionary + setLocaleMessage< + LocaleSchema extends string = never, + MessageSchema extends LocaleMessage = {}, + Locale extends PickupLocales> = PickupLocales< + NonNullable + > + >( + locale: LocaleSchema | Locale, + message: NonNullable[Locale] | MessageSchema // TODO: dynamic type ! ): void /** * Merge locale message @@ -1037,9 +1264,15 @@ export interface Composer< * @param locale - A target locale * @param message - A message */ - mergeLocaleMessage( - locale: Locale, - message: LocaleMessageDictionary + mergeLocaleMessage< + LocaleSchema extends string = never, + MessageSchema extends LocaleMessage = {}, + Locale extends PickupLocales> = PickupLocales< + NonNullable + > + >( + locale: LocaleSchema | Locale, + message: NonNullable[Locale] | MessageSchema // TODO: dynamic type ! ): void /** * Get datetime format @@ -1159,7 +1392,7 @@ function defineCoreMissingHandler( missing: MissingHandler ): CoreMissingHandler { return (( - ctx: CoreCommonContext, + ctx: CoreContext, locale: Locale, key: Path, type: string @@ -1168,17 +1401,17 @@ function defineCoreMissingHandler( }) as CoreMissingHandler } -type GetLocaleMessagesOptions = { - messages?: LocaleMessages +type GetLocaleMessagesOptions = { + messages?: { [K in keyof Messages]: Messages[K] } __i18n?: CustomBlocks messageResolver?: MessageResolver flatJson?: boolean } -export function getLocaleMessages( +export function getLocaleMessages( locale: Locale, - options: GetLocaleMessagesOptions -): LocaleMessages { + options: GetLocaleMessagesOptions +): { [K in keyof Messages]: Messages[K] } { const { messages, __i18n, messageResolver, flatJson } = options // prettier-ignore @@ -1209,7 +1442,7 @@ export function getLocaleMessages( } } - return ret as any + return ret as { [K in keyof Messages]: Messages[K] } } const isNotObjectOrIsArray = (val: unknown) => !isObject(val) || isArray(val) @@ -1243,39 +1476,58 @@ const getMetaInfo = /* #__PURE__*/ (): MetaInfo | null => { : null } -/** - * Create composer interface factory - * - * @internal - */ export function createComposer< Message = VueMessageType, - Options extends ComposerOptions = object, - Messages extends Record< - keyof Options['messages'], - LocaleMessage - > = Record>, - DateTimeFormats extends Record< - keyof Options['datetimeFormats'], - DateTimeFormat - > = Record, - NumberFormats extends Record< - keyof Options['numberFormats'], - NumberFormat - > = Record + Options extends ComposerOptions = {} >( - options: Options = {} as Options + options: Options ): Composer< + Message, Options['messages'], Options['datetimeFormats'], Options['numberFormats'], - Message -> { + Options['locale'], + SchemaParams, Message> +> + +export function createComposer< + Schema = LocaleMessage, + Locales = 'en-US', + Message = VueMessageType, + Options extends ComposerOptions< + Message, + SchemaParams, + LocaleParams + > = ComposerOptions< + Message, + SchemaParams, + LocaleParams + > +>( + options: Options +): Composer< + Message, + Options['messages'], + Options['datetimeFormats'], + Options['numberFormats'], + Options['locale'], + SchemaParams, + LocaleParams +> + +/** + * Create composer interface factory + * + * @internal + */ +export function createComposer( + options: any = {} +): any { const { __root } = options as ComposerInternalOptions< - Messages, - DateTimeFormats, - NumberFormats, - Message + Message, + LocaleMessages>, + DateTimeFormatsType, + NumberFormatsType > const _isGlobal = __root === undefined @@ -1304,8 +1556,11 @@ export function createComposer< : _locale.value ) - const _messages = ref>( - getLocaleMessages(_locale.value, options) + const _messages = ref>>( + getLocaleMessages>>( + _locale.value as Locale, + options + ) ) const _datetimeFormats = ref( @@ -1463,17 +1718,17 @@ export function createComposer< }) // messages - const messages = computed(() => _messages.value as Messages) + const messages = computed, Message>>( + () => _messages.value as any + ) // datetimeFormats - const datetimeFormats = computed( - () => _datetimeFormats.value as DateTimeFormats + const datetimeFormats = computed( + () => _datetimeFormats.value ) // numberFormats - const numberFormats = computed( - () => _numberFormats.value as NumberFormats - ) + const numberFormats = computed(() => _numberFormats.value) // getPostTranslationHandler function getPostTranslationHandler(): PostTranslationHandler | null { @@ -1582,7 +1837,7 @@ export function createComposer< context => Reflect.apply(translate, null, [context, ...args]) as string, () => parseTranslateArgs(...args), 'translate', - root => root.t(...args), + root => Reflect.apply(root.t, root, [...args]), key => key as string, val => isString(val) ) @@ -1603,7 +1858,7 @@ export function createComposer< context => Reflect.apply(datetime, null, [context, ...args]) as string, () => parseDateTimeArgs(...args), 'datetime format', - root => root.d(...args), + root => Reflect.apply(root.d, root, [...args]), () => MISSING_RESOLVE_VALUE, val => isString(val) ) @@ -1615,7 +1870,7 @@ export function createComposer< context => Reflect.apply(number, null, [context, ...args]) as string, () => parseNumberArgs(...args), 'number format', - root => root.n(...args), + root => Reflect.apply(root.n, root, [...args]), () => MISSING_RESOLVE_VALUE, val => isString(val) ) @@ -1641,7 +1896,10 @@ export function createComposer< return wrapWithDeps( context => { let ret: unknown - const _context = context as CoreTranslationContext + const _context = context as CoreContext< + VNode, + LocaleMessages> + > try { _context.processor = processor ret = Reflect.apply(translate, null, [_context, ...args]) @@ -1724,29 +1982,32 @@ export function createComposer< return messages != null ? messages : __root - ? __root.tm(key) as LocaleMessageValue || {} + ? __root.tm(key as any) as LocaleMessageValue || {} : {} } // getLocaleMessage - function getLocaleMessage(locale: Locale): LocaleMessage { - return (_messages.value[locale] || {}) as LocaleMessage + function getLocaleMessage(locale: Locale): LocaleMessageDictionary { + return (_messages.value[locale] || {}) as LocaleMessageDictionary } // setLocaleMessage - function setLocaleMessage(locale: Locale, message: LocaleMessage) { - _messages.value[locale] = message as any - _context.messages = _messages.value as any + function setLocaleMessage( + locale: Locale, + message: LocaleMessageDictionary + ) { + _messages.value[locale] = message + _context.messages = _messages.value as typeof _context.messages } // mergeLocaleMessage function mergeLocaleMessage( locale: Locale, - message: LocaleMessage + message: LocaleMessageDictionary ): void { - _messages.value[locale] = _messages.value[locale] || ({} as any) + _messages.value[locale] = _messages.value[locale] || {} deepCopy(message, _messages.value[locale]) - _context.messages = _messages.value as any + _context.messages = _messages.value as typeof _context.messages } // getDateTimeFormat @@ -1757,8 +2018,8 @@ export function createComposer< // setDateTimeFormat function setDateTimeFormat(locale: Locale, format: DateTimeFormat): void { _datetimeFormats.value[locale] = format - _context.datetimeFormats = _datetimeFormats.value as typeof _context.datetimeFormats - clearDateTimeFormat( + _context.datetimeFormats = _datetimeFormats.value + clearDateTimeFormat( _context as any, locale, format @@ -1771,8 +2032,8 @@ export function createComposer< _datetimeFormats.value[locale] || {}, format ) - _context.datetimeFormats = _datetimeFormats.value as typeof _context.datetimeFormats - clearDateTimeFormat( + _context.datetimeFormats = _datetimeFormats.value + clearDateTimeFormat( _context as any, locale, format @@ -1787,8 +2048,12 @@ export function createComposer< // setNumberFormat function setNumberFormat(locale: Locale, format: NumberFormat): void { _numberFormats.value[locale] = format - _context.numberFormats = _numberFormats.value as typeof _context.numberFormats - clearNumberFormat(_context as any, locale, format) + _context.numberFormats = _numberFormats.value + clearNumberFormat( + _context as any, + locale, + format + ) } // mergeNumberFormat @@ -1797,8 +2062,12 @@ export function createComposer< _numberFormats.value[locale] || {}, format ) - _context.numberFormats = _numberFormats.value as typeof _context.numberFormats - clearNumberFormat(_context as any, locale, format) + _context.numberFormats = _numberFormats.value + clearNumberFormat( + _context as any, + locale, + format + ) } // for debug @@ -1806,7 +2075,7 @@ export function createComposer< // watch root locale & fallbackLocale if (__root) { - watch(__root.locale, (val: Locale) => { + watch(__root.locale as any, (val: Locale) => { if (_inheritLocale) { _locale.value = val _context.locale = val @@ -1817,7 +2086,7 @@ export function createComposer< ) } }) - watch(__root.fallbackLocale, (val: FallbackLocale) => { + watch(__root.fallbackLocale as any, (val: FallbackLocale) => { if (_inheritLocale) { _fallbackLocale.value = val _context.fallbackLocale = val as any @@ -1841,8 +2110,8 @@ export function createComposer< set inheritLocale(val: boolean) { _inheritLocale = val if (val && __root) { - _locale.value = __root.locale.value - _fallbackLocale.value = __root.fallbackLocale.value + _locale.value = __root.locale.value as Locale + _fallbackLocale.value = __root.fallbackLocale.value as FallbackLocale updateFallbackLocale( _context as any, _locale.value, @@ -1943,7 +2212,7 @@ export function createComposer< } } - return composer as any + return composer } /* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/packages/vue-i18n/src/devtools.ts b/packages/vue-i18n/src/devtools.ts index 861f18189..4975b67af 100644 --- a/packages/vue-i18n/src/devtools.ts +++ b/packages/vue-i18n/src/devtools.ts @@ -363,7 +363,12 @@ function getComposer< ) if (instance) { return i18n.mode === 'composition' - ? (instance as Composer) + ? // TODO: + ((instance as unknown) as Composer< + Messages, + DateTimeFormats, + NumberFormats + >) : ((instance as unknown) as VueI18nInternal< Messages, DateTimeFormats, @@ -387,7 +392,8 @@ function inspectScope< ): any { const composer = getComposer(payload.nodeId, i18n) if (composer) { - payload.state = makeScopeInspectState(composer) + // TODO: + payload.state = makeScopeInspectState(composer as any) } return null } diff --git a/packages/vue-i18n/src/directive.ts b/packages/vue-i18n/src/directive.ts index f921f7ef6..3e30b0cfa 100644 --- a/packages/vue-i18n/src/directive.ts +++ b/packages/vue-i18n/src/directive.ts @@ -122,7 +122,11 @@ export function vTDirective< } const parsedValue = parseValue(value) - el.textContent = composer.t(...makeParams(parsedValue)) + // el.textContent = composer.t(...makeParams(parsedValue)) + // TODO: + el.textContent = Reflect.apply(composer.t, composer, [ + ...makeParams(parsedValue) + ]) } return { diff --git a/packages/vue-i18n/src/i18n.ts b/packages/vue-i18n/src/i18n.ts index 13c3d03b1..9a0791318 100644 --- a/packages/vue-i18n/src/i18n.ts +++ b/packages/vue-i18n/src/i18n.ts @@ -330,8 +330,8 @@ export function createI18n< >() // prettier-ignore const __global = __FEATURE_LEGACY_API__ && __legacyMode - ? createVueI18n(options) - : createComposer(options) + ? createVueI18n(options as any) // TODO: + : createComposer(options as any) // TODO: const symbol: InjectionKey | string = makeSymbol( __DEV__ ? 'vue-i18n' : '' ) @@ -431,7 +431,7 @@ export function createI18n< M extends Messages, Instance extends VueI18n | Composer >(component: ComponentInternalInstance, instance: Instance): void { - __instances.set(component, instance) + __instances.set(component, instance as any) // TODO: }, // @internal __deleteInstance(component: ComponentInternalInstance): void { @@ -510,6 +510,7 @@ export function useI18n< >( options: Options = {} as Options ): Composer< + VueMessageType, Options['messages'], Options['datetimeFormats'], Options['numberFormats'] @@ -554,7 +555,7 @@ export function useI18n< if (scope === 'global') { let messages = isObject(options.messages) ? options.messages : {} if ('__i18nGlobal' in instance.type) { - messages = getLocaleMessages(global.locale.value, { + messages = getLocaleMessages(global.locale.value as Locale, { messages, __i18n: instance.type.__i18nGlobal }) @@ -593,7 +594,13 @@ export function useI18n< if (__DEV__) { warn(getWarnMessage(I18nWarnCodes.NOT_FOUND_PARENT_SCOPE)) } - composer = global + composer = (global as unknown) as Composer< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats, + Options['locale'] + > } return composer } @@ -675,7 +682,7 @@ function getComposer< >( i18n: I18n, target: ComponentInternalInstance -): Composer | null { +): Composer | null { let composer: Composer | null = null const root = target.root let current: ComponentInternalInstance | null = target.parent @@ -713,7 +720,8 @@ function getComposer< } current = current.parent } - return composer + // TODO: + return composer as any } function setupLifeCycle( diff --git a/packages/vue-i18n/src/legacy.ts b/packages/vue-i18n/src/legacy.ts index 656e5842b..6a08a7802 100644 --- a/packages/vue-i18n/src/legacy.ts +++ b/packages/vue-i18n/src/legacy.ts @@ -22,6 +22,7 @@ import type { NamedValue, MessageFunction, Locale, + LocaleMessage, LocaleMessages, LocaleMessageDictionary, PostTranslationHandler, @@ -1128,7 +1129,7 @@ function convertComposerOptions< DateTimeFormats, NumberFormats > -): ComposerOptions & +): ComposerOptions & ComposerInternalOptions< VueMessageType, Messages, @@ -1177,7 +1178,10 @@ function convertComposerOptions< warn(getWarnMessage(I18nWarnCodes.NOT_SUPPORTED_PRESERVE_DIRECTIVE)) } - let messages = options.messages + // TODO: + let messages = (options.messages as unknown) as LocaleMessages< + LocaleMessage + > if (isPlainObject(options.sharedMessages)) { const sharedMessages = options.sharedMessages as Record< Locale, @@ -1188,7 +1192,7 @@ function convertComposerOptions< const message = messages[locale] || (messages[locale] = {} as any) assign(message, sharedMessages[locale]) return messages - }, (messages || {}) as LocaleMessages) as typeof options.messages + }, (messages || {}) as LocaleMessages>) } const { __i18n, __root } = options @@ -1251,7 +1255,13 @@ export function createVueI18n< > { const composer = createComposer( convertComposerOptions(options) - ) as Composer + ) as Composer< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats, + Options['locale'] + > // defines VueI18n const vueI18n = { @@ -1260,18 +1270,18 @@ export function createVueI18n< // locale get locale(): Locale { - return composer.locale.value + return composer.locale.value as Locale }, set locale(val: Locale) { - composer.locale.value = val + composer.locale.value = val as any }, // fallbackLocale get fallbackLocale(): FallbackLocale { - return composer.fallbackLocale.value + return composer.fallbackLocale.value as FallbackLocale }, set fallbackLocale(val: FallbackLocale) { - composer.fallbackLocale.value = val + composer.fallbackLocale.value = val as any }, // messages @@ -1291,7 +1301,7 @@ export function createVueI18n< // availableLocales get availableLocales(): Locale[] { - return composer.availableLocales + return composer.availableLocales as Locale[] }, // formatter @@ -1428,11 +1438,17 @@ export function createVueI18n< named = arg3 as NamedValue } - return composer.t(key, list || named || {}, options) + // TODO: + return composer.t( + key as any, + (list || named || {}) as any, + options as any + ) }, rt(...args: unknown[]): TranslateResult { - return composer.rt(...args) + // TODO: return composer.rt(...args) + return Reflect.apply(composer.rt, composer, [...args]) }, // tc @@ -1465,12 +1481,18 @@ export function createVueI18n< named = arg3 as NamedValue } - return composer.t(key, list || named || {}, options) + // TODO: + return composer.t( + key as any, + (list || named || {}) as any, + options as any + ) }, // te te(key: Path, locale?: Locale): boolean { - return composer.te(key, locale) + // TODO: + return composer.te(key as any, locale as any) }, // tm @@ -1480,7 +1502,8 @@ export function createVueI18n< // getLocaleMessage getLocaleMessage(locale: Locale): LocaleMessageDictionary { - return composer.getLocaleMessage(locale) + // TODO: + return composer.getLocaleMessage(locale as any) as any }, // setLocaleMessage @@ -1488,7 +1511,8 @@ export function createVueI18n< locale: Locale, message: LocaleMessageDictionary ): void { - composer.setLocaleMessage(locale, message) + // TODO: + composer.setLocaleMessage(locale, message as any) }, // mergeLocaleMessage @@ -1496,12 +1520,15 @@ export function createVueI18n< locale: Locale, message: LocaleMessageDictionary ): void { - composer.mergeLocaleMessage(locale, message) + // TODO: + composer.mergeLocaleMessage(locale, message as any) }, // d d(...args: unknown[]): DateTimeFormatResult { - return composer.d(...args) + // return composer.d(...args) + // TODO: + return Reflect.apply(composer.d, composer, [...args]) }, // getDateTimeFormat @@ -1521,7 +1548,9 @@ export function createVueI18n< // n n(...args: unknown[]): NumberFormatResult { - return composer.n(...args) + // return composer.n(...args) + // TODO: + return Reflect.apply(composer.n, composer, [...args]) }, // getNumberFormat @@ -1558,14 +1587,14 @@ export function createVueI18n< // for vue-devtools timeline event if (__DEV__) { - ;(vueI18n as VueI18nInternal).__enableEmitter = ( - emitter: VueDevToolsEmitter - ): void => { + // TODO: + ;(vueI18n as any).__enableEmitter = (emitter: VueDevToolsEmitter): void => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const __composer = composer as any __composer[EnableEmitter] && __composer[EnableEmitter](emitter) } - ;(vueI18n as VueI18nInternal).__disableEmitter = (): void => { + // TODO: + ;(vueI18n as any).__disableEmitter = (): void => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const __composer = composer as any __composer[DisableEmitter] && __composer[DisableEmitter]() diff --git a/packages/vue-i18n/src/mixin.ts b/packages/vue-i18n/src/mixin.ts index ac8f5fd7c..761cc8257 100644 --- a/packages/vue-i18n/src/mixin.ts +++ b/packages/vue-i18n/src/mixin.ts @@ -55,7 +55,8 @@ export function defineMixin( } optionsI18n.__root = composer as any if (this === this.$root) { - this.$i18n = mergeToRoot(vuei18n, optionsI18n) + // TODO; + this.$i18n = mergeToRoot(vuei18n as any, optionsI18n as any) } else { this.$i18n = createVueI18n(optionsI18n) } @@ -186,7 +187,8 @@ function mergeToRoot( __i18n: options.__i18n as any }) Object.keys(messages).forEach(locale => - root.mergeLocaleMessage(locale, messages[locale] as any) + // TODO: + root.mergeLocaleMessage(locale, (messages as any)[locale] as any) ) if (options.datetimeFormats) { Object.keys(options.datetimeFormats).forEach(locale => diff --git a/packages/vue-i18n/test/composer.test.ts b/packages/vue-i18n/test/composer.test.ts index f66bb6211..fc865ee08 100644 --- a/packages/vue-i18n/test/composer.test.ts +++ b/packages/vue-i18n/test/composer.test.ts @@ -400,7 +400,7 @@ describe('fallbackFormat', () => { } }) - expect(t('hi, {name}!', { name: 'kazupon' })).toEqual('hi, kazupon!') + expect(t('hi, {name}!' as any, { name: 'kazupon' })).toEqual('hi, kazupon!') expect(mockWarn).toHaveBeenCalledTimes(5) }) }) @@ -440,8 +440,8 @@ describe('fallbackRoot', () => { fr: {} }, __root: root - } as any) - expect(t('hello')).toEqual('hello') + }) + expect(t('hello' as any)).toEqual('hello') expect(mockWarn).toHaveBeenCalled() expect(mockWarn.mock.calls[0][0]).toEqual( getWarnMessage(I18nWarnCodes.FALLBACK_TO_ROOT, { @@ -473,8 +473,8 @@ describe('fallbackRoot', () => { fr: {} }, __root: root - } as any) - expect(t('hello')).toEqual('hello') + }) + expect(t('hello' as any)).toEqual('hello') expect(mockWarn).not.toHaveBeenCalledTimes(1) }) }) @@ -659,7 +659,7 @@ describe('t', () => { en: {} } }) - expect(t('foo.bar.buz')).toEqual('FOO.BAR.BUZ') + expect(t('foo.bar.buz' as any)).toEqual('FOO.BAR.BUZ') }) test('computed property name', () => { @@ -803,7 +803,7 @@ describe('d', () => { } }) const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) - expect(d(dt, { key: 'long' })).toEqual('') + expect(d(dt, { key: 'long' as any })).toEqual('') }) test('iso', () => { @@ -976,7 +976,7 @@ describe('n', () => { 'en-US': {} } }) - expect(n(0.99, { key: 'percent' })).toEqual('') + expect(n(0.99, { key: 'percent' as any })).toEqual('') }) }) @@ -1099,8 +1099,8 @@ test('te', async () => { }) expect(te('message.hello')).toEqual(true) - expect(te('message.hallo')).toEqual(false) - expect(te('message.hallo', 'ja')).toEqual(false) + expect(te('message.hallo' as any)).toEqual(false) + expect(te('message.hallo' as any, 'ja' as any)).toEqual(false) }) describe('getLocaleMessage / setLocaleMessage / mergeLocaleMessage', () => { @@ -1629,7 +1629,7 @@ describe('root', () => { __root }) - expect(t('hello')).toEqual('hello!') + expect(t('hello' as any)).toEqual('hello!') }) test('d', () => { @@ -1658,7 +1658,7 @@ describe('root', () => { }) const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) - expect(d(dt, { key: 'short' })).toEqual('12/19/2012, 10:00 PM') + expect(d(dt, { key: 'short' as any })).toEqual('12/19/2012, 10:00 PM') }) test('n', () => { @@ -1682,7 +1682,7 @@ describe('root', () => { __root }) - expect(n(0.99, { key: 'percent' })).toEqual('99%') + expect(n(0.99, { key: 'percent' as any })).toEqual('99%') }) }) From 548e7e3dd0ff29aa5ff3035b521da3d41e8a1bb4 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Sun, 9 May 2021 00:19:36 +0900 Subject: [PATCH 04/24] more updates --- packages/core-base/src/datetime.ts | 63 +++-- packages/core-base/src/number.ts | 57 ++++- packages/core-base/src/translate.ts | 106 ++++++-- packages/core-base/test/datetime.test.ts | 2 +- packages/core-base/test/number.test.ts | 2 +- packages/core-base/test/translate.test.ts | 76 ++---- packages/vue-i18n/src/composer.ts | 184 ++++++++++---- packages/vue-i18n/test/composer.test.ts | 70 ++++-- test-d/core-base/context.test-d.ts | 23 +- test-d/core-base/datetime.test-d.ts | 39 +++ test-d/core-base/number.test-d.ts | 34 +++ test-d/core-base/translate.test-d.ts | 43 ++++ test-d/schema.ts | 19 ++ test-d/vue-i18n/composer.test-d.ts | 294 ++++++++++++++++++++++ 14 files changed, 813 insertions(+), 199 deletions(-) create mode 100644 test-d/core-base/datetime.test-d.ts create mode 100644 test-d/core-base/number.test-d.ts create mode 100644 test-d/core-base/translate.test-d.ts create mode 100644 test-d/schema.ts create mode 100644 test-d/vue-i18n/composer.test-d.ts diff --git a/packages/core-base/src/datetime.ts b/packages/core-base/src/datetime.ts index 09ef05868..5c7584530 100644 --- a/packages/core-base/src/datetime.ts +++ b/packages/core-base/src/datetime.ts @@ -24,7 +24,7 @@ import type { DateTimeFormat, DateTimeFormats as DateTimeFormatsType, DateTimeFormatOptions, - PickupKeys + PickupFormatKeys } from './types/index' import type { CoreContext, CoreInternalContext } from './context' @@ -104,7 +104,10 @@ export interface DateTimeOptions { part?: boolean } -// `datetime` function overloads +/** + * `datetime` function overloads + */ + export function datetime< Context extends CoreContext, Message = string @@ -112,43 +115,75 @@ export function datetime< context: Context, value: number | string | Date ): string | number | Intl.DateTimeFormatPart[] + export function datetime< Context extends CoreContext, - Key extends PickupKeys, + Value extends number | string | Date = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['datetimeFormats'] + > = PickupFormatKeys, Message = string >( context: Context, - value: number | string | Date, - keyOrOptions: Key | DateTimeOptions + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | DateTimeOptions ): string | number | Intl.DateTimeFormatPart[] + export function datetime< Context extends CoreContext, - Key extends PickupKeys, + Value extends number | string | Date = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['datetimeFormats'] + > = PickupFormatKeys, Message = string >( context: Context, - value: number | string | Date, - keyOrOptions: Key | DateTimeOptions, + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | DateTimeOptions, locale: Context['locale'] ): string | number | Intl.DateTimeFormatPart[] + export function datetime< Context extends CoreContext, - Key extends PickupKeys, + Value extends number | string | Date = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['datetimeFormats'] + > = PickupFormatKeys, Message = string >( context: Context, - value: number | string | Date, - keyOrOptions: Key | DateTimeOptions, + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | DateTimeOptions, override: Intl.DateTimeFormatOptions ): string | number | Intl.DateTimeFormatPart[] + export function datetime< Context extends CoreContext, - Key extends PickupKeys, + Value extends number | string | Date = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['datetimeFormats'] + > = PickupFormatKeys, Message = string >( context: Context, - value: number | string | Date, - keyOrOptions: Key | DateTimeOptions, + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | DateTimeOptions, locale: Context['locale'], override: Intl.DateTimeFormatOptions ): string | number | Intl.DateTimeFormatPart[] diff --git a/packages/core-base/src/number.ts b/packages/core-base/src/number.ts index 8eee801ee..79a902db4 100644 --- a/packages/core-base/src/number.ts +++ b/packages/core-base/src/number.ts @@ -23,7 +23,7 @@ import type { NumberFormat, NumberFormats as NumberFormatsType, NumberFormatOptions, - PickupKeys + PickupFormatKeys } from './types/index' import type { CoreContext, CoreInternalContext } from './context' @@ -102,48 +102,83 @@ export interface NumberOptions { part?: boolean } -// `number` function overloads +/** + * `number` function overloads + */ + export function number< Context extends CoreContext, Message = string >(context: Context, value: number): string | number | Intl.NumberFormatPart[] + export function number< Context extends CoreContext, - Key extends PickupKeys, + Value extends number = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['numberFormats'] + > = PickupFormatKeys, Message = string >( context: Context, - value: number, - keyOrOptions: Key | NumberOptions + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | NumberOptions ): string | number | Intl.NumberFormatPart[] + export function number< Context extends CoreContext, - Key extends PickupKeys, + Value extends number = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['numberFormats'] + > = PickupFormatKeys, Message = string >( context: Context, value: number, - keyOrOptions: Key | NumberOptions, + keyOrOptions: + | Key + | ResourceKeys + | NumberOptions, locale: Context['locale'] ): string | number | Intl.NumberFormatPart[] + export function number< Context extends CoreContext, - Key extends PickupKeys, + Value extends number = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['numberFormats'] + > = PickupFormatKeys, Message = string >( context: Context, value: number, - keyOrOptions: Key | NumberOptions, + keyOrOptions: + | Key + | ResourceKeys + | NumberOptions, override: Intl.NumberFormatOptions ): string | number | Intl.NumberFormatPart[] + export function number< Context extends CoreContext, - Key extends PickupKeys, + Value extends number = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys< + Context['numberFormats'] + > = PickupFormatKeys, Message = string >( context: Context, value: number, - keyOrOptions: Key | NumberOptions, + keyOrOptions: + | Key + | ResourceKeys + | NumberOptions, locale: Context['locale'], override: Intl.NumberFormatOptions ): string | number | Intl.NumberFormatPart[] diff --git a/packages/core-base/src/translate.ts b/packages/core-base/src/translate.ts index dda4fda27..d76c10612 100644 --- a/packages/core-base/src/translate.ts +++ b/packages/core-base/src/translate.ts @@ -154,75 +154,109 @@ export interface TranslateOptions { resolvedMessage?: boolean } -// `translate` function overloads +/** + * `translate` function overloads + */ + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction + key: Key | ResourceKeys | number | MessageFunction ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, plural: number ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, plural: number, options: TranslateOptions ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, defaultMsg: string ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, defaultMsg: string, options: TranslateOptions ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, list: unknown[] ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, list: unknown[], plural: number ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, @@ -230,52 +264,72 @@ export function translate< list: unknown[], defaultMsg: string ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, list: unknown[], options: TranslateOptions ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, named: NamedValue ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, named: NamedValue, plural: number ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, named: NamedValue, defaultMsg: string ): MessageType | number + export function translate< Context extends CoreContext, - Key extends PickupKeys, + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys< + Context['messages'] + >, Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, named: NamedValue, options: TranslateOptions ): MessageType | number diff --git a/packages/core-base/test/datetime.test.ts b/packages/core-base/test/datetime.test.ts index 54fbbed45..f87ab29f8 100644 --- a/packages/core-base/test/datetime.test.ts +++ b/packages/core-base/test/datetime.test.ts @@ -273,7 +273,7 @@ describe('context unresolving option', () => { datetimeFormats }) - expect(datetime(ctx, dt, 'custom' as any)).toEqual(NOT_REOSLVED) + expect(datetime(ctx, dt, 'custom')).toEqual(NOT_REOSLVED) expect(mockWarn).not.toHaveBeenCalled() }) }) diff --git a/packages/core-base/test/number.test.ts b/packages/core-base/test/number.test.ts index d65555498..25611e43f 100644 --- a/packages/core-base/test/number.test.ts +++ b/packages/core-base/test/number.test.ts @@ -256,7 +256,7 @@ describe('context unresolving option', () => { numberFormats }) - expect(number(ctx, 123456789, 'custom' as any)).toEqual(NOT_REOSLVED) + expect(number(ctx, 123456789, 'custom')).toEqual(NOT_REOSLVED) expect(mockWarn).not.toHaveBeenCalled() }) }) diff --git a/packages/core-base/test/translate.test.ts b/packages/core-base/test/translate.test.ts index e47f6adf9..23c4922f2 100644 --- a/packages/core-base/test/translate.test.ts +++ b/packages/core-base/test/translate.test.ts @@ -100,7 +100,7 @@ describe('default option', () => { en: {} } }) - expect(translate(ctx, 'hello' as any, 'hello, default message!')).toEqual( + expect(translate(ctx, 'hello', 'hello, default message!')).toEqual( 'hello, default message!' ) }) @@ -113,12 +113,7 @@ describe('default option', () => { } }) expect( - translate( - ctx, - 'hi {name}!' as any, - { name: 'kazupon' }, - { default: true } - ) + translate(ctx, 'hi {name}!', { name: 'kazupon' }, { default: true }) ).toEqual('hi kazupon!') }) }) @@ -136,7 +131,7 @@ describe('context fallbackLocale option', () => { } }) - expect(translate(ctx, 'hello' as any)).toEqual('hello') + expect(translate(ctx, 'hello')).toEqual('hello') expect(mockWarn.mock.calls[0][0]).toEqual( `Not found 'hello' key in 'en' locale messages.` ) @@ -197,7 +192,7 @@ describe('context missing option', () => { } }) - expect(translate(ctx, 'hello' as any)).toEqual('hello') + expect(translate(ctx, 'hello')).toEqual('hello') expect(mockWarn.mock.calls[0][0]).toEqual( `Not found 'hello' key in 'en' locale messages.` ) @@ -219,7 +214,7 @@ describe('context missing option', () => { en: {} } }) - expect(translate(ctx, 'hello' as any)).toEqual('HELLO') + expect(translate(ctx, 'hello')).toEqual('HELLO') expect(mockWarn).not.toHaveBeenCalled() }) }) @@ -238,7 +233,7 @@ describe('context missingWarn option', () => { } }) - expect(translate(ctx, 'hello' as any)).toEqual('hello') + expect(translate(ctx, 'hello')).toEqual('hello') expect(mockWarn).not.toHaveBeenCalled() }) @@ -255,8 +250,8 @@ describe('context missingWarn option', () => { } }) - expect(translate(ctx, 'hi kazupon!' as any)).toEqual('hi kazupon!') - expect(translate(ctx, 'hello' as any)).toEqual('hello') + expect(translate(ctx, 'hi kazupon!')).toEqual('hi kazupon!') + expect(translate(ctx, 'hello')).toEqual('hello') expect(mockWarn).toHaveBeenCalledTimes(1) expect(mockWarn.mock.calls[0][0]).not.toEqual( `Not found 'hello' key in 'en' locale messages.` @@ -275,9 +270,7 @@ describe('context missingWarn option', () => { } }) - expect(translate(ctx, 'hello' as any, {}, { missingWarn: false })).toEqual( - 'hello' - ) + expect(translate(ctx, 'hello', {}, { missingWarn: false })).toEqual('hello') expect(mockWarn).not.toHaveBeenCalled() }) }) @@ -295,7 +288,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello' as any)).toEqual('hello') + expect(translate(ctx, 'hello')).toEqual('hello') expect(mockWarn).not.toHaveBeenCalled() }) @@ -336,7 +329,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello.world' as any)).toEqual('hello.world') + expect(translate(ctx, 'hello.world')).toEqual('hello.world') expect(mockWarn).toHaveBeenCalledTimes(2) expect(mockWarn.mock.calls[0][0]).toEqual( `Fall back to translate 'hello.world' key with 'ja' locale.` @@ -361,7 +354,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello.world' as any)).toEqual('hello.world') + expect(translate(ctx, 'hello.world')).toEqual('hello.world') expect(mockWarn).toHaveBeenCalledTimes(0) }) @@ -380,7 +373,7 @@ describe('context fallbackWarn option', () => { } }) - expect(translate(ctx, 'hello.world' as any)).toEqual('hello.world') + expect(translate(ctx, 'hello.world')).toEqual('hello.world') expect(mockWarn).toHaveBeenCalledTimes(2) }) @@ -401,9 +394,7 @@ describe('context fallbackWarn option', () => { }) expect(translate(ctx, 'hello')).toEqual('こんにちは!') - expect(translate(ctx, 'hi' as any, {}, { fallbackWarn: false })).toEqual( - 'hi' - ) + expect(translate(ctx, 'hi', {}, { fallbackWarn: false })).toEqual('hi') expect(mockWarn).toHaveBeenCalledTimes(1) }) }) @@ -424,7 +415,7 @@ describe('context fallbackFormat option', () => { } }) - expect(translate(ctx, 'hi, {name}!' as any, { name: 'kazupon' })).toEqual( + expect(translate(ctx, 'hi, {name}!', { name: 'kazupon' })).toEqual( 'hi, kazupon!' ) expect(mockWarn).toHaveBeenCalledTimes(5) @@ -461,12 +452,7 @@ describe('context fallbackFormat option', () => { }) expect( - translate( - ctx, - 'hi, {name}!' as any, - { name: 'kazupon' }, - 'hello, {name}!' - ) + translate(ctx, 'hi, {name}!', { name: 'kazupon' }, 'hello, {name}!') ).toEqual('hello, kazupon!') expect(mockWarn).toHaveBeenCalledTimes(5) expect(mockWarn.mock.calls[0][0]).toEqual( @@ -499,12 +485,7 @@ describe('context fallbackFormat option', () => { }) expect( - translate( - ctx, - 'hi, {name}!' as any, - { name: 'kazupon' }, - 'hello, {name}!' - ) + translate(ctx, 'hi, {name}!', { name: 'kazupon' }, 'hello, {name}!') ).toEqual('hello, kazupon!') expect(mockWarn).toHaveBeenCalledTimes(1) expect(mockWarn.mock.calls[0][0]).toEqual( @@ -526,7 +507,7 @@ describe('context unresolving option', () => { ja: {} } }) - expect(translate(ctx, 'hello.world' as any)).toEqual(NOT_REOSLVED) + expect(translate(ctx, 'hello.world')).toEqual(NOT_REOSLVED) }) test('fallbackWarn is false', () => { @@ -541,7 +522,7 @@ describe('context unresolving option', () => { ja: {} } }) - expect(translate(ctx, 'hello.world' as any)).toEqual(NOT_REOSLVED) + expect(translate(ctx, 'hello.world')).toEqual(NOT_REOSLVED) }) test('fallbackFormat is true', () => { @@ -558,7 +539,7 @@ describe('context unresolving option', () => { ja: {} } }) - expect(translate(ctx, 'hi, {name}!' as any, { name: 'kazupon' })).toEqual( + expect(translate(ctx, 'hi, {name}!', { name: 'kazupon' })).toEqual( 'hi, kazupon!' ) }) @@ -693,29 +674,22 @@ test('resolvedMessage', () => { en: {} } }) - expect(translate(ctx, 'car' as any, 1, { resolvedMessage: true })).toEqual( - 'car' - ) + expect(translate(ctx, 'car', 1, { resolvedMessage: true })).toEqual('car') expect( translate(ctx, () => 'hello!', 1, { resolvedMessage: true }) ).toEqual('hello!') - expect( - translate(ctx, 'list {0}' as any, [1], { resolvedMessage: true }) - ).toEqual('list 1') + expect(translate(ctx, 'list {0}', [1], { resolvedMessage: true })).toEqual( + 'list 1' + ) expect( translate(ctx, (ctx: MessageContext) => `list ${ctx.list(0)}`, [1], { resolvedMessage: true }) ).toEqual('list 1') expect( - translate( - ctx, - 'named {name}' as any, - { name: 'dio' }, - { resolvedMessage: true } - ) + translate(ctx, 'named {name}', { name: 'dio' }, { resolvedMessage: true }) ).toEqual('named dio') expect( translate( diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index 2b1155571..df9d88492 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -40,7 +40,9 @@ import { handleFlatJson, MessageFunction, setAdditionalMeta, - IsUnion + IsUnion, + ResourcePath, + UnionToTuple } from '@intlify/core-base' import { VueDevToolsTimelineEvents } from '@intlify/vue-devtools' import { I18nWarnCodes, getWarnMessage } from './warnings' @@ -78,9 +80,11 @@ import type { MetaInfo, PickupLocales, PickupKeys, + PickupFormatKeys, FallbackLocales, SchemaParams, - LocaleParams + LocaleParams, + ResourceValue } from '@intlify/core-base' import type { VueDevToolsEmitter } from '@intlify/vue-devtools' @@ -468,8 +472,11 @@ export interface ComposerTranslation { * * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) */ - = PickupKeys>( - key: Key | number + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number ): string /** * Locale message translation for plurals @@ -491,8 +498,11 @@ export interface ComposerTranslation { * * @VueI18nSee [Pluralization](../guide/essentials/pluralization) */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, plural: number, options?: TranslateOptions ): string @@ -514,8 +524,11 @@ export interface ComposerTranslation { * * @returns Translated message */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, defaultMsg: string, options?: TranslateOptions ): string @@ -539,8 +552,11 @@ export interface ComposerTranslation { * * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, list: unknown[], options?: TranslateOptions ): string @@ -561,8 +577,11 @@ export interface ComposerTranslation { * @VueI18nSee [Pluralization](../guide/essentials/pluralization) * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, list: unknown[], plural: number ): string @@ -582,8 +601,11 @@ export interface ComposerTranslation { * * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, list: unknown[], defaultMsg: string ): string @@ -607,8 +629,11 @@ export interface ComposerTranslation { * * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, named: NamedValue, options?: TranslateOptions ): string @@ -629,8 +654,11 @@ export interface ComposerTranslation { * @VueI18nSee [Pluralization](../guide/essentials/pluralization) * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, named: NamedValue, plural: number ): string @@ -650,8 +678,11 @@ export interface ComposerTranslation { * * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - = PickupKeys>( - key: Key | number, + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys | number, named: NamedValue, defaultMsg: string ): string @@ -803,9 +834,7 @@ export interface ComposerDateTimeFormatting< * * @VueI18nSee [Datetime formatting](../guide/essentials/datetime) */ - = PickupKeys>( - value: number | Date | string - ): string + (value: number | Date | string): string /** * Datetime formatting * @@ -819,9 +848,16 @@ export interface ComposerDateTimeFormatting< * * @returns Formatted value */ - = PickupKeys>( - value: number | Date | string, - keyOrOptions: Key | DateTimeOptions + < + Value extends number | Date | string = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys = PickupFormatKeys + >( + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | DateTimeOptions ): string /** * Datetime formatting @@ -837,9 +873,16 @@ export interface ComposerDateTimeFormatting< * * @returns Formatted value */ - = PickupKeys>( - value: number | Date | string, - keyOrOptions: Key | DateTimeOptions, + < + Value extends number | Date | string = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys = PickupFormatKeys + >( + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | DateTimeOptions, locale: Locales ): string } @@ -886,9 +929,16 @@ export interface ComposerNumberFormatting< * * @returns Formatted value */ - = PickupKeys>( - value: number, - keyOrOptions: Key | NumberOptions + < + Value extends number = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys = PickupFormatKeys + >( + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | NumberOptions ): string /** * Number Formatting @@ -904,9 +954,16 @@ export interface ComposerNumberFormatting< * * @returns Formatted value */ - = PickupKeys>( - value: number, - keyOrOptions: Key | NumberOptions, + < + Value extends number = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys = PickupFormatKeys + >( + value: Value, + keyOrOptions: + | Key + | ResourceKeys + | NumberOptions, locale: Locales ): string } @@ -1150,8 +1207,11 @@ export interface Composer< * * @returns If found locale message, `true`, else `false` */ - te = PickupKeys>( - key: Key, + te< + Str extends string, + Key extends PickupKeys = PickupKeys + >( + key: Str | Key, locale?: Locales ): boolean /** @@ -1214,9 +1274,19 @@ export interface Composer< * * @return Locale messages */ - tm = PickupKeys>( - key: Key | string // TODO: dynamic type! - ): LocaleMessageValue + tm< + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys, + Locale extends PickupLocales> = PickupLocales< + NonNullable + >, + Target = NonNullable[Locale], + Return = ResourceKeys extends ResourcePath + ? ResourceValue + : Record + >( + key: Key | ResourceKeys + ): Return /** * Get locale message * @@ -1228,14 +1298,17 @@ export interface Composer< * @returns Locale messages */ getLocaleMessage< - LocaleSchema extends string = never, - MessageSchema extends LocaleMessage = {}, + MessageSchema extends LocaleMessage = never, + LocaleSchema extends string = string, Locale extends PickupLocales> = PickupLocales< NonNullable - > + >, + Return = [MessageSchema] extends [never] + ? NonNullable[Locale] // TODO: more strict! + : MessageSchema >( locale: LocaleSchema | Locale - ): Ref[Locale]> // TODO: dynamic type ! + ): Return /** * Set locale message * @@ -1246,14 +1319,17 @@ export interface Composer< * @param message - A message */ setLocaleMessage< - LocaleSchema extends string = never, - MessageSchema extends LocaleMessage = {}, + MessageSchema extends LocaleMessage = never, + LocaleSchema extends string = string, Locale extends PickupLocales> = PickupLocales< NonNullable - > + >, + Message = [MessageSchema] extends [never] + ? NonNullable[Locale] // TODO: more strict! + : MessageSchema >( locale: LocaleSchema | Locale, - message: NonNullable[Locale] | MessageSchema // TODO: dynamic type ! + message: Message ): void /** * Merge locale message @@ -1265,14 +1341,16 @@ export interface Composer< * @param message - A message */ mergeLocaleMessage< - LocaleSchema extends string = never, - MessageSchema extends LocaleMessage = {}, + MessageSchema extends LocaleMessage = never, Locale extends PickupLocales> = PickupLocales< NonNullable - > + >, + Message = [MessageSchema] extends [never] + ? Record + : MessageSchema >( - locale: LocaleSchema | Locale, - message: NonNullable[Locale] | MessageSchema // TODO: dynamic type ! + locale: Locale, + message: Message ): void /** * Get datetime format diff --git a/packages/vue-i18n/test/composer.test.ts b/packages/vue-i18n/test/composer.test.ts index fc865ee08..3c0f91e45 100644 --- a/packages/vue-i18n/test/composer.test.ts +++ b/packages/vue-i18n/test/composer.test.ts @@ -28,6 +28,7 @@ import { PathValue, MessageResolver } from '@intlify/core-base' +import { stringify } from 'node:querystring' beforeEach(() => { registerMessageCompiler(compileToFunction) @@ -400,7 +401,7 @@ describe('fallbackFormat', () => { } }) - expect(t('hi, {name}!' as any, { name: 'kazupon' })).toEqual('hi, kazupon!') + expect(t('hi, {name}!', { name: 'kazupon' })).toEqual('hi, kazupon!') expect(mockWarn).toHaveBeenCalledTimes(5) }) }) @@ -441,7 +442,7 @@ describe('fallbackRoot', () => { }, __root: root }) - expect(t('hello' as any)).toEqual('hello') + expect(t('hello')).toEqual('hello') expect(mockWarn).toHaveBeenCalled() expect(mockWarn.mock.calls[0][0]).toEqual( getWarnMessage(I18nWarnCodes.FALLBACK_TO_ROOT, { @@ -474,7 +475,7 @@ describe('fallbackRoot', () => { }, __root: root }) - expect(t('hello' as any)).toEqual('hello') + expect(t('hello')).toEqual('hello') expect(mockWarn).not.toHaveBeenCalledTimes(1) }) }) @@ -659,7 +660,7 @@ describe('t', () => { en: {} } }) - expect(t('foo.bar.buz' as any)).toEqual('FOO.BAR.BUZ') + expect(t('foo.bar.buz')).toEqual('FOO.BAR.BUZ') }) test('computed property name', () => { @@ -803,7 +804,7 @@ describe('d', () => { } }) const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) - expect(d(dt, { key: 'long' as any })).toEqual('') + expect(d(dt, { key: 'long' })).toEqual('') }) test('iso', () => { @@ -976,7 +977,7 @@ describe('n', () => { 'en-US': {} } }) - expect(n(0.99, { key: 'percent' as any })).toEqual('') + expect(n(0.99, { key: 'percent' })).toEqual('') }) }) @@ -985,8 +986,7 @@ describe('tm', () => { const composer = createComposer({ locale: 'ja', messages: { - en: {}, - ja: { + en: { foo: { bar: { buz: 'hello' @@ -995,14 +995,24 @@ describe('tm', () => { errors: ['error1', 'error2'] } } + }, + ja: { + foo: { + bar: { + buz: 'こんにちは' + }, + codes: { + errors: ['エラー1', 'エラー2'] + } + } } } }) let messages1 = composer.tm('foo.bar') let messages2 = composer.tm('foo.codes') - expect(messages1).toEqual({ buz: 'hello' }) - expect(messages2).toEqual({ errors: ['error1', 'error2'] }) + expect(messages1).toEqual({ buz: 'こんにちは' }) + expect(messages2).toEqual({ errors: ['エラー1', 'エラー2'] }) watchEffect(() => { messages1 = composer.tm('foo.bar') @@ -1060,10 +1070,9 @@ describe('tm', () => { test('resolved with rt', () => { const { rt, tm } = createComposer({ - locale: 'ja', + locale: 'en', messages: { - en: {}, - ja: { + en: { foo: { bar: { buz: 'hello, {name}!' @@ -1072,14 +1081,22 @@ describe('tm', () => { errors: [() => 'error1', () => 'error2'] } } + }, + ja: { + foo: { + bar: { + buz: 'こんにちは、 {name}!' + }, + codes: { + errors: [() => 'エラー1', () => 'エラー2'] + } + } } } }) - expect(rt((tm('foo.bar') as any).buz, { name: 'dio' })).toEqual( - 'hello, dio!' - ) - const errors = tm('foo.codes.errors') as (() => string)[] + expect(rt(tm('foo.bar').buz, { name: 'dio' })).toEqual('hello, dio!') + const errors = tm('foo.codes.errors') for (const [index, err] of errors.entries()) { expect(rt(err)).toEqual(`error${index + 1}`) } @@ -1099,8 +1116,8 @@ test('te', async () => { }) expect(te('message.hello')).toEqual(true) - expect(te('message.hallo' as any)).toEqual(false) - expect(te('message.hallo' as any, 'ja' as any)).toEqual(false) + expect(te('message.hallo')).toEqual(false) + expect(te('message.hallo', 'ja' as any)).toEqual(false) }) describe('getLocaleMessage / setLocaleMessage / mergeLocaleMessage', () => { @@ -1117,10 +1134,14 @@ describe('getLocaleMessage / setLocaleMessage / mergeLocaleMessage', () => { expect(getLocaleMessage('en')).toEqual({ hello: 'Hello!' }) setLocaleMessage('en', { hi: { hi: 'Hi!' } }) - expect(getLocaleMessage('en')).toEqual({ hi: { hi: 'Hi!' } }) + expect(getLocaleMessage<{ hi: { hi: string } }>('en')).toEqual({ + hi: { hi: 'Hi!' } + }) mergeLocaleMessage('en', { hi: { hello: 'Hello!' } }) - expect(getLocaleMessage('en')).toEqual({ + expect( + getLocaleMessage<{ hi: { hi: string; hello: string } }>('en') + ).toEqual({ hi: { hi: 'Hi!', hello: 'Hello!' @@ -1136,6 +1157,7 @@ describe('getDateTimeFormat / setDateTimeFormat / mergeDateTimeFormat', () => { setDateTimeFormat, mergeDateTimeFormat } = createComposer({ + locale: 'en-US', datetimeFormats: { 'en-US': { short: { @@ -1629,7 +1651,7 @@ describe('root', () => { __root }) - expect(t('hello' as any)).toEqual('hello!') + expect(t('hello')).toEqual('hello!') }) test('d', () => { @@ -1658,7 +1680,7 @@ describe('root', () => { }) const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) - expect(d(dt, { key: 'short' as any })).toEqual('12/19/2012, 10:00 PM') + expect(d(dt, { key: 'short' })).toEqual('12/19/2012, 10:00 PM') }) test('n', () => { @@ -1682,7 +1704,7 @@ describe('root', () => { __root }) - expect(n(0.99, { key: 'percent' as any })).toEqual('99%') + expect(n(0.99, { key: 'percent' })).toEqual('99%') }) }) diff --git a/test-d/core-base/context.test-d.ts b/test-d/core-base/context.test-d.ts index 2e3b47d31..a6af96d1b 100644 --- a/test-d/core-base/context.test-d.ts +++ b/test-d/core-base/context.test-d.ts @@ -8,24 +8,11 @@ import { PickupFallbackLocales, createCoreContext } from '../../packages/core-base/src/context' - -type ResourceSchema = { - foo: string - nest: { - bar: string - } - errors: string[] -} -type MyDatetimeScehma = { - short: { - hour: 'numeric' - } -} -type MyNumberSchema = { - currency: { - style: 'symbol' - } -} +import type { + ResourceSchema, + MyDatetimeScehma, + MyNumberSchema +} from '../schema' // loose options const looseOptions = { diff --git a/test-d/core-base/datetime.test-d.ts b/test-d/core-base/datetime.test-d.ts new file mode 100644 index 000000000..4585b7418 --- /dev/null +++ b/test-d/core-base/datetime.test-d.ts @@ -0,0 +1,39 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { expectType } from '../index' + +import { createCoreContext } from '../../packages/core-base/src/context' +import { datetime } from '../../packages/core-base/src/datetime' + +const ctx = createCoreContext({ + locale: 'en-US', + datetimeFormats: { + 'en-US': { + short: { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + timeZone: 'America/New_York' + } + } + } +}) + +const dt = new Date(Date.UTC(2012, 11, 20, 3, 0, 0)) + +expectType(datetime(ctx, dt)) +expectType( + datetime(ctx, dt, { locale: 'en-US', key: 'short' }) +) +expectType( + datetime(ctx, dt, { key: 'short' }, 'en-US') +) +expectType( + datetime(ctx, dt, { key: 'short' }, { hourCycle: 'h24' }) +) +expectType( + datetime(ctx, dt, { key: 'short' }, 'en-US', { hourCycle: 'h24' }) +) + +/* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/test-d/core-base/number.test-d.ts b/test-d/core-base/number.test-d.ts new file mode 100644 index 000000000..1588f39b0 --- /dev/null +++ b/test-d/core-base/number.test-d.ts @@ -0,0 +1,34 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { expectType } from '../index' + +import { createCoreContext } from '../../packages/core-base/src/context' +import { number } from '../../packages/core-base/src/number' + +const ctx = createCoreContext({ + locale: 'en-US', + numberFormats: { + 'en-US': { + currency: { + style: 'currency', + currency: 'USD', + currencyDisplay: 'symbol' + } + } + } +}) + +expectType(number(ctx, 10100)) +expectType( + number(ctx, 10100, { locale: 'en-US', key: 'currency' }) +) +expectType( + number(ctx, 10100, { key: 'currency' }, 'en-US') +) +expectType( + number(ctx, 10100, { locale: 'en-US', key: 'currency' }, { unit: '' }) +) +expectType( + number(ctx, 10100, { key: 'currency' }, 'en-US', { unit: '' }) +) + +/* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/test-d/core-base/translate.test-d.ts b/test-d/core-base/translate.test-d.ts new file mode 100644 index 000000000..f8251d177 --- /dev/null +++ b/test-d/core-base/translate.test-d.ts @@ -0,0 +1,43 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { expectType } from '../index' + +import { createCoreContext } from '../../packages/core-base/src/context' +import { translate } from '../../packages/core-base/src/translate' + +const ctx = createCoreContext({ + locale: 'en', + messages: { + en: { + hello: 'hello world!' + } + } +}) + +expectType(translate(ctx, 'hello')) +expectType(translate(ctx, 'hello', 1)) +expectType( + translate(ctx, 'hello', 1, { locale: 'en', missingWarn: true }) +) +expectType(translate(ctx, 'hello', 'default msg')) +expectType( + translate(ctx, 'hello', 'default msg', { locale: 'en', plural: 2 }) +) +expectType(translate(ctx, 'hello', ['list'])) +expectType(translate(ctx, 'hello', ['list'], 1)) +expectType(translate(ctx, 'hello', ['list'], 'default msg')) +expectType(translate(ctx, 'hello', ['list'], { locale: 'en' })) +expectType(translate(ctx, 'hello', { name: 'dio' })) +expectType(translate(ctx, 'hello', { name: 'dio' }, 1)) +expectType( + translate(ctx, 'hello', { name: 'dio' }, 'default msg') +) +expectType( + translate( + ctx, + 'hello', + { name: 'dio' }, + { locale: 'en', resolvedMessage: true } + ) +) + +/* eslint-enable @typescript-eslint/no-explicit-any */ diff --git a/test-d/schema.ts b/test-d/schema.ts new file mode 100644 index 000000000..7a1d83cd8 --- /dev/null +++ b/test-d/schema.ts @@ -0,0 +1,19 @@ +export type ResourceSchema = { + foo: string + nest: { + bar: string + } + errors: string[] +} + +export type MyDatetimeScehma = { + short: { + hour: 'numeric' + } +} + +export type MyNumberSchema = { + currency: { + style: 'symbol' + } +} diff --git a/test-d/vue-i18n/composer.test-d.ts b/test-d/vue-i18n/composer.test-d.ts new file mode 100644 index 000000000..3bbb0c117 --- /dev/null +++ b/test-d/vue-i18n/composer.test-d.ts @@ -0,0 +1,294 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { expectType } from '../index' + +import { Ref } from 'vue' +import { + LocaleMessageValue, + PickupFallbackLocales +} from '../../packages/core-base/src/context' +import { + ComposerOptions, + createComposer +} from '../../packages/vue-i18n/src/composer' +import { SchemaParams, LocaleParams } from '../../packages/core-base/src/' + +type ResourceSchema = { + foo: string + nest: { + bar: string + } + errors: string[] +} +type MyDatetimeScehma = { + short: { + hour: 'numeric' + } +} +type MyNumberSchema = { + currency: { + style: 'symbol' + } +} + +// loose options +const looseOptions = { + locale: 'en', + fallbackLocale: { + ja: ['en'] + }, + messages: { + en: { + foo: 'foo', + nest: { + bar: 'bar' + } + }, + ja: { + bar: 'foo', + nest: { + bar: 'bar' + } + } + }, + datetimeFormats: { + 'en-US': { + short: {} + } + }, + numberFormats: { + 'ja-JP': { + currency: {} + } + } +} + +// strict options +const strictOptions = { + locale: 'en', + fallbackLocale: { + ja: ['en'] + }, + messages: { + en: { + foo: 'foo', + nest: { + bar: 'bar' + }, + errors: ['error1'] + }, + ja: { + // bar: 'foo', // TODO: + foo: 'foo', + nest: { + bar: 'bar' + }, + errors: ['error2'] + } + } +} + +expectType(looseOptions) +expectType< + ComposerOptions< + string, + SchemaParams< + { + message: ResourceSchema + datetime: MyDatetimeScehma + number: MyNumberSchema + }, + string + >, + LocaleParams<'en' | 'ja'> + > +>(strictOptions) + +// check loose composer +const looseComposer = createComposer(looseOptions) +expectType<'en' | 'ja' | 'en-US' | 'ja-JP'>(looseComposer.locale.value) +expectType< + | 'en' + | 'ja' + | 'en-US' + | 'ja-JP' + | ('en' | 'ja' | 'en-US' | 'ja-JP')[] + | { + [x in string]: PickupFallbackLocales<['en' | 'ja' | 'en-US' | 'ja-JP']>[] + } + | false +>(looseComposer.fallbackLocale.value) +expectType<{ + en: { + foo: string + nest: { + bar: string + } + } + ja: { + bar: string + nest: { + bar: string + } + } +}>(looseComposer.messages.value) +expectType<{ 'en-US': { short: {} } }>(looseComposer.datetimeFormats.value) +expectType<{ 'ja-JP': { currency: {} } }>(looseComposer.numberFormats.value) +expectType(looseComposer.t('nest.bar')) +expectType(looseComposer.t('nest', 1, { locale: 'en' })) +expectType(looseComposer.t('foo', 'default msg', { locale: 'en' })) +expectType(looseComposer.t('errors', [1], { plural: 1 })) +expectType(looseComposer.t('errors', [1], 1)) +expectType(looseComposer.t('errors', [1], 'default msg')) +expectType(looseComposer.t(1, { foo: 1 }, { locale: 'en' })) +expectType(looseComposer.t('nestt', { foo: 1 }, 'msg')) +expectType(looseComposer.te('errors', 'en')) +expectType<{ bar: string }>(looseComposer.tm('nest')) +expectType(looseComposer.tm('errors')) +expectType(looseComposer.rt('foo')) +// TODO: more strict! +expectType( + looseComposer.getLocaleMessage('en') +) +expectType<{ japan: string }>( + looseComposer.getLocaleMessage<{ japan: string }>('japan') +) +// TODO: more strict! +looseComposer.setLocaleMessage('en', { + foo: 'foo', + nest: { + bar: 'bar' + }, + errors: ['error1'] +}) +looseComposer.setLocaleMessage<{ dio: string }>('jojo', { + dio: 'The world!' +}) +looseComposer.mergeLocaleMessage('en', { + bar: 'foo' +}) +looseComposer.mergeLocaleMessage<{ dio: string }>('en', { + dio: 'The world!' +}) + +// check strict composer +const strictComposer = createComposer<[ResourceSchema], 'en' | 'ja'>( + strictOptions +) +expectType<'en' | 'ja'>(strictComposer.locale.value) +expectType< + | 'en' + | 'ja' + | ('en' | 'ja')[] + | { [x in string]: PickupFallbackLocales<['en' | 'ja']>[] } + | false +>(strictComposer.fallbackLocale.value) +expectType<{ en: ResourceSchema; ja: ResourceSchema }>( + strictComposer.messages.value +) +expectType<{ en: {}; ja: {} }>(strictComposer.datetimeFormats.value) +expectType<{ en: {}; ja: {} }>(strictComposer.numberFormats.value) +expectType(strictComposer.t('nest.bar')) +expectType(strictComposer.t('nest', 1, { locale: 'en' })) +expectType(strictComposer.t('foo', 'default msg', { locale: 'en' })) +expectType(strictComposer.t('errors', [1], { plural: 1 })) +expectType(strictComposer.t('errors', [1], 1)) +expectType(strictComposer.t('errors', [1], 'default msg')) +expectType(strictComposer.t(1, { foo: 1 }, { locale: 'en' })) +expectType(strictComposer.t('nestt', { foo: 1 }, 'msg')) +expectType(strictComposer.te('errors', 'en')) +expectType<{ bar: string }>(strictComposer.tm('nest')) +expectType(strictComposer.tm('errors')) +expectType(strictComposer.rt('foo')) +// TODO: more strict! +expectType( + strictComposer.getLocaleMessage('en') +) +expectType<{ japan: string }>( + strictComposer.getLocaleMessage<{ japan: string }>('japan') +) +// TODO: more strict! +strictComposer.setLocaleMessage('en', { + foo: 'foo', + nest: { + bar: 'bar' + }, + errors: ['error1'] +}) +strictComposer.setLocaleMessage<{ dio: string }>('jojo', { + dio: 'The world!' +}) +strictComposer.mergeLocaleMessage('en', { + bar: 'foo' +}) +strictComposer.mergeLocaleMessage<{ dio: string }>('en', { + dio: 'The world!' +}) + +// check strict context with direct options +const strictDirectComposer = createComposer< + { + message: ResourceSchema + datetime: MyDatetimeScehma + number: MyNumberSchema + }, + { messages: 'en'; datetimeFormats: 'ja-JP' | 'zh'; numberFormats: 'ca' } +>({ + messages: { + en: { + foo: '', + nest: { + bar: '' + }, + errors: [''] + } + }, + datetimeFormats: { + zh: { + short: { + hour: 'numeric' + } + }, + 'ja-JP': { + short: { + hour: 'numeric' + } + } + }, + numberFormats: { + ca: { + currency: { style: 'symbol' } + } + } +}) +expectType<'en' | 'zh' | 'ca' | 'ja-JP'>(strictDirectComposer.locale.value) +expectType< + | 'en' + | 'zh' + | 'ca' + | 'ja-JP' + | ('en' | 'zh' | 'ca' | 'ja-JP')[] + | { [x in string]: PickupFallbackLocales<['en' | 'zh' | 'ca' | 'ja-JP']>[] } + | false +>(strictDirectComposer.fallbackLocale.value) +expectType<{ en: ResourceSchema }>(strictDirectComposer.messages.value) +expectType<{ zh: {}; 'ja-JP': { short: {} } }>( + strictDirectComposer.datetimeFormats.value +) +expectType<{ ca: { currency: {} } }>(strictDirectComposer.numberFormats.value) +expectType(strictDirectComposer.d(new Date())) +expectType(strictDirectComposer.d(new Date(), 'short', 'ja-JP')) +expectType( + strictDirectComposer.d(new Date(), { key: 'short', locale: 'zh' }) +) +expectType(strictDirectComposer.d(new Date(), 'custom' as any)) +expectType(strictDirectComposer.n(1)) +expectType(strictDirectComposer.n(1, 'currency', 'zh')) +expectType(strictDirectComposer.n(1, { key: 'currency', locale: 'en' })) +expectType(strictDirectComposer.n(1, 'custom' as any)) + +// const noOptionsComposer = createComposer({ missingWarn: true }) +const noOptionsComposer = createComposer({ locale: 'en' }) +expectType(noOptionsComposer.locale.value) +expectType(noOptionsComposer.fallbackLocale.value) + +/* eslint-enable @typescript-eslint/no-explicit-any */ From 0bec188f4668de3af832cbea61cd90302e63a868 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Mon, 10 May 2021 03:59:48 +0900 Subject: [PATCH 05/24] updates --- packages/vue-i18n/src/composer.ts | 120 ++++++++++++++++++----------- test-d/vue-i18n/composer.test-d.ts | 46 +++++++++++ 2 files changed, 122 insertions(+), 44 deletions(-) diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index df9d88492..8ce7d6ac3 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -40,9 +40,7 @@ import { handleFlatJson, MessageFunction, setAdditionalMeta, - IsUnion, - ResourcePath, - UnionToTuple + ResourcePath } from '@intlify/core-base' import { VueDevToolsTimelineEvents } from '@intlify/vue-devtools' import { I18nWarnCodes, getWarnMessage } from './warnings' @@ -50,7 +48,7 @@ import { I18nErrorCodes, createI18nError } from './errors' import { VERSION } from './misc' import type { ComponentInternalInstance, VNode, VNodeArrayChildren } from 'vue' -import type { Ref, WritableComputedRef, ComputedRef } from '@vue/reactivity' +import type { WritableComputedRef, ComputedRef } from '@vue/reactivity' import type { Path, MessageResolver, @@ -998,40 +996,6 @@ export interface Composer< numberFormats: unknown } | string = Locale, - MessagesLocales = SchemaLocales extends { messages: infer M } - ? M - : SchemaLocales extends string - ? SchemaLocales - : Locale, - DateTimeFormatsLocales = SchemaLocales extends { datetimeFormats: infer D } - ? D - : SchemaLocales extends string - ? SchemaLocales - : SchemaLocales, - NumberFormatsLocales = SchemaLocales extends { numberFormats: infer N } - ? N - : SchemaLocales extends string - ? SchemaLocales - : Locale, - MessageSchema = Schema extends { message: infer M } - ? M - : LocaleMessage, - DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, - NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, - MessagesEntity extends LocaleMessages< - MessageSchema, - MessagesLocales, - Message - > = LocaleMessages, - DateTimeFormatsEntity extends DateTimeFormatsType< - DateTimeSchema, - DateTimeFormatsLocales - > = DateTimeFormatsType, - NumberFormatsEntity extends NumberFormatsType< - NumberSchema, - NumberFormatsLocales - > = NumberFormatsType, - M = { [K in keyof Messages]: Messages[K] }, ResourceLocales = | PickupLocales> | PickupLocales> @@ -1362,7 +1326,18 @@ export interface Composer< * * @returns Datetime format */ - getDateTimeFormat(locale: Locale): DateTimeFormat + getDateTimeFormat< + DateTimeSchema extends Record = never, + LocaleSchema extends string = string, + Locale extends PickupLocales> = PickupLocales< + NonNullable + >, + Return = [DateTimeSchema] extends [never] + ? NonNullable[Locale] // TODO: more strict! + : DateTimeSchema + >( + locale: LocaleSchema | Locale + ): Return /** * Set datetime format * @@ -1372,7 +1347,19 @@ export interface Composer< * @param locale - A target locale * @param format - A target datetime format */ - setDateTimeFormat(locale: Locale, format: DateTimeFormat): void + setDateTimeFormat< + DateTimeSchema extends Record = never, + LocaleSchema extends string = string, + Locale extends PickupLocales> = PickupLocales< + NonNullable + >, + Formats = [DateTimeSchema] extends [never] + ? NonNullable[Locale] // TODO: more strict! + : DateTimeSchema + >( + locale: LocaleSchema | Locale, + format: Formats + ): void /** * Merge datetime format * @@ -1382,7 +1369,18 @@ export interface Composer< * @param locale - A target locale * @param format - A target datetime format */ - mergeDateTimeFormat(locale: Locale, format: DateTimeFormat): void + mergeDateTimeFormat< + DateTimeSchema extends Record = never, + Locale extends PickupLocales> = PickupLocales< + NonNullable + >, + Formats = [DateTimeSchema] extends [never] + ? Record + : DateTimeSchema + >( + locale: Locale, + format: Formats + ): void /** * Get number format * @@ -1393,7 +1391,18 @@ export interface Composer< * * @returns Number format */ - getNumberFormat(locale: Locale): NumberFormat + getNumberFormat< + NumberSchema extends Record = never, + LocaleSchema extends string = string, + Locale extends PickupLocales> = PickupLocales< + NonNullable + >, + Return = [NumberSchema] extends [never] + ? NonNullable[Locale] // TODO: more strict! + : NumberSchema + >( + locale: LocaleSchema | Locale + ): Return /** * Set number format * @@ -1403,7 +1412,19 @@ export interface Composer< * @param locale - A target locale * @param format - A target number format */ - setNumberFormat(locale: Locale, format: NumberFormat): void + setNumberFormat< + NumberSchema extends Record = never, + LocaleSchema extends string = string, + Locale extends PickupLocales> = PickupLocales< + NonNullable + >, + Formats = [NumberSchema] extends [never] + ? NonNullable[Locale] // TODO: more strict! + : NumberSchema + >( + locale: LocaleSchema | Locale, + format: Formats + ): void /** * Merge number format * @@ -1413,7 +1434,18 @@ export interface Composer< * @param locale - A target locale * @param format - A target number format */ - mergeNumberFormat(locale: Locale, format: NumberFormat): void + mergeNumberFormat< + NumberSchema extends Record = never, + Locale extends PickupLocales> = PickupLocales< + NonNullable + >, + Formats = [NumberSchema] extends [never] + ? Record + : NumberSchema + >( + locale: Locale, + format: Formats + ): void /** * Get post translation handler * diff --git a/test-d/vue-i18n/composer.test-d.ts b/test-d/vue-i18n/composer.test-d.ts index 3bbb0c117..a2174d174 100644 --- a/test-d/vue-i18n/composer.test-d.ts +++ b/test-d/vue-i18n/composer.test-d.ts @@ -169,6 +169,52 @@ looseComposer.mergeLocaleMessage('en', { looseComposer.mergeLocaleMessage<{ dio: string }>('en', { dio: 'The world!' }) +// TODO: more strict! +expectType( + looseComposer.getDateTimeFormat('en-US') +) +expectType<{ long: { hour: string } }>( + looseComposer.getLocaleMessage<{ long: { hour: string } }>('en-US') +) +// TODO: more strict! +looseComposer.setDateTimeFormat('en-US', { + long: { + hour: 'numeric' + } +}) +looseComposer.setDateTimeFormat<{ stop: { hour: string } }>('world', { + stop: { hour: 'infinity' } +}) +looseComposer.mergeDateTimeFormat('en-US', { + long: { hour: 'numeric' } +}) +looseComposer.mergeDateTimeFormat<{ stop: { hour: string } }>('en-US', { + stop: { hour: 'infinity' } +}) +// TODO: more strict! +expectType( + looseComposer.getNumberFormat('ja-JP') +) +expectType<{ weight: { unit: string } }>( + looseComposer.getNumberFormat<{ weight: { unit: string } }>('en-US') +) +// TODO: more strict! +looseComposer.setNumberFormat('en-US', { + weight: { + unit: 'kiro' + } +}) +looseComposer.setNumberFormat<{ echoes: { act: string } }>('stand', { + echoes: { act: '2' } +}) +looseComposer.mergeNumberFormat('ja-JP', { + weight: { + unit: 'kiro' + } +}) +looseComposer.mergeNumberFormat<{ echoes: { act: string } }>('ja-JP', { + echoes: { act: '2' } +}) // check strict composer const strictComposer = createComposer<[ResourceSchema], 'en' | 'ja'>( From 6c82c5fc300005a1a6c1c0162eb8459fad13d67d Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 11 May 2021 08:50:19 +0900 Subject: [PATCH 06/24] updates --- .gitignore | 1 - package.json | 2 +- packages/core-base/src/context.ts | 60 ++--------- packages/core-base/src/index.ts | 2 +- packages/core-base/src/number.ts | 8 +- packages/core-base/src/translate.ts | 4 +- packages/core-base/src/types/index.ts | 2 + packages/core-base/src/types/intl.ts | 79 ++++++++++++++ packages/core-base/src/types/utils.ts | 129 +++++++++++++++++++++++ packages/core-base/test/datetime.test.ts | 2 +- packages/vue-i18n/src/composer.ts | 26 +---- packages/vue-i18n/src/devtools.ts | 1 + packages/vue-i18n/test/composer.test.ts | 1 - test-d/core-base/context.test-d.ts | 2 +- test-d/core-base/datetime.test-d.ts | 4 +- test-d/core-base/number.test-d.ts | 4 +- test-d/core-base/translate.test-d.ts | 4 +- test-d/vue-i18n/composer.test-d.ts | 7 +- 18 files changed, 241 insertions(+), 97 deletions(-) create mode 100644 packages/core-base/src/types/index.ts create mode 100644 packages/core-base/src/types/intl.ts create mode 100644 packages/core-base/src/types/utils.ts diff --git a/.gitignore b/.gitignore index efc1f78a1..ef1155b65 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ dist docs/api/*.md !docs/api/injection.md -types temp coverage node_modules diff --git a/package.json b/package.json index 98dff2bb1..d98c747b1 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "clean:dist": "rimraf ./dist ./packages/**/dist ./docs/.vitepress/dist", "clean:docs": "trash './docs/api/!(injection).md'", "clean:duplicate": "yarn-deduplicate yarn.lock", - "clean:type": "rimraf ./packages/**/types ./temp", + "clean:type": "rimraf ./temp", "coverage": "opener coverage/lcov-report/index.html", "dev": "node -r esbuild-register scripts/dev.ts", "dev:e2e": "jest --runInBand --config ./jest.e2e.config.js", diff --git a/packages/core-base/src/context.ts b/packages/core-base/src/context.ts index 435c5817b..baa24bf10 100644 --- a/packages/core-base/src/context.ts +++ b/packages/core-base/src/context.ts @@ -32,13 +32,15 @@ import type { VueDevToolsEmitter } from '@intlify/vue-devtools' import type { UnionToTuple, LocaleRecord, - IsUnion, - First, NumberFormat, DateTimeFormat, DateTimeFormats as DateTimeFormatsType, - NumberFormats as NumberFormatsType -} from './types/index' + NumberFormats as NumberFormatsType, + SchemaParams, + LocaleParams, + PickupLocales, + FallbackLocales +} from './types' export interface MetaInfo { [field: string]: unknown @@ -174,16 +176,6 @@ export interface CoreInternalOptions { __meta?: MetaInfo } -export type PickupFallbackLocales = T[number] | `${T[number]}!` - -export type FallbackLocales = - | Locales - | Array - | { - [locale in string]: Array>> - } - | false - export interface CoreCommonContext { cid: number version: string @@ -219,11 +211,6 @@ export interface CoreNumberContext { numberFormats: { [K in keyof NumberFormats]: NumberFormats[K] } } -export type PickupLocales< - T extends Record, - K = keyof T -> = K extends string ? K : never - export type CoreContext< Message = string, Messages = {}, @@ -295,41 +282,6 @@ export const getAdditionalMeta = /* #__PURE__*/ (): MetaInfo | null => // ID for CoreContext let _cid = 0 -// prettier-ignore -type LocaleParamsType = T extends IsUnion - ? T - : T extends string - ? T - : R - -// prettier-ignore -export type SchemaParams = T extends readonly any[] - ? { message: First, datetime: DateTimeFormat, number: NumberFormat } - : T extends { message?: infer M, datetime?: infer D, number?: infer N } - ? { - message: M extends LocaleMessage ? M : LocaleMessage, - datetime: D extends DateTimeFormat ? D : DateTimeFormat, - number: N extends NumberFormat ? N : NumberFormat - } - : { - message: LocaleMessage, - datetime: DateTimeFormat, - number: NumberFormat - } - -// prettier-ignore -export type LocaleParams = T extends IsUnion - ? { messages: T, datetimeFormats: T, numberFormats: T } - : T extends { messages?: infer M, datetimeFormats?: infer D, numberFormats?: infer N } - ? { - messages: LocaleParamsType, - datetimeFormats: LocaleParamsType, - numberFormats: LocaleParamsType - } - : T extends string - ? { messages: T, datetimeFormats: T, numberFormats: T } - : { messages: Default, datetimeFormats: Default, numberFormats: Default } - export function createCoreContext< Message = string, Options extends CoreOptions = CoreOptions diff --git a/packages/core-base/src/index.ts b/packages/core-base/src/index.ts index 94b2e22a1..eb59ab78c 100644 --- a/packages/core-base/src/index.ts +++ b/packages/core-base/src/index.ts @@ -12,5 +12,5 @@ export * from './datetime' export * from './number' export { getWarnMessage, CoreWarnCodes } from './warnings' export { CoreError, CoreErrorCodes, createCoreError } from './errors' -export * from './types/index' +export * from './types' export * from './devtools' diff --git a/packages/core-base/src/number.ts b/packages/core-base/src/number.ts index 79a902db4..4720a2f6b 100644 --- a/packages/core-base/src/number.ts +++ b/packages/core-base/src/number.ts @@ -24,7 +24,7 @@ import type { NumberFormats as NumberFormatsType, NumberFormatOptions, PickupFormatKeys -} from './types/index' +} from './types' import type { CoreContext, CoreInternalContext } from './context' /** @@ -138,7 +138,7 @@ export function number< Message = string >( context: Context, - value: number, + value: Value, keyOrOptions: | Key | ResourceKeys @@ -156,7 +156,7 @@ export function number< Message = string >( context: Context, - value: number, + value: Value, keyOrOptions: | Key | ResourceKeys @@ -174,7 +174,7 @@ export function number< Message = string >( context: Context, - value: number, + value: Value, keyOrOptions: | Key | ResourceKeys diff --git a/packages/core-base/src/translate.ts b/packages/core-base/src/translate.ts index d76c10612..31688fa46 100644 --- a/packages/core-base/src/translate.ts +++ b/packages/core-base/src/translate.ts @@ -48,7 +48,7 @@ import type { LocaleMessageValue, CoreInternalContext } from './context' -import type { PickupKeys } from './types/index' +import type { PickupKeys } from './types' const NOOP_MESSAGE_FUNCTION = () => '' export const isMessageFunction = (val: unknown): val is MessageFunction => @@ -260,7 +260,7 @@ export function translate< Message = string >( context: Context, - key: Key | number | MessageFunction, + key: Key | ResourceKeys | number | MessageFunction, list: unknown[], defaultMsg: string ): MessageType | number diff --git a/packages/core-base/src/types/index.ts b/packages/core-base/src/types/index.ts new file mode 100644 index 000000000..a5f17987a --- /dev/null +++ b/packages/core-base/src/types/index.ts @@ -0,0 +1,2 @@ +export * from './utils' +export * from './intl' \ No newline at end of file diff --git a/packages/core-base/src/types/intl.ts b/packages/core-base/src/types/intl.ts new file mode 100644 index 000000000..0b76a98ce --- /dev/null +++ b/packages/core-base/src/types/intl.ts @@ -0,0 +1,79 @@ +import type { LocaleRecord, UnionToTuple } from './utils' +import type { Locale } from '@intlify/runtime' + +/** + * datetime + */ + +export type DateTimeHumanReadable = 'long' | 'short' | 'narrow' +export type DateTimeDigital = 'numeric' | '2-digit' +export type LocaleMatcher = 'lookup' | 'best fit' +export type FormatMatcher = 'basic' | 'best fit' + +export interface SpecificDateTimeFormatOptions + extends Intl.DateTimeFormatOptions { + year?: DateTimeDigital + month?: DateTimeDigital | DateTimeHumanReadable + day?: DateTimeDigital + hour?: DateTimeDigital + minute?: DateTimeDigital + second?: DateTimeDigital + weekday?: DateTimeHumanReadable + era?: DateTimeHumanReadable + timeZoneName?: 'long' | 'short' + localeMatcher?: LocaleMatcher + formatMatcher?: FormatMatcher +} +export type DateTimeFormatOptions = + | Intl.DateTimeFormatOptions + | SpecificDateTimeFormatOptions +export type DateTimeFormat = { [key: string]: DateTimeFormatOptions } +export type DateTimeFormats = LocaleRecord, Schema> + +/** + * number + */ + +export type CurrencyDisplay = 'symbol' | 'code' | 'name' + +export interface SpecificNumberFormatOptions extends Intl.NumberFormatOptions { + style?: 'decimal' | 'percent' + currency?: string + currencyDisplay?: CurrencyDisplay + localeMatcher?: LocaleMatcher + formatMatcher?: FormatMatcher +} + +export interface CurrencyNumberFormatOptions extends Intl.NumberFormatOptions { + style: 'currency' + currency: string // Obligatory if style is 'currency' + currencyDisplay?: CurrencyDisplay + localeMatcher?: LocaleMatcher + formatMatcher?: FormatMatcher +} + +export type NumberFormatOptions = + | Intl.NumberFormatOptions + | SpecificNumberFormatOptions + | CurrencyNumberFormatOptions +export type NumberFormat = { [key: string]: NumberFormatOptions } +export type NumberFormats = LocaleRecord, Schema> + +export type FormattedNumberPartType = + | 'currency' + | 'decimal' + | 'fraction' + | 'group' + | 'infinity' + | 'integer' + | 'literal' + | 'minusSign' + | 'nan' + | 'plusSign' + | 'percentSign' + +export type FormattedNumberPart = { + type: FormattedNumberPartType + value: string +} +export type NumberFormatToPartsResult = { [index: number]: FormattedNumberPart } \ No newline at end of file diff --git a/packages/core-base/src/types/utils.ts b/packages/core-base/src/types/utils.ts new file mode 100644 index 000000000..054f6dc65 --- /dev/null +++ b/packages/core-base/src/types/utils.ts @@ -0,0 +1,129 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import type { LocaleMessage } from '../context' +import type { DateTimeFormat, NumberFormat } from './intl' + +export type IsUnion = T extends B + ? [B] extends [T] + ? false + : true + : never + +// prettier-ignore +export type UnionToIntersection = (U extends any ? (arg: U) => void : never) extends (arg: infer I) => void + ? I + : never + +export type LastInUnion = UnionToIntersection< + U extends unknown ? (x: U) => 0 : never +> extends (x: infer L) => 0 + ? L + : never + +export type UnionToTuple> = [U] extends [never] + ? [] + : [...UnionToTuple>, Last] + +export type LocaleRecord = { + [K in T[number]]: R +} + +export type First = T[0] + +type __ResourcePath = Key extends string + ? T[Key] extends Record + ? + | `${Key}.${__ResourcePath> & + string}` + | `${Key}.${Exclude & string}` + : never + : never +type _ResourcePath = __ResourcePath | keyof T +export type ResourcePath = _ResourcePath extends string | keyof T + ? _ResourcePath + : keyof T + +export type ResourceValue< + T, + P extends ResourcePath +> = P extends `${infer Key}.${infer Rest}` + ? Key extends keyof T + ? Rest extends ResourcePath + ? ResourceValue + : never + : never + : P extends keyof T + ? T[P] + : never + +export type PickupLocales< + T extends Record, + K = keyof T +> = K extends string ? K : never + +export type PickupKeys< + T extends Record, + K = keyof T +> = K extends string ? ResourcePath : never + +type __ResourceFormatPath = Key extends string + ? T[Key] extends Record + ? | `${Key}` + : never + : never +type _ResourceFormatPath = __ResourceFormatPath | keyof T +export type ResourceFormatPath = _ResourceFormatPath extends string | keyof T + ? _ResourceFormatPath + : keyof T + +export type PickupFormatKeys< + T extends Record, + K = keyof T +> = K extends string ? ResourceFormatPath : never + +export type PickupFallbackLocales = T[number] | `${T[number]}!` + +export type FallbackLocales = + | Locales + | Array + | { + [locale in string]: Array>> + } + | false + +// prettier-ignore +type LocaleParamsType = T extends IsUnion + ? T + : T extends string + ? T + : R + +// prettier-ignore +export type SchemaParams = T extends readonly any[] + ? { message: First, datetime: DateTimeFormat, number: NumberFormat } + : T extends { message?: infer M, datetime?: infer D, number?: infer N } + ? { + message: M extends LocaleMessage ? M : LocaleMessage, + datetime: D extends DateTimeFormat ? D : DateTimeFormat, + number: N extends NumberFormat ? N : NumberFormat + } + : { + message: LocaleMessage, + datetime: DateTimeFormat, + number: NumberFormat + } + +// prettier-ignore +export type LocaleParams = T extends IsUnion + ? { messages: T, datetimeFormats: T, numberFormats: T } + : T extends { messages?: infer M, datetimeFormats?: infer D, numberFormats?: infer N } + ? { + messages: LocaleParamsType, + datetimeFormats: LocaleParamsType, + numberFormats: LocaleParamsType + } + : T extends string + ? { messages: T, datetimeFormats: T, numberFormats: T } + : { messages: Default, datetimeFormats: Default, numberFormats: Default } + +/* eslint-enable @typescript-eslint/no-explicit-any */ \ No newline at end of file diff --git a/packages/core-base/test/datetime.test.ts b/packages/core-base/test/datetime.test.ts index f87ab29f8..355b1bbb9 100644 --- a/packages/core-base/test/datetime.test.ts +++ b/packages/core-base/test/datetime.test.ts @@ -20,7 +20,7 @@ import { CoreErrorCodes, errorMessages } from '../src/errors' import { registerMessageCompiler } from '../src/context' import { compileToFunction } from '../src/compile' -import type { DateTimeFormats } from '../src/types/index' +import type { DateTimeFormats } from '../src/types' type MyDateTimeSchema = { short: {} // loose schema diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index 8ce7d6ac3..0739bb1dd 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -980,22 +980,6 @@ export interface Composer< DateTimeFormats = {}, NumberFormats = {}, OptionLocale = unknown, - Schema extends { - message?: unknown - datetime?: unknown - number?: unknown - } = { - message: LocaleMessage - datetime: DateTimeFormat - number: NumberFormat - }, - SchemaLocales extends - | { - messages: unknown - datetimeFormats: unknown - numberFormats: unknown - } - | string = Locale, ResourceLocales = | PickupLocales> | PickupLocales> @@ -1596,8 +1580,8 @@ export function createComposer< Options['messages'], Options['datetimeFormats'], Options['numberFormats'], - Options['locale'], - SchemaParams, Message> + Options['locale'] + // SchemaParams, Message> > export function createComposer< @@ -1620,9 +1604,9 @@ export function createComposer< Options['messages'], Options['datetimeFormats'], Options['numberFormats'], - Options['locale'], - SchemaParams, - LocaleParams + Options['locale'] + // SchemaParams, + // LocaleParams > /** diff --git a/packages/vue-i18n/src/devtools.ts b/packages/vue-i18n/src/devtools.ts index 4975b67af..9f036c463 100644 --- a/packages/vue-i18n/src/devtools.ts +++ b/packages/vue-i18n/src/devtools.ts @@ -393,6 +393,7 @@ function inspectScope< const composer = getComposer(payload.nodeId, i18n) if (composer) { // TODO: + // eslint-disable-next-line @typescript-eslint/no-explicit-any payload.state = makeScopeInspectState(composer as any) } return null diff --git a/packages/vue-i18n/test/composer.test.ts b/packages/vue-i18n/test/composer.test.ts index 3c0f91e45..419a2059c 100644 --- a/packages/vue-i18n/test/composer.test.ts +++ b/packages/vue-i18n/test/composer.test.ts @@ -28,7 +28,6 @@ import { PathValue, MessageResolver } from '@intlify/core-base' -import { stringify } from 'node:querystring' beforeEach(() => { registerMessageCompiler(compileToFunction) diff --git a/test-d/core-base/context.test-d.ts b/test-d/core-base/context.test-d.ts index a6af96d1b..e5a414820 100644 --- a/test-d/core-base/context.test-d.ts +++ b/test-d/core-base/context.test-d.ts @@ -7,7 +7,7 @@ import { LocaleParams, PickupFallbackLocales, createCoreContext -} from '../../packages/core-base/src/context' +} from '../../packages/core-base/src' import type { ResourceSchema, MyDatetimeScehma, diff --git a/test-d/core-base/datetime.test-d.ts b/test-d/core-base/datetime.test-d.ts index 4585b7418..550ff700a 100644 --- a/test-d/core-base/datetime.test-d.ts +++ b/test-d/core-base/datetime.test-d.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { expectType } from '../index' -import { createCoreContext } from '../../packages/core-base/src/context' -import { datetime } from '../../packages/core-base/src/datetime' +import { createCoreContext } from '../../packages/core-base/src' +import { datetime } from '../../packages/core-base/src' const ctx = createCoreContext({ locale: 'en-US', diff --git a/test-d/core-base/number.test-d.ts b/test-d/core-base/number.test-d.ts index 1588f39b0..1532d6c04 100644 --- a/test-d/core-base/number.test-d.ts +++ b/test-d/core-base/number.test-d.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { expectType } from '../index' -import { createCoreContext } from '../../packages/core-base/src/context' -import { number } from '../../packages/core-base/src/number' +import { createCoreContext } from '../../packages/core-base/src' +import { number } from '../../packages/core-base/src' const ctx = createCoreContext({ locale: 'en-US', diff --git a/test-d/core-base/translate.test-d.ts b/test-d/core-base/translate.test-d.ts index f8251d177..e9ea92a08 100644 --- a/test-d/core-base/translate.test-d.ts +++ b/test-d/core-base/translate.test-d.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { expectType } from '../index' -import { createCoreContext } from '../../packages/core-base/src/context' -import { translate } from '../../packages/core-base/src/translate' +import { createCoreContext } from '../../packages/core-base/src' +import { translate } from '../../packages/core-base/src' const ctx = createCoreContext({ locale: 'en', diff --git a/test-d/vue-i18n/composer.test-d.ts b/test-d/vue-i18n/composer.test-d.ts index a2174d174..d09c163e9 100644 --- a/test-d/vue-i18n/composer.test-d.ts +++ b/test-d/vue-i18n/composer.test-d.ts @@ -1,16 +1,15 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { expectType } from '../index' +import { expectType } from '..' -import { Ref } from 'vue' import { LocaleMessageValue, PickupFallbackLocales -} from '../../packages/core-base/src/context' +} from '../../packages/core-base/src' import { ComposerOptions, createComposer } from '../../packages/vue-i18n/src/composer' -import { SchemaParams, LocaleParams } from '../../packages/core-base/src/' +import { SchemaParams, LocaleParams } from '../../packages/core-base/src' type ResourceSchema = { foo: string From add26a57448f6cc84074c196d8753cb48da7c89e Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 11 May 2021 09:08:43 +0900 Subject: [PATCH 07/24] export APIs --- packages/vue-i18n/src/composer.ts | 9 ++++++--- packages/vue-i18n/src/index.ts | 9 +++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index 0739bb1dd..d047cb31a 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -1290,6 +1290,7 @@ export interface Composer< */ mergeLocaleMessage< MessageSchema extends LocaleMessage = never, + LocaleSchema extends string = string, Locale extends PickupLocales> = PickupLocales< NonNullable >, @@ -1297,7 +1298,7 @@ export interface Composer< ? Record : MessageSchema >( - locale: Locale, + locale: LocaleSchema | Locale, message: Message ): void /** @@ -1355,6 +1356,7 @@ export interface Composer< */ mergeDateTimeFormat< DateTimeSchema extends Record = never, + LocaleSchema extends string = string, Locale extends PickupLocales> = PickupLocales< NonNullable >, @@ -1362,7 +1364,7 @@ export interface Composer< ? Record : DateTimeSchema >( - locale: Locale, + locale: LocaleSchema | Locale, format: Formats ): void /** @@ -1420,6 +1422,7 @@ export interface Composer< */ mergeNumberFormat< NumberSchema extends Record = never, + LocaleSchema extends string = string, Locale extends PickupLocales> = PickupLocales< NonNullable >, @@ -1427,7 +1430,7 @@ export interface Composer< ? Record : NumberSchema >( - locale: Locale, + locale: LocaleSchema | Locale, format: Formats ): void /** diff --git a/packages/vue-i18n/src/index.ts b/packages/vue-i18n/src/index.ts index a11d2aa82..648696399 100644 --- a/packages/vue-i18n/src/index.ts +++ b/packages/vue-i18n/src/index.ts @@ -37,7 +37,11 @@ export { ComposerOptions, Composer, CustomBlock, - CustomBlocks + CustomBlocks, + ComposerTranslation, + ComposerDateTimeFormatting, + ComposerNumberFormatting, + ComposerResolveLocaleMessageTranslation } from './composer' export { TranslateResult, @@ -49,7 +53,8 @@ export { NumberFormatResult, Formatter, VueI18nOptions, - VueI18n + VueI18n, + ComponentInstanceCreatedListener } from './legacy' export { createI18n, From 6de781e907b5a538c3037f039528598292402282 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 11 May 2021 09:39:14 +0900 Subject: [PATCH 08/24] tweak types --- packages/vue-i18n/src/composer.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index d047cb31a..0f37dc0ef 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -1768,7 +1768,7 @@ export function createComposer( ? ((_context as unknown) as CoreInternalContext).__v_emitter : undefined, __meta: { framework: 'vue' } - } as any + } return createCoreContext(ctxOptions) as CoreContext< Message, LocaleMessages, Message>, @@ -2079,7 +2079,7 @@ export function createComposer( return messages != null ? messages : __root - ? __root.tm(key as any) as LocaleMessageValue || {} + ? __root.tm(key) as LocaleMessageValue || {} : {} } From b28c38252c5599f6e1538ab317a31ca3e162bd50 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Sat, 15 May 2021 18:33:07 +0900 Subject: [PATCH 09/24] add legacy API type safe --- packages/vue-i18n/src/composer.ts | 9 +- packages/vue-i18n/src/devtools.ts | 14 +- packages/vue-i18n/src/directive.ts | 13 +- packages/vue-i18n/src/i18n.ts | 114 ++- packages/vue-i18n/src/legacy.ts | 1282 +++++++++++++++++----------- packages/vue-i18n/src/mixin.ts | 65 +- test-d/vue-i18n/composer.test-d.ts | 19 +- test-d/vue-i18n/legacy.test-d.ts | 251 ++++++ 8 files changed, 1155 insertions(+), 612 deletions(-) create mode 100644 test-d/vue-i18n/legacy.test-d.ts diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index 0f37dc0ef..90dd990cb 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -928,11 +928,10 @@ export interface ComposerNumberFormatting< * @returns Formatted value */ < - Value extends number = number, Key extends string = string, ResourceKeys extends PickupFormatKeys = PickupFormatKeys >( - value: Value, + value: number, keyOrOptions: | Key | ResourceKeys @@ -953,11 +952,10 @@ export interface ComposerNumberFormatting< * @returns Formatted value */ < - Value extends number = number, Key extends string = string, ResourceKeys extends PickupFormatKeys = PickupFormatKeys >( - value: Value, + value: number, keyOrOptions: | Key | ResourceKeys @@ -1584,7 +1582,6 @@ export function createComposer< Options['datetimeFormats'], Options['numberFormats'], Options['locale'] - // SchemaParams, Message> > export function createComposer< @@ -1608,8 +1605,6 @@ export function createComposer< Options['datetimeFormats'], Options['numberFormats'], Options['locale'] - // SchemaParams, - // LocaleParams > /** diff --git a/packages/vue-i18n/src/devtools.ts b/packages/vue-i18n/src/devtools.ts index 9f036c463..67284c95b 100644 --- a/packages/vue-i18n/src/devtools.ts +++ b/packages/vue-i18n/src/devtools.ts @@ -28,7 +28,7 @@ import type { } from '@vue/devtools-api' import type { VueDevToolsTimelineEventPayloads } from '@intlify/vue-devtools' import type { I18n, I18nInternal } from './i18n' -import type { Composer } from './composer' +import type { Composer, VueMessageType } from './composer' import type { VueI18nInternal } from './legacy' type _I18n< @@ -348,11 +348,17 @@ function getComposer< >( nodeId: string, i18n: _I18n -): Composer | null { +): Composer | null { if (nodeId === 'global') { return i18n.mode === 'composition' - ? (i18n.global as Composer) + ? (i18n.global as Composer< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + >) : ((i18n.global as unknown) as VueI18nInternal< + VueMessageType, Messages, DateTimeFormats, NumberFormats @@ -365,11 +371,13 @@ function getComposer< return i18n.mode === 'composition' ? // TODO: ((instance as unknown) as Composer< + VueMessageType, Messages, DateTimeFormats, NumberFormats >) : ((instance as unknown) as VueI18nInternal< + VueMessageType, Messages, DateTimeFormats, NumberFormats diff --git a/packages/vue-i18n/src/directive.ts b/packages/vue-i18n/src/directive.ts index 3e30b0cfa..f8bfb7c40 100644 --- a/packages/vue-i18n/src/directive.ts +++ b/packages/vue-i18n/src/directive.ts @@ -9,7 +9,7 @@ import type { } from 'vue' import type { I18n, I18nInternal } from './i18n' import type { VueI18n, VueI18nInternal } from './legacy' -import type { Composer } from './composer' +import type { Composer, VueMessageType } from './composer' import type { Locale, TranslateOptions, NamedValue } from '@intlify/core-base' type VTDirectiveValue = { @@ -28,33 +28,38 @@ function getComposer< >( i18n: I18n, instance: ComponentInternalInstance -): Composer { +): Composer { const i18nInternal = (i18n as unknown) as I18nInternal if (i18n.mode === 'composition') { return (i18nInternal.__getInstance< + VueMessageType, Messages, DateTimeFormats, NumberFormats, - Composer + Composer >(instance) || i18n.global) as Composer< + VueMessageType, Messages, DateTimeFormats, NumberFormats > } else { const vueI18n = i18nInternal.__getInstance< + VueMessageType, Messages, DateTimeFormats, NumberFormats, - VueI18n + VueI18n >(instance) return vueI18n != null ? ((vueI18n as unknown) as VueI18nInternal< + VueMessageType, Messages, DateTimeFormats, NumberFormats >).__composer : ((i18n.global as unknown) as VueI18nInternal< + VueMessageType, Messages, DateTimeFormats, NumberFormats diff --git a/packages/vue-i18n/src/i18n.ts b/packages/vue-i18n/src/i18n.ts index 9a0791318..8d1e82b18 100644 --- a/packages/vue-i18n/src/i18n.ts +++ b/packages/vue-i18n/src/i18n.ts @@ -143,8 +143,8 @@ export interface I18n< * An instance of this property is **global scope***. */ readonly global: Legacy extends true - ? VueI18n - : Composer + ? VueI18n + : Composer /** * Install entry point * @@ -162,22 +162,24 @@ export interface I18n< export interface I18nInternal { __instances: Map __getInstance< + Message, Messages, DateTimeFormats, NumberFormats, Instance extends - | VueI18n - | Composer + | VueI18n + | Composer >( component: ComponentInternalInstance ): Instance | null __setInstance< + Message, Messages, DateTimeFormats, NumberFormats, Instance extends - | VueI18n - | Composer + | VueI18n + | Composer >( component: ComponentInternalInstance, instance: Instance @@ -326,12 +328,12 @@ export function createI18n< const __globalInjection = !!options.globalInjection const __instances = new Map< ComponentInternalInstance, - VueI18n | Composer + VueI18n | Composer >() // prettier-ignore const __global = __FEATURE_LEGACY_API__ && __legacyMode - ? createVueI18n(options as any) // TODO: - : createComposer(options as any) // TODO: + ? createVueI18n(options as any) + : createComposer(options as any) const symbol: InjectionKey | string = makeSymbol( __DEV__ ? 'vue-i18n' : '' ) @@ -339,10 +341,10 @@ export function createI18n< type Legacy = Options['legacy'] extends boolean ? Options['legacy'] : true // prettier-ignore type GlobalType = Legacy extends true - ? VueI18n + ? VueI18n : Legacy extends false - ? Composer - : VueI18n + ? Composer + : VueI18n const i18n = { // mode @@ -352,18 +354,28 @@ export function createI18n< // install plugin async install(app: App, ...options: unknown[]): Promise { if ((__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) && !__NODE_JS__) { - app.__VUE_I18N__ = i18n as _I18n + app.__VUE_I18N__ = (i18n as unknown) as _I18n } // setup global provider app.__VUE_I18N_SYMBOL__ = symbol - app.provide(app.__VUE_I18N_SYMBOL__, i18n as I18n) + app.provide(app.__VUE_I18N_SYMBOL__, (i18n as unknown) as I18n) // global method and properties injection for Composition API if (!__legacyMode && __globalInjection) { - injectGlobalFields( + injectGlobalFields< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + >( app, - i18n.global as Composer + i18n.global as Composer< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + > ) } @@ -379,21 +391,32 @@ export function createI18n< // setup mixin for Legacy API if (__FEATURE_LEGACY_API__ && __legacyMode) { app.mixin( - defineMixin( - __global as VueI18n, + defineMixin( + (__global as unknown) as VueI18n< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + >, ((__global as unknown) as VueI18nInternal< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + >).__composer as Composer< + VueMessageType, Messages, DateTimeFormats, NumberFormats - >).__composer as Composer, - i18n as I18nInternal + >, + (i18n as unknown) as I18nInternal ) ) } // setup vue-devtools plugin if ((__DEV__ || __FEATURE_PROD_VUE_DEVTOOLS__) && !__NODE_JS__) { - const ret = await enableDevTools(app, i18n as _I18n) + const ret = await enableDevTools(app, (i18n as unknown) as _I18n) if (!ret) { throw createI18nError(I18nErrorCodes.CANNOT_SETUP_VUE_DEVTOOLS_PLUGIN) } @@ -415,7 +438,7 @@ export function createI18n< }, // global accessor get global(): GlobalType { - return __global as GlobalType + return (__global as unknown) as GlobalType }, // @internal __instances, @@ -612,10 +635,11 @@ export function useI18n< const i18nInternal = (i18n as unknown) as I18nInternal let composer = i18nInternal.__getInstance< + VueMessageType, Messages, DateTimeFormats, NumberFormats, - Composer + Composer >(instance) if (composer == null) { const type = instance.type as ComponentOptions @@ -654,18 +678,19 @@ export function useI18n< Composer >(instance, composer) */ - composer = createComposer(composerOptions) as any - setupLifeCycle( + composer = createComposer(composerOptions as any) + setupLifeCycle( i18nInternal, instance, composer as any ) i18nInternal.__setInstance< + VueMessageType, Messages, DateTimeFormats, NumberFormats, - Composer + Composer >(instance, composer as any) } @@ -683,33 +708,50 @@ function getComposer< i18n: I18n, target: ComponentInternalInstance ): Composer | null { - let composer: Composer | null = null + let composer: Composer< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + > | null = null const root = target.root let current: ComponentInternalInstance | null = target.parent while (current != null) { const i18nInternal = (i18n as unknown) as I18nInternal if (i18n.mode === 'composition') { composer = i18nInternal.__getInstance< + VueMessageType, Messages, DateTimeFormats, NumberFormats, - Composer + Composer >(current) } else { const vueI18n = i18nInternal.__getInstance< + VueMessageType, Messages, DateTimeFormats, NumberFormats, - VueI18n + VueI18n >(current) if (vueI18n != null) { composer = (vueI18n as VueI18n< + VueMessageType, Messages, DateTimeFormats, NumberFormats > & - VueI18nInternal) - .__composer as Composer + VueI18nInternal< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + >).__composer as Composer< + VueMessageType, + Messages, + DateTimeFormats, + NumberFormats + > } } if (composer != null) { @@ -721,13 +763,13 @@ function getComposer< current = current.parent } // TODO: - return composer as any + return composer } -function setupLifeCycle( +function setupLifeCycle( i18n: I18nInternal, target: ComponentInternalInstance, - composer: Composer + composer: Composer ): void { let emitter: VueDevToolsEmitter | null = null @@ -804,9 +846,9 @@ const globalExportProps = [ ] as const const globalExportMethods = ['t', 'rt', 'd', 'n', 'tm'] as const -function injectGlobalFields( +function injectGlobalFields( app: App, - composer: Composer + composer: Composer ): void { const i18n = Object.create(null) globalExportProps.forEach(prop => { diff --git a/packages/vue-i18n/src/legacy.ts b/packages/vue-i18n/src/legacy.ts index 6a08a7802..11cbf94c4 100644 --- a/packages/vue-i18n/src/legacy.ts +++ b/packages/vue-i18n/src/legacy.ts @@ -20,7 +20,6 @@ import type { PluralizationRules, LinkedModifiers, NamedValue, - MessageFunction, Locale, LocaleMessage, LocaleMessages, @@ -32,7 +31,15 @@ import type { DateTimeFormats as DateTimeFormatsType, NumberFormats as NumberFormatsType, DateTimeFormat, - NumberFormat + NumberFormat, + PickupKeys, + PickupFormatKeys, + PickupLocales, + ResourcePath, + ResourceValue, + SchemaParams, + LocaleParams, + FallbackLocales } from '@intlify/core-base' import type { VueDevToolsEmitter } from '@intlify/vue-devtools' import type { @@ -40,7 +47,8 @@ import type { MissingHandler, Composer, ComposerOptions, - ComposerInternalOptions + ComposerInternalOptions, + ComposerResolveLocaleMessageTranslation } from './composer' /** @VueI18nLegacy */ @@ -73,7 +81,30 @@ export type ComponentInstanceCreatedListener = ( * * @VueI18nLegacy */ -export interface VueI18nOptions { +export interface VueI18nOptions< + Message = VueMessageType, + Schema extends { + message?: unknown + datetime?: unknown + number?: unknown + } = { + message: LocaleMessage + datetime: DateTimeFormat + number: NumberFormat + }, + Locales extends + | { + messages: unknown + datetimeFormats: unknown + numberFormats: unknown + } + | string = Locale, + Options extends ComposerOptions = ComposerOptions< + Message, + Schema, + Locales + > +> { /** * @remarks * The locale of localization. @@ -84,7 +115,7 @@ export interface VueI18nOptions { * * @defaultValue `'en-US'` */ - locale?: Locale + locale?: Options['locale'] /** * @remarks * The locale of fallback localization. @@ -95,7 +126,7 @@ export interface VueI18nOptions { * * @defaultValue The default `'en-US'` for the `locale` if it's not specified, or it's `locale` value */ - fallbackLocale?: FallbackLocale + fallbackLocale?: Options['fallbackLocale'] /** * @remarks * The locale messages of localization. @@ -104,14 +135,14 @@ export interface VueI18nOptions { * * @defaultValue `{}` */ - messages?: LocaleMessages + messages?: Options['messages'] /** * @remarks * Allow use flat json messages or not * * @defaultValue `false` */ - flatJson?: boolean + flatJson?: Options['flatJson'] /** * @remarks * The datetime formats of localization. @@ -120,7 +151,7 @@ export interface VueI18nOptions { * * @defaultValue `{}` */ - datetimeFormats?: DateTimeFormatsType + datetimeFormats?: Options['datetimeFormats'] /** * @remarks * The number formats of localization. @@ -129,7 +160,7 @@ export interface VueI18nOptions { * * @defaultValue `{}` */ - numberFormats?: NumberFormatsType + numberFormats?: Options['numberFormats'] /** * @remarks * The list of available locales in messages in lexical order. @@ -143,7 +174,7 @@ export interface VueI18nOptions { * * @VueI18nSee [Custom Modifiers](../guide/essentials/syntax#custom-modifiers) */ - modifiers?: LinkedModifiers + modifiers?: Options['modifiers'] /** * @remarks * The formatter that implemented with Formatter interface. @@ -161,7 +192,7 @@ export interface VueI18nOptions { * * @defaultValue `null` */ - missing?: MissingHandler + missing?: Options['missing'] /** * @remarks * In the component localization, whether to fall back to root level (global scope) localization when localization fails. @@ -172,7 +203,7 @@ export interface VueI18nOptions { * * @defaultValue `true` */ - fallbackRoot?: boolean + fallbackRoot?: Options['fallbackRoot'] /** * @remarks * Whether suppress warnings outputted when localization fails. @@ -185,7 +216,7 @@ export interface VueI18nOptions { * * @defaultValue `false` */ - silentTranslationWarn?: boolean | RegExp + silentTranslationWarn?: Options['missingWarn'] /** * @remarks * Whether do template interpolation on translation keys when your language lacks a translation for a key. @@ -196,7 +227,7 @@ export interface VueI18nOptions { * * @defaultValue `false` */ - silentFallbackWarn?: boolean | RegExp + silentFallbackWarn?: Options['fallbackWarn'] /** * @remarks * Whether suppress warnings when falling back to either `fallbackLocale` or root. @@ -205,7 +236,7 @@ export interface VueI18nOptions { * * @defaultValue `false` */ - formatFallbackMessages?: boolean + formatFallbackMessages?: Options['fallbackFormat'] /** * @remarks * Whether `v-t` directive's element should preserve `textContent` after directive is unbinded. @@ -246,7 +277,7 @@ export interface VueI18nOptions { * * @defaultValue `false` */ - escapeParameterHtml?: boolean + escapeParameterHtml?: Options['escapeParameter'] /** * @remarks * The shared locale messages of localization for components. More detail see Component based localization. @@ -264,7 +295,7 @@ export interface VueI18nOptions { * * @defaultValue `{}` */ - pluralizationRules?: PluralizationRules + pluralizationRules?: Options['pluralRules'] /** * @remarks * A handler for post processing of translation. The handler gets after being called with the `$t`, `t`, `$tc`, and `tc`. @@ -273,7 +304,7 @@ export interface VueI18nOptions { * * @defaultValue `null` */ - postTranslation?: PostTranslationHandler + postTranslation?: Options['postTranslation'] /** * @remarks * Whether synchronize the root level locale to the component localization locale. @@ -362,152 +393,14 @@ export interface VueI18nOptions { } /** - * VueI18n legacy interfaces + * Locale message translation functions for VueI18n legacy interfaces * - * @remarks - * This interface is compatible with interface of `VueI18n` class (offered with Vue I18n v8.x). + * @remarks + * This is the interface for {@link VueI18n} * - * @VueI18nLegacy + * @VueI18nLegacy */ -export interface VueI18n< - Messages = {}, - DateTimeFormats = {}, - NumberFormats = {} -> { - /** - * @remarks - * Instance ID. - */ - id: number - /** - * @remarks - * The current locale this VueI18n instance is using. - * - * If the locale contains a territory and a dialect, this locale contains an implicit fallback. - * - * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) - */ - locale: Locale - /** - * @remarks - * The current fallback locales this VueI18n instance is using. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - fallbackLocale: FallbackLocale - /** - * @remarks - * The list of available locales in `messages` in lexical order. - */ - readonly availableLocales: Locale[] - /** - * @remarks - * The locale messages of localization. - * - * @VueI18nSee [Getting Started](../guide/) - */ - readonly messages: LocaleMessages - /** - * @remarks - * The datetime formats of localization. - * - * @VueI18nSee [Datetime Formatting](../guide/essentials/datetime) - */ - readonly datetimeFormats: DateTimeFormats - /** - * @remarks - * The number formats of localization. - * - * @VueI18nSee [Number Formatting](../guide/essentials/number) - */ - readonly numberFormats: NumberFormats - /** - * @remarks - * Custom Modifiers for linked messages. - * - * @VueI18nSee [Custom Modifiers](../guide/essentials/syntax#custom-modifiers) - */ - readonly modifiers: LinkedModifiers - /** - * @remarks - * The formatter that implemented with Formatter interface. - * - * @deprecated See the [here](../guide/migration/breaking#remove-custom-formatter) - */ - formatter: Formatter - /** - * @remarks - * A handler for localization missing. - */ - missing: MissingHandler | null - /** - * @remarks - * A handler for post processing of translation. - */ - postTranslation: PostTranslationHandler | null - /** - * @remarks - * Whether suppress warnings outputted when localization fails. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - silentTranslationWarn: boolean | RegExp - /** - * @remarks - * Whether suppress fallback warnings when localization fails. - */ - silentFallbackWarn: boolean | RegExp - /** - * @remarks - * Whether suppress warnings when falling back to either `fallbackLocale` or root. - * - * @VueI18nSee [Fallbacking](../guide/essentials/fallback) - */ - formatFallbackMessages: boolean - /** - * @remarks - * Whether synchronize the root level locale to the component localization locale. - * - * @VueI18nSee [Local Scope](../guide/essentials/scope#local-scope-2) - */ - sync: boolean - /** - * @remarks - * Whether to allow the use locale messages of HTML formatting. - * - * If you set `warn` or` error`, will check the locale messages on the VueI18n instance. - * - * If you are specified `warn`, a warning will be output at console. - * - * If you are specified `error` will occurred an Error. - * - * @VueI18nSee [HTML Message](../guide/essentials/syntax#html-message) - * @VueI18nSee [Change `warnHtmlInMessage` option default value](../guide/migration/breaking#change-warnhtmlinmessage-option-default-value) - */ - warnHtmlInMessage: WarnHtmlInMessageLevel - /** - * @remarks - * Whether interpolation parameters are escaped before the message is translated. - * - * @VueI18nSee [HTML Message](../guide/essentials/syntax#html-message) - */ - escapeParameterHtml: boolean - /** - * @remarks - * Whether `v-t` directive's element should preserve `textContent` after directive is unbinded. - * - * @VueI18nSee [Custom Directive](../guide/advanced/directive) - * @VueI18nSee [Remove preserveDirectiveContent option](../guide/migration/breaking#remove-preservedirectivecontent-option) - * - * @deprecated The `v-t` directive for Vue 3 now preserves the default content. Therefore, this option and its properties have been removed from the VueI18n instance. - */ - preserveDirectiveContent: boolean - /** - * A set of rules for word pluralization - * - * @VueI18nSee [Custom Pluralization](../guide/essentials/pluralization#custom-pluralization) - */ - pluralizationRules: PluralizationRules +export interface VueI18nTranslation { /** * Locale message translation. * @@ -524,7 +417,12 @@ export interface VueI18n< * * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) */ - t(key: Path): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys + ): TranslateResult /** * Locale message translation. * @@ -536,7 +434,13 @@ export interface VueI18n< * * @returns Translated message */ - t(key: Path, locale: Locale): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + locale: Locales | Locale + ): TranslateResult /** * Locale message translation. * @@ -551,7 +455,14 @@ export interface VueI18n< * * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - t(key: Path, locale: Locale, list: unknown[]): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + locale: Locales | Locale, + list: unknown[] + ): TranslateResult /** * Locale message translation. * @@ -566,7 +477,14 @@ export interface VueI18n< * * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - t(key: Path, locale: Locale, named: object): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + locale: Locales | Locale, + named: Record + ): TranslateResult /** * Locale message translation. * @@ -580,7 +498,13 @@ export interface VueI18n< * * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) */ - t(key: Path, list: unknown[]): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + list: unknown[] + ): TranslateResult /** * Locale message translation. * @@ -594,111 +518,37 @@ export interface VueI18n< * * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) */ - t(key: Path, named: Record): TranslateResult - /** @internal */ - t(...args: unknown[]): TranslateResult // for $t - /** - * Resolve locale message translation - * - * @remarks - * If this is used in a reactive context, it will re-evaluate once the locale changes. - * - * @VueI18nTip - * The use-case for `rt` is for programmatic locale messages translation with using `tm`, `v-for`, javascript `for` statement. - * - * @VueI18nWarning - * `rt` differs from `t` in that it processes the locale message directly, not the key of the locale message. There is no internal fallback with `rt`. You need to understand and use the structure of the locale messge returned by `tm`. - * - * @param message - A target locale message to be resolved. You will need to specify the locale message returned by `tm`. - * - * @returns Translated message - * - * @VueI18nSee [Scope and Locale Changing](../guide/essentials/scope) - */ - rt(message: MessageFunction | VueMessageType): string - /** - * Resolve locale message translation for plurals - * - * @remarks - * Overloaded `rt`. About details, see the [rt](legacy#rt-message) details. - * - * In this overloaded `rt`, return a pluralized translation message. - * - * @VueI18nTip - * The use-case for `rt` is for programmatic locale messages translation with using `tm`, `v-for`, javascript `for` statement. - * - * @VueI18nWarning - * `rt` differs from `t` in that it processes the locale message directly, not the key of the locale message. There is no internal fallback with `rt`. You need to understand and use the structure of the locale messge returned by `tm`. - * - * @param message - A target locale message to be resolved. You will need to specify the locale message returned by `tm`. - * @param plural - Which plural string to get. 1 returns the first one. - * @param options - Additional {@link TranslateOptions | options} for translation - * - * @returns Translated message - * - * @VueI18nSee [Pluralization](../guide/essentials/pluralization) - */ - rt( - message: MessageFunction | VueMessageType, - plural: number, - options?: TranslateOptions - ): string - /** - * Resolve locale message translation for list interpolations - * - * @remarks - * Overloaded `rt`. About details, see the [rt](legacy#rt-message) details. - * - * In this overloaded `rt`, return a pluralized translation message. - * - * @VueI18nTip - * The use-case for `rt` is for programmatic locale messages translation with using `tm`, `v-for`, javascript `for` statement. - * - * @VueI18nWarning - * `rt` differs from `t` in that it processes the locale message directly, not the key of the locale message. There is no internal fallback with `rt`. You need to understand and use the structure of the locale messge returned by `tm`. - * - * @param message - A target locale message to be resolved. You will need to specify the locale message returned by `tm`. - * @param list - A values of list interpolation. - * @param options - Additional {@link TranslateOptions | options} for translation - * - * @returns Translated message - * - * @VueI18nSee [List interpolation](../guide/essentials/syntax#list-interpolation) - */ - rt( - message: MessageFunction | VueMessageType, - list: unknown[], - options?: TranslateOptions - ): string - /** - * Resolve locale message translation for named interpolations - * - * @remarks - * Overloaded `rt`. About details, see the [rt](legacy#rt-message) details. - * - * In this overloaded `rt`, for each placeholder x, the locale messages should contain a `{x}` token. - * - * @VueI18nTip - * The use-case for `rt` is for programmatic locale messages translation with using `tm`, `v-for`, javascript `for` statement. - * - * @VueI18nWarning - * `rt` differs from `t` in that it processes the locale message directly, not the key of the locale message. There is no internal fallback with `rt`. You need to understand and use the structure of the locale messge returned by `tm`. - * - * @param message - A target locale message to be resolved. You will need to specify the locale message returned by `tm`. - * @param named - A values of named interpolation. - * @param options - Additional {@link TranslateOptions | options} for translation - * - * @returns Translated message - * - * @VueI18nSee [Named interpolation](../guide/essentials/syntax#named-interpolation) - */ - rt( - message: MessageFunction | VueMessageType, - named: NamedValue, - options?: TranslateOptions - ): string - /** @internal */ - rt(...args: unknown[]): string // for $rt + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + named: Record + ): TranslateResult +} + +/** + * Resolve locale message translation functions for VueI18n legacy interfaces + * + * @remarks + * This is the interface for {@link VueI18n}. This interfce is an alias of {@link ComposerResolveLocaleMessageTranslation}. + * + * @VueI18nLegacy + */ +export type VueI18nResolveLocaleMessageTranslation< + Message, + Locales = 'en-US' +> = ComposerResolveLocaleMessageTranslation + +/** + * Locale message pluralization functions for VueI18n legacy interfaces + * + * @remarks + * This is the interface for {@link VueI18n} + * + * @VueI18nLegacy + */ +export interface VueI18nTranslationChoice { /** * Locale message pluralization * @@ -717,7 +567,12 @@ export interface VueI18n< * * @VueI18nSee [Pluralization](../guide/essentials/pluralization) */ - tc(key: Path): TranslateResult + < + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys + ): TranslateResult /** * Locale message pluralization * @@ -729,7 +584,13 @@ export interface VueI18n< * * @returns Pluraled message */ - tc(key: Path, locale: Locale): TranslateResult + < + Key extends string = string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + locale: Locales | Locale + ): TranslateResult /** * Locale message pluralization * @@ -741,7 +602,13 @@ export interface VueI18n< * * @returns Pluraled message */ - tc(key: Path, list: unknown[]): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + list: unknown[] + ): TranslateResult /** * Locale message pluralization * @@ -753,7 +620,13 @@ export interface VueI18n< * * @returns Pluraled message */ - tc(key: Path, named: Record): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + named: Record + ): TranslateResult /** * Locale message pluralization * @@ -765,7 +638,13 @@ export interface VueI18n< * * @returns Pluraled message */ - tc(key: Path, choice: number): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + choice: number + ): TranslateResult /** * Locale message pluralization * @@ -778,7 +657,14 @@ export interface VueI18n< * * @returns Pluraled message */ - tc(key: Path, choice: number, locale: Locale): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + choice: number, + locale: Locales | Locale + ): TranslateResult /** * Locale message pluralization * @@ -791,7 +677,14 @@ export interface VueI18n< * * @returns Pluraled message */ - tc(key: Path, choice: number, list: unknown[]): TranslateResult + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + choice: number, + list: unknown[] + ): TranslateResult /** * Locale message pluralization * @@ -804,48 +697,410 @@ export interface VueI18n< * * @returns Pluraled message */ - tc(key: Path, choice: number, named: Record): TranslateResult - /** @internal */ - tc(...args: unknown[]): TranslateResult // for $tc + < + Key extends string, + ResourceKeys extends PickupKeys = PickupKeys + >( + key: Key | ResourceKeys, + choice: number, + named: Record + ): TranslateResult +} + +/** + * Datetime formatting functions for VueI18n legacy interfaces + * + * @remarks + * This is the interface for {@link VueI18n} + * + * @VueI18nLegacy + */ +export interface VueI18nDateTimeFormatting< + DateTimeFormats = {}, + Locales = 'en-US' +> { /** - * Translation locale message exist + * Datetime formatting * * @remarks - * whether do exist locale message on VueI18n instance [messages](legacy#messages). + * If this is used in a reactive context, it will re-evaluate once the locale changes. * - * If you specified `locale`, check the locale messages of `locale`. + * If [i18n component options](injection#i18n) is specified, it’s formatted in preferentially local scope datetime formats than global scope locale messages. * - * @param key - A target locale message key - * @param locale - A target locale + * If [i18n component options](injection#i18n) isn't specified, it’s formatted with global scope datetime formats. * - * @returns If found locale message, `true`, else `false` + * @param value - A value, timestamp number or `Date` instance + * + * @returns Formatted value + * + * @VueI18nSee [Datetime formatting](../guide/essentials/datetime) */ - te(key: Path, locale?: Locale): boolean + (value: number | Date): DateTimeFormatResult /** - * Locale messages getter + * Datetime formatting * * @remarks - * If [i18n component options](injection#i18n) is specified, it’s get in preferentially local scope locale messages than global scope locale messages. + * Overloaded `d`. About details, see the [d](legacy#d-value) details. * - * If [i18n component options](injection#i18n) isn't specified, it’s get with global scope locale messages. + * @param value - A value, timestamp number or `Date` instance + * @param key - A key of datetime formats * - * Based on the current `locale`, locale messages will be returned from Composer instance messages. + * @returns Formatted value + */ + < + Value extends number | Date = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys = PickupFormatKeys + >( + value: Value, + key: Key | ResourceKeys + ): DateTimeFormatResult + /** + * Datetime formatting * - * If you change the `locale`, the locale messages returned will also correspond to the locale. + * @remarks + * Overloaded `d`. About details, see the [d](legacy#d-value) details. * - * If there are no locale messages for the given `key` in the composer instance messages, they will be returned with [fallbacking](../guide/essentials/fallback). + * @param value - A value, timestamp number or `Date` instance + * @param key - A key of datetime formats + * @param locale - A locale, it will be used over than global scope or local scope. * - * @VueI18nWarning - * You need to use `rt` for the locale message returned by `tm`. see the [rt](legacy#rt-message) details. + * @returns Formatted value + */ + < + Value extends number | Date = number, + Key extends string = string, + ResourceKeys extends PickupFormatKeys = PickupFormatKeys + >( + value: Value, + key: Key | ResourceKeys, + locale: Locales + ): DateTimeFormatResult + /** + * Datetime formatting * - * @example - * template: - * ```html - *
- * - + + diff --git a/examples/type-safe/package.json b/examples/type-safe/package.json new file mode 100644 index 000000000..083bb1f78 --- /dev/null +++ b/examples/type-safe/package.json @@ -0,0 +1,21 @@ +{ + "name": "type-safe", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vue-tsc --noEmit && vite build", + "serve": "vite preview" + }, + "dependencies": { + "vue": "^3.0.11", + "vue-i18n": "link:../packages/vue-i18n" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^1.2.2", + "@vue/compiler-sfc": "^3.0.11", + "typescript": "^4.1.3", + "vite": "^2.3.3", + "vue-tsc": "^0.0.24" + } +} \ No newline at end of file diff --git a/examples/type-safe/public/favicon.ico b/examples/type-safe/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/examples/type-safe/src/App.vue b/examples/type-safe/src/App.vue new file mode 100644 index 000000000..c8098c159 --- /dev/null +++ b/examples/type-safe/src/App.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/examples/type-safe/src/assets/logo.png b/examples/type-safe/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d2503fc2a44b5053b0837ebea6e87a2d339a43 GIT binary patch literal 6849 zcmaKRcUV(fvo}bjDT-7nLI_nlK}sT_69H+`qzVWDA|yaU?}j417wLi^B1KB1SLsC& zL0ag7$U(XW5YR7p&Ux?sP$d4lvMt8C^+TcQu4F zQqv!UF!I+kw)c0jhd6+g6oCr9P?7)?!qX1ui*iL{p}sKCAGuJ{{W)0z1pLF|=>h}& zt(2Lr0Z`2ig8<5i%Zk}cO5Fm=LByqGWaS`oqChZdEFmc`0hSb#gg|Aap^{+WKOYcj zHjINK)KDG%&s?Mt4CL(T=?;~U@bU2x_mLKN!#GJuK_CzbNw5SMEJorG!}_5;?R>@1 zSl)jns3WlU7^J%=(hUtfmuUCU&C3%8B5C^f5>W2Cy8jW3#{Od{lF1}|?c61##3dzA zsPlFG;l_FzBK}8>|H_Ru_H#!_7$UH4UKo3lKOA}g1(R&|e@}GINYVzX?q=_WLZCgh z)L|eJMce`D0EIwgRaNETDsr+?vQknSGAi=7H00r`QnI%oQnFxm`G2umXso9l+8*&Q z7WqF|$p49js$mdzo^BXpH#gURy=UO;=IMrYc5?@+sR4y_?d*~0^YP7d+y0{}0)zBM zIKVM(DBvICK#~7N0a+PY6)7;u=dutmNqK3AlsrUU9U`d;msiucB_|8|2kY=(7XA;G zwDA8AR)VCA#JOkxm#6oHNS^YVuOU;8p$N)2{`;oF|rQ?B~K$%rHDxXs+_G zF5|-uqHZvSzq}L;5Kcy_P+x0${33}Ofb6+TX&=y;;PkEOpz%+_bCw_{<&~ zeLV|!bP%l1qxywfVr9Z9JI+++EO^x>ZuCK);=$VIG1`kxK8F2M8AdC$iOe3cj1fo(ce4l-9 z7*zKy3={MixvUk=enQE;ED~7tv%qh&3lR<0m??@w{ILF|e#QOyPkFYK!&Up7xWNtL zOW%1QMC<3o;G9_S1;NkPB6bqbCOjeztEc6TsBM<(q9((JKiH{01+Ud=uw9B@{;(JJ z-DxI2*{pMq`q1RQc;V8@gYAY44Z!%#W~M9pRxI(R?SJ7sy7em=Z5DbuDlr@*q|25V)($-f}9c#?D%dU^RS<(wz?{P zFFHtCab*!rl(~j@0(Nadvwg8q|4!}L^>d?0al6}Rrv9$0M#^&@zjbfJy_n!%mVHK4 z6pLRIQ^Uq~dnyy$`ay51Us6WaP%&O;@49m&{G3z7xV3dLtt1VTOMYl3UW~Rm{Eq4m zF?Zl_v;?7EFx1_+#WFUXxcK78IV)FO>42@cm@}2I%pVbZqQ}3;p;sDIm&knay03a^ zn$5}Q$G!@fTwD$e(x-~aWP0h+4NRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*VA4|QE7bf@-4vb?Q+pPKLkY2{yKsw{&udv_2v8{Dbd zm~8VAv!G~s)`O3|Q6vFUV%8%+?ZSVUa(;fhPNg#vab@J*9XE4#D%)$UU-T5`fwjz! z6&gA^`OGu6aUk{l*h9eB?opVdrHK>Q@U>&JQ_2pR%}TyOXGq_6s56_`U(WoOaAb+K zXQr#6H}>a-GYs9^bGP2Y&hSP5gEtW+GVC4=wy0wQk=~%CSXj=GH6q z-T#s!BV`xZVxm{~jr_ezYRpqqIcXC=Oq`b{lu`Rt(IYr4B91hhVC?yg{ol4WUr3v9 zOAk2LG>CIECZ-WIs0$N}F#eoIUEtZudc7DPYIjzGqDLWk_A4#(LgacooD z2K4IWs@N`Bddm-{%oy}!k0^i6Yh)uJ1S*90>|bm3TOZxcV|ywHUb(+CeX-o1|LTZM zwU>dY3R&U)T(}5#Neh?-CWT~@{6Ke@sI)uSuzoah8COy)w)B)aslJmp`WUcjdia-0 zl2Y}&L~XfA`uYQboAJ1;J{XLhYjH){cObH3FDva+^8ioOQy%Z=xyjGLmWMrzfFoH; zEi3AG`_v+%)&lDJE;iJWJDI@-X9K5O)LD~j*PBe(wu+|%ar~C+LK1+-+lK=t# z+Xc+J7qp~5q=B~rD!x78)?1+KUIbYr^5rcl&tB-cTtj+e%{gpZZ4G~6r15+d|J(ky zjg@@UzMW0k9@S#W(1H{u;Nq(7llJbq;;4t$awM;l&(2s+$l!Ay9^Ge|34CVhr7|BG z?dAR83smef^frq9V(OH+a+ki#q&-7TkWfFM=5bsGbU(8mC;>QTCWL5ydz9s6k@?+V zcjiH`VI=59P-(-DWXZ~5DH>B^_H~;4$)KUhnmGo*G!Tq8^LjfUDO)lASN*=#AY_yS zqW9UX(VOCO&p@kHdUUgsBO0KhXxn1sprK5h8}+>IhX(nSXZKwlNsjk^M|RAaqmCZB zHBolOHYBas@&{PT=R+?d8pZu zUHfyucQ`(umXSW7o?HQ3H21M`ZJal+%*)SH1B1j6rxTlG3hx1IGJN^M7{$j(9V;MZ zRKybgVuxKo#XVM+?*yTy{W+XHaU5Jbt-UG33x{u(N-2wmw;zzPH&4DE103HV@ER86 z|FZEmQb|&1s5#`$4!Cm}&`^{(4V}OP$bk`}v6q6rm;P!H)W|2i^e{7lTk2W@jo_9q z*aw|U7#+g59Fv(5qI`#O-qPj#@_P>PC#I(GSp3DLv7x-dmYK=C7lPF8a)bxb=@)B1 zUZ`EqpXV2dR}B&r`uM}N(TS99ZT0UB%IN|0H%DcVO#T%L_chrgn#m6%x4KE*IMfjX zJ%4veCEqbXZ`H`F_+fELMC@wuy_ch%t*+Z+1I}wN#C+dRrf2X{1C8=yZ_%Pt6wL_~ zZ2NN-hXOT4P4n$QFO7yYHS-4wF1Xfr-meG9Pn;uK51?hfel`d38k{W)F*|gJLT2#T z<~>spMu4(mul-8Q3*pf=N4DcI)zzjqAgbE2eOT7~&f1W3VsdD44Ffe;3mJp-V@8UC z)|qnPc12o~$X-+U@L_lWqv-RtvB~%hLF($%Ew5w>^NR82qC_0FB z)=hP1-OEx?lLi#jnLzH}a;Nvr@JDO-zQWd}#k^an$Kwml;MrD&)sC5b`s0ZkVyPkb zt}-jOq^%_9>YZe7Y}PhW{a)c39G`kg(P4@kxjcYfgB4XOOcmezdUI7j-!gs7oAo2o zx(Ph{G+YZ`a%~kzK!HTAA5NXE-7vOFRr5oqY$rH>WI6SFvWmahFav!CfRMM3%8J&c z*p+%|-fNS_@QrFr(at!JY9jCg9F-%5{nb5Bo~z@Y9m&SHYV`49GAJjA5h~h4(G!Se zZmK{Bo7ivCfvl}@A-ptkFGcWXAzj3xfl{evi-OG(TaCn1FAHxRc{}B|x+Ua1D=I6M z!C^ZIvK6aS_c&(=OQDZfm>O`Nxsw{ta&yiYPA~@e#c%N>>#rq)k6Aru-qD4(D^v)y z*>Rs;YUbD1S8^D(ps6Jbj0K3wJw>L4m)0e(6Pee3Y?gy9i0^bZO?$*sv+xKV?WBlh zAp*;v6w!a8;A7sLB*g-^<$Z4L7|5jXxxP1}hQZ<55f9<^KJ>^mKlWSGaLcO0=$jem zWyZkRwe~u{{tU63DlCaS9$Y4CP4f?+wwa(&1ou)b>72ydrFvm`Rj-0`kBJgK@nd(*Eh!(NC{F-@=FnF&Y!q`7){YsLLHf0_B6aHc# z>WIuHTyJwIH{BJ4)2RtEauC7Yq7Cytc|S)4^*t8Va3HR zg=~sN^tp9re@w=GTx$;zOWMjcg-7X3Wk^N$n;&Kf1RgVG2}2L-(0o)54C509C&77i zrjSi{X*WV=%C17((N^6R4Ya*4#6s_L99RtQ>m(%#nQ#wrRC8Y%yxkH;d!MdY+Tw@r zjpSnK`;C-U{ATcgaxoEpP0Gf+tx);buOMlK=01D|J+ROu37qc*rD(w`#O=3*O*w9?biwNoq3WN1`&Wp8TvKj3C z3HR9ssH7a&Vr<6waJrU zdLg!ieYz%U^bmpn%;(V%%ugMk92&?_XX1K@mwnVSE6!&%P%Wdi7_h`CpScvspMx?N zQUR>oadnG17#hNc$pkTp+9lW+MBKHRZ~74XWUryd)4yd zj98$%XmIL4(9OnoeO5Fnyn&fpQ9b0h4e6EHHw*l68j;>(ya`g^S&y2{O8U>1*>4zR zq*WSI_2o$CHQ?x0!wl9bpx|Cm2+kFMR)oMud1%n2=qn5nE&t@Fgr#=Zv2?}wtEz^T z9rrj=?IH*qI5{G@Rn&}^Z{+TW}mQeb9=8b<_a`&Cm#n%n~ zU47MvCBsdXFB1+adOO)03+nczfWa#vwk#r{o{dF)QWya9v2nv43Zp3%Ps}($lA02*_g25t;|T{A5snSY?3A zrRQ~(Ygh_ebltHo1VCbJb*eOAr;4cnlXLvI>*$-#AVsGg6B1r7@;g^L zFlJ_th0vxO7;-opU@WAFe;<}?!2q?RBrFK5U{*ai@NLKZ^};Ul}beukveh?TQn;$%9=R+DX07m82gP$=}Uo_%&ngV`}Hyv8g{u z3SWzTGV|cwQuFIs7ZDOqO_fGf8Q`8MwL}eUp>q?4eqCmOTcwQuXtQckPy|4F1on8l zP*h>d+cH#XQf|+6c|S{7SF(Lg>bR~l(0uY?O{OEVlaxa5@e%T&xju=o1`=OD#qc16 zSvyH*my(dcp6~VqR;o(#@m44Lug@~_qw+HA=mS#Z^4reBy8iV?H~I;{LQWk3aKK8$bLRyt$g?- +

{{ t('nest.foo') }}

+ + + + + diff --git a/examples/type-safe/src/locales/en.json b/examples/type-safe/src/locales/en.json new file mode 100644 index 000000000..57f07c054 --- /dev/null +++ b/examples/type-safe/src/locales/en.json @@ -0,0 +1,12 @@ +{ + "hello": "Hello!", + "nest": { + "foo": { + "bar": { + "buz": { + "msg": "nest message!" + } + } + } + } +} \ No newline at end of file diff --git a/examples/type-safe/src/locales/schema.ts b/examples/type-safe/src/locales/schema.ts new file mode 100644 index 000000000..9463fd464 --- /dev/null +++ b/examples/type-safe/src/locales/schema.ts @@ -0,0 +1,4 @@ +import en from './en.json' + +// define the resource schema from default language resource +export type ResourceSchema = typeof en diff --git a/examples/type-safe/src/main.ts b/examples/type-safe/src/main.ts new file mode 100644 index 000000000..f5e704b6a --- /dev/null +++ b/examples/type-safe/src/main.ts @@ -0,0 +1,20 @@ +import { createApp } from 'vue' +import App from './App.vue' +import { createI18n } from 'vue-i18n' +import en from './locales/en.json' +import type { ResourceSchema } from './locales/schema' + +/** + * if you can specify resource schema to type parameter of `createI18n`, + * you can make to be type-safe the i18n resources. + */ +const i18n = createI18n<[ResourceSchema], 'en' | 'ja', false>({ + locale: 'en', + legacy: false, + fallbackLocale: 'en', + messages: { + en + } +}) + +createApp(App).use(i18n).mount('#app') diff --git a/examples/type-safe/src/shims-vue.d.ts b/examples/type-safe/src/shims-vue.d.ts new file mode 100644 index 000000000..ac1ded792 --- /dev/null +++ b/examples/type-safe/src/shims-vue.d.ts @@ -0,0 +1,5 @@ +declare module '*.vue' { + import { DefineComponent } from 'vue' + const component: DefineComponent<{}, {}, any> + export default component +} diff --git a/examples/type-safe/tsconfig.json b/examples/type-safe/tsconfig.json new file mode 100644 index 000000000..e754e6529 --- /dev/null +++ b/examples/type-safe/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "esnext", + "module": "esnext", + "moduleResolution": "node", + "strict": true, + "jsx": "preserve", + "sourceMap": true, + "resolveJsonModule": true, + "esModuleInterop": true, + "lib": ["esnext", "dom"], + "types": ["vite/client"] + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] +} diff --git a/examples/type-safe/vite.config.ts b/examples/type-safe/vite.config.ts new file mode 100644 index 000000000..315212d69 --- /dev/null +++ b/examples/type-safe/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue()] +}) diff --git a/examples/type-safe/yarn.lock b/examples/type-safe/yarn.lock new file mode 100644 index 000000000..bb43ecb8c --- /dev/null +++ b/examples/type-safe/yarn.lock @@ -0,0 +1,614 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/helper-validator-identifier@^7.14.0": + version "7.14.0" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" + integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== + +"@babel/parser@^7.12.0", "@babel/parser@^7.13.9": + version "7.14.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.3.tgz#9b530eecb071fd0c93519df25c5ff9f14759f298" + integrity sha512-7MpZDIfI7sUC5zWo2+foJ50CSI5lcqDehZ0lVgIhSi4bFEk94fLAKlF3Q0nzSQQ+ca0lm+O6G9ztKVBeu8PMRQ== + +"@babel/types@^7.12.0", "@babel/types@^7.13.0": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.2.tgz#4208ae003107ef8a057ea8333e56eb64d2f6a2c3" + integrity sha512-SdjAG/3DikRHpUOjxZgnkbR11xUlyDMUFJdvnIgZEE16mqmY0BINMmc4//JMJglEmn6i7sq6p+mGrFWyZ98EEw== + dependencies: + "@babel/helper-validator-identifier" "^7.14.0" + to-fast-properties "^2.0.0" + +"@vitejs/plugin-vue@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-1.2.2.tgz#b0038fc11b9099f4cd01fcbf0ee419adda417b52" + integrity sha512-5BI2WFfs/Z0pAV4S/IQf1oH3bmFYlL5ATMBHgTt1Lf7hAnfpNd5oUAAs6hZPfk3QhvyUQgtk0rJBlabwNFcBJQ== + +"@vue/compiler-core@3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.0.11.tgz#5ef579e46d7b336b8735228758d1c2c505aae69a" + integrity sha512-6sFj6TBac1y2cWCvYCA8YzHJEbsVkX7zdRs/3yK/n1ilvRqcn983XvpBbnN3v4mZ1UiQycTvOiajJmOgN9EVgw== + dependencies: + "@babel/parser" "^7.12.0" + "@babel/types" "^7.12.0" + "@vue/shared" "3.0.11" + estree-walker "^2.0.1" + source-map "^0.6.1" + +"@vue/compiler-dom@3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.0.11.tgz#b15fc1c909371fd671746020ba55b5dab4a730ee" + integrity sha512-+3xB50uGeY5Fv9eMKVJs2WSRULfgwaTJsy23OIltKgMrynnIj8hTYY2UL97HCoz78aDw1VDXdrBQ4qepWjnQcw== + dependencies: + "@vue/compiler-core" "3.0.11" + "@vue/shared" "3.0.11" + +"@vue/compiler-sfc@^3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.0.11.tgz#cd8ca2154b88967b521f5ad3b10f5f8b6b665679" + integrity sha512-7fNiZuCecRleiyVGUWNa6pn8fB2fnuJU+3AGjbjl7r1P5wBivfl02H4pG+2aJP5gh2u+0wXov1W38tfWOphsXw== + dependencies: + "@babel/parser" "^7.13.9" + "@babel/types" "^7.13.0" + "@vue/compiler-core" "3.0.11" + "@vue/compiler-dom" "3.0.11" + "@vue/compiler-ssr" "3.0.11" + "@vue/shared" "3.0.11" + consolidate "^0.16.0" + estree-walker "^2.0.1" + hash-sum "^2.0.0" + lru-cache "^5.1.1" + magic-string "^0.25.7" + merge-source-map "^1.1.0" + postcss "^8.1.10" + postcss-modules "^4.0.0" + postcss-selector-parser "^6.0.4" + source-map "^0.6.1" + +"@vue/compiler-ssr@3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.0.11.tgz#ac5a05fd1257412fa66079c823d8203b6a889a13" + integrity sha512-66yUGI8SGOpNvOcrQybRIhl2M03PJ+OrDPm78i7tvVln86MHTKhM3ERbALK26F7tXl0RkjX4sZpucCpiKs3MnA== + dependencies: + "@vue/compiler-dom" "3.0.11" + "@vue/shared" "3.0.11" + +"@vue/reactivity@3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.11.tgz#07b588349fd05626b17f3500cbef7d4bdb4dbd0b" + integrity sha512-SKM3YKxtXHBPMf7yufXeBhCZ4XZDKP9/iXeQSC8bBO3ivBuzAi4aZi0bNoeE2IF2iGfP/AHEt1OU4ARj4ao/Xw== + dependencies: + "@vue/shared" "3.0.11" + +"@vue/runtime-core@3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.0.11.tgz#c52dfc6acf3215493623552c1c2919080c562e44" + integrity sha512-87XPNwHfz9JkmOlayBeCCfMh9PT2NBnv795DSbi//C/RaAnc/bGZgECjmkD7oXJ526BZbgk9QZBPdFT8KMxkAg== + dependencies: + "@vue/reactivity" "3.0.11" + "@vue/shared" "3.0.11" + +"@vue/runtime-dom@3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.0.11.tgz#7a552df21907942721feb6961c418e222a699337" + integrity sha512-jm3FVQESY3y2hKZ2wlkcmFDDyqaPyU3p1IdAX92zTNeCH7I8zZ37PtlE1b9NlCtzV53WjB4TZAYh9yDCMIEumA== + dependencies: + "@vue/runtime-core" "3.0.11" + "@vue/shared" "3.0.11" + csstype "^2.6.8" + +"@vue/shared@3.0.11": + version "3.0.11" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.0.11.tgz#20d22dd0da7d358bb21c17f9bde8628152642c77" + integrity sha512-b+zB8A2so8eCE0JsxjL24J7vdGl8rzPQ09hZNhystm+KqSbKcAej1A+Hbva1rCMmTTqA+hFnUSDc5kouEo0JzA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +big-integer@^1.6.17: + version "1.6.48" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e" + integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w== + +big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79" + integrity sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk= + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +bluebird@~3.4.1: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + integrity sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM= + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +buffer-indexof-polyfill@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c" + integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A== + +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" + integrity sha1-skV5w77U1tOWru5tmorn9Ugqt7s= + +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98" + integrity sha1-XqtQsor+WAdNDVgpE4iCi15fvJg= + dependencies: + traverse ">=0.3.0 <0.4" + +colorette@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94" + integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + +consolidate@^0.16.0: + version "0.16.0" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.16.0.tgz#a11864768930f2f19431660a65906668f5fbdc16" + integrity sha512-Nhl1wzCslqXYTJVDyJCu3ODohy9OfBMB5uD2BiBTzd7w+QY0lBzafkR8y8755yMYHAaMD4NuzbAw03/xzfw+eQ== + dependencies: + bluebird "^3.7.2" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^2.6.8: + version "2.6.17" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.17.tgz#4cf30eb87e1d1a005d8b6510f95292413f6a1c0e" + integrity sha512-u1wmTI1jJGzCJzWndZo8mk4wnPTZd1eOIYTYvuEyOQGfmDl3TrabCCfKnOC86FZwW/9djqTl933UF/cS425i9A== + +duplexer2@~0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + integrity sha1-ixLauHjA1p4+eJEFFmKjL8a93ME= + dependencies: + readable-stream "^2.0.2" + +emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + +esbuild@^0.11.23: + version "0.11.23" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.11.23.tgz#c42534f632e165120671d64db67883634333b4b8" + integrity sha512-iaiZZ9vUF5wJV8ob1tl+5aJTrwDczlvGP0JoMmnpC2B0ppiMCu8n8gmy5ZTGl5bcG081XBVn+U+jP+mPFm5T5Q== + +estree-walker@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + +fsevents@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fstream@^1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +generic-names@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-2.0.1.tgz#f8a378ead2ccaa7a34f0317b05554832ae41b872" + integrity sha512-kPCHWa1m9wGG/OwQpeweTwM/PYiQLrUIxXbt/P4Nic3LbGjCP0YwrALHW1uNLKZ0LIMg+RF+XRlj2ekT9ZlZAQ== + dependencies: + loader-utils "^1.1.0" + +glob@^7.1.3: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +graceful-fs@^4.1.2, graceful-fs@^4.2.2: + version "4.2.6" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" + integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +hash-sum@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-2.0.0.tgz#81d01bb5de8ea4a214ad5d6ead1b523460b0b45a" + integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== + +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + integrity sha1-Bupvg2ead0njhs/h/oEq5dsiPe0= + +icss-utils@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@~2.0.0, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-core-module@^2.2.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.4.0.tgz#8e9fc8e15027b011418026e98f0e6f4d86305cc1" + integrity sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A== + dependencies: + has "^1.0.3" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + +json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + +listenercount@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" + integrity sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc= + +loader-utils@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.4.0.tgz#c579b5e34cb34b1a74edc6c1fb36bfa371d5a613" + integrity sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^1.0.1" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +magic-string@^0.25.7: + version "0.25.7" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.7.tgz#3f497d6fd34c669c6798dcb821f2ef31f5445051" + integrity sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA== + dependencies: + sourcemap-codec "^1.4.4" + +merge-source-map@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646" + integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw== + dependencies: + source-map "^0.6.1" + +minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + +"mkdirp@>=0.5 0": + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + +nanoid@^3.1.23: + version "3.1.23" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81" + integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + +path-parse@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + +postcss-modules-extract-imports@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== + +postcss-modules-local-by-default@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^6.0.2" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== + dependencies: + postcss-selector-parser "^6.0.4" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-modules@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules/-/postcss-modules-4.0.0.tgz#2bc7f276ab88f3f1b0fadf6cbd7772d43b5f3b9b" + integrity sha512-ghS/ovDzDqARm4Zj6L2ntadjyQMoyJmi0JkLlYtH2QFLrvNlxH5OAVRPWPeKilB0pY7SbuhO173KOWkPAxRJcw== + dependencies: + generic-names "^2.0.1" + icss-replace-symbols "^1.1.0" + lodash.camelcase "^4.3.0" + postcss-modules-extract-imports "^3.0.0" + postcss-modules-local-by-default "^4.0.0" + postcss-modules-scope "^3.0.0" + postcss-modules-values "^4.0.0" + string-hash "^1.1.1" + +postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4: + version "6.0.6" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== + +postcss@^8.1.10, postcss@^8.2.10: + version "8.2.15" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65" + integrity sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q== + dependencies: + colorette "^1.2.2" + nanoid "^3.1.23" + source-map "^0.6.1" + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +readable-stream@^2.0.2, readable-stream@~2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +resolve@^1.19.0: + version "1.20.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975" + integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + +rimraf@2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rollup@^2.38.5: + version "2.48.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.48.0.tgz#fceb01ed771f991f29f7bd2ff7838146e55acb74" + integrity sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A== + optionalDependencies: + fsevents "~2.3.1" + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +setimmediate@~1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sourcemap-codec@^1.4.4: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + +string-hash@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b" + integrity sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs= + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" + integrity sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk= + +typescript@^4.1.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.4.tgz#8610b59747de028fda898a8aef0e103f156d0961" + integrity sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg== + +unzipper@0.10.11: + version "0.10.11" + resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.11.tgz#0b4991446472cbdb92ee7403909f26c2419c782e" + integrity sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw== + dependencies: + big-integer "^1.6.17" + binary "~0.3.0" + bluebird "~3.4.1" + buffer-indexof-polyfill "~1.0.0" + duplexer2 "~0.1.4" + fstream "^1.0.12" + graceful-fs "^4.2.2" + listenercount "~1.0.1" + readable-stream "~2.3.6" + setimmediate "~1.0.4" + +util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + +vite@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/vite/-/vite-2.3.3.tgz#7e88a71abd03985c647789938d784cce0ee3b0fd" + integrity sha512-eO1iwRbn3/BfkNVMNJDeANAFCZ5NobYOFPu7IqfY7DcI7I9nFGjJIZid0EViTmLDGwwSUPmRAq3cRBbO3+DsMA== + dependencies: + esbuild "^0.11.23" + postcss "^8.2.10" + resolve "^1.19.0" + rollup "^2.38.5" + optionalDependencies: + fsevents "~2.3.1" + +"vue-i18n@link:../packages/vue-i18n": + version "0.0.0" + uid "" + +vue-tsc@^0.0.24: + version "0.0.24" + resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-0.0.24.tgz#0cd90db679f53ea1694254b8663fdb3d624a0872" + integrity sha512-Qx0V7jkWMtvddtaWa1SA8YKkBCRmjq9zZUB2UIMZiso6JSH538oHD2VumSzkoDnAfFbY3t0/j1mB2abpA0bGWA== + dependencies: + unzipper "0.10.11" + +vue@^3.0.11: + version "3.0.11" + resolved "https://registry.yarnpkg.com/vue/-/vue-3.0.11.tgz#c82f9594cbf4dcc869241d4c8dd3e08d9a8f4b5f" + integrity sha512-3/eUi4InQz8MPzruHYSTQPxtM3LdZ1/S/BvaU021zBnZi0laRUyH6pfuE4wtUeLvI8wmUNwj5wrZFvbHUXL9dw== + dependencies: + "@vue/compiler-dom" "3.0.11" + "@vue/runtime-dom" "3.0.11" + "@vue/shared" "3.0.11" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== From 1398bee8bca2fefe4ae3f5f8708f09671aed3710 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Sun, 23 May 2021 03:50:18 +0900 Subject: [PATCH 19/24] update processor for api-docs-gen --- scripts/api/processor.js | 121 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/scripts/api/processor.js b/scripts/api/processor.js index 3c285802d..8a8491e90 100644 --- a/scripts/api/processor.js +++ b/scripts/api/processor.js @@ -5,6 +5,14 @@ const { createContentBuilder } = require('api-docs-gen') +function escapeTitle(text) { + return text + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>') +} + function process(model, pkg, style, resolver, customTags) { // console.log('custom process', model, pkg, style, customTags) @@ -137,6 +145,7 @@ function process(model, pkg, style, resolver, customTags) { function buildFunction(model, builder) { model.summary && buildSummary(model, builder) model.signature && buildSignature(model, builder) + model.typeParameters && buildTypeParameters(model, builder) model.deprecated && buildDeprecated(model, builder) model.remarks && buildDetails(model, builder) model.tips && buildTips(model, builder) @@ -156,6 +165,7 @@ function buildEnum(model, builder) { function buildInterface(model, builder) { model.summary && buildSummary(model, builder) model.signature && buildSignature(model, builder) + model.typeParameters && buildTypeParameters(model, builder) model.deprecated && buildDeprecated(model, builder) model.remarks && buildDetails(model, builder) model.tips && buildTips(model, builder) @@ -172,6 +182,14 @@ function buildInterface(model, builder) { } } + if (model.functions) { + for (const m of model.functions) { + builder.pushline(`### ${m.name}`) + builder.newline() + buildMethodSignature(m, builder) + } + } + if (model.methods) { for (const m of model.methods) { builder.pushline(`### ${m.name}`) @@ -184,6 +202,7 @@ function buildInterface(model, builder) { function buildPropertySignature(model, builder) { model.summary && buildSummary(model, builder) model.signature && buildSignature(model, builder) + model.typeParameters && buildTypeParameters(model, builder) model.deprecated && buildDeprecated(model, builder) model.remarks && buildDetails(model, builder) model.tips && buildTips(model, builder) @@ -197,6 +216,7 @@ function buildPropertySignature(model, builder) { function buildMethodSignature(model, builder) { model.summary && buildSummary(model, builder) model.signature && buildSignature(model, builder) + model.typeParameters && buildTypeParameters(model, builder) model.deprecated && buildDeprecated(model, builder) model.remarks && buildDetails(model, builder) model.seeAlso && buildSeeAlso(model, builder) @@ -216,6 +236,7 @@ function buildClass(model, builder) { function buildTypeAlias(model, builder) { model.summary && buildSummary(model, builder) model.signature && buildSignature(model, builder) + model.typeParameters && buildTypeParameters(model, builder) model.deprecated && buildDeprecated(model, builder) model.remarks && buildDetails(model, builder) model.tips && buildTips(model, builder) @@ -250,6 +271,20 @@ function buildSignature(model, builder) { builder.newline() } +function buildTypeParameters(model, builder, level = 3) { + builder.pushline(`${'#'.repeat(level)} Type Parameters`) + builder.newline() + builder.pushline(`| Parameter | Description |`) + builder.pushline(`| --- | --- |`) + for (const p of model.typeParameters) { + builder.pushline( + `| ${p.name} | ${ p.description } |` + ) + } + builder.newline() +} + + function buildDeprecated(model, builder) { builder.pushline(`:::danger DEPRECATED`) builder.pushline(model.deprecated) @@ -394,6 +429,17 @@ function parseFunction(style, model, pkg, resolver, item, customTags) { // signature genModel.signature = getSignature(item) + // type parameters + genModel.typeParameters = getTypeParameters( + docs, + style, + model, + pkg, + resolver, + item, + customTags + ) + // deprecated genModel.deprecated = getDeprecated( docs, @@ -629,6 +675,11 @@ function getNameSignature(item, type) { return `${ type === 'constrcutor' ? 'constructor' : item.displayName }(${item.parameters.map(p => p.name).join(', ')})` + } else if (type === 'function') { + const display = item.excerptTokens + .map(token => token.text) + .join('') + return escapeTitle(display.slice(display.indexOf('('))) } else { return item.displayName } @@ -670,6 +721,17 @@ function parseContentForClassinizable( // signature genModel.signature = getSignature(item) + // type parameters + genModel.typeParameters = getTypeParameters( + docs, + style, + model, + pkg, + resolver, + item, + customTags + ) + // deprecated genModel.deprecated = getDeprecated( docs, @@ -742,7 +804,7 @@ function parseContentForClassinizable( ) // parameters - if (type === 'constrcutor' || type === 'method') { + if (type === 'constrcutor' || type === 'method' || type === 'function') { genModel.parameters = getParameters( docs, style, @@ -755,7 +817,7 @@ function parseContentForClassinizable( } // returns - if (type === 'method') { + if (type === 'method' || type === 'function') { genModel.returns = getReturns( docs, style, @@ -768,7 +830,7 @@ function parseContentForClassinizable( } // throws - if (type === 'constructor' || type === 'method') { + if (type === 'constructor' || type === 'method' || type === 'function') { genModel.throws = getThrows( docs, style, @@ -805,6 +867,24 @@ function parseInterface(style, model, pkg, resolver, item, customTags) { customTags ) + const functions = item.members.filter(m => m.kind === 'CallSignature') + if (functions.length > 0) { + genModel.functions = [] + for (const func of functions) { + genModel.functions.push( + parseContentForClassinizable( + style, + model, + pkg, + resolver, + func, + 'function', + customTags + ) + ) + } + } + const methods = item.members.filter(m => m.kind === 'MethodSignature') if (methods.length > 0) { genModel.methods = [] @@ -877,6 +957,17 @@ function parseTypeAlias(style, model, pkg, resolver, item, customTags) { // signature genModel.signature = getSignature(item) + // type parameters + genModel.typeParameters = getTypeParameters( + docs, + style, + model, + pkg, + resolver, + item, + customTags + ) + // deprecated genModel.deprecated = getDeprecated( docs, @@ -1079,6 +1170,30 @@ function getSignature(item) { : undefined } +function getTypeParameters(docs, style, model, pkg, resolver, item, customTags) { + if (docs.typeParams && docs.typeParams.count > 0) { + return docs.typeParams.blocks.map(b => { + return { + name: b.parameterName, + description: + b.content + ? getDocSectionContent( + model, + pkg, + b.content, + item, + style, + resolver, + customTags + ) + : '' + } + }) + } else { + return undefined + } +} + function getDeprecated(docs, style, model, pkg, resolver, item, customTags) { if (docs.deprecatedBlock) { return getDocSectionContent( From e2fc9a3690cba339128e1c06478c14d647a2f968 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Mon, 24 May 2021 01:35:40 +0900 Subject: [PATCH 20/24] tweaks --- examples/type-safe/src/components/HelloWorld.vue | 2 +- packages/core-base/src/context.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/type-safe/src/components/HelloWorld.vue b/examples/type-safe/src/components/HelloWorld.vue index 6d551e055..5e73786dd 100644 --- a/examples/type-safe/src/components/HelloWorld.vue +++ b/examples/type-safe/src/components/HelloWorld.vue @@ -15,7 +15,7 @@ type Schema = { export default defineComponent({ name: 'HelloWorld', - setup: () => { + setup() { /** * if you can specify resource schema to type parameter of `useI18n`, * you can make to be type-safe the i18n resources. diff --git a/packages/core-base/src/context.ts b/packages/core-base/src/context.ts index abf71aaa4..b65cd9a90 100644 --- a/packages/core-base/src/context.ts +++ b/packages/core-base/src/context.ts @@ -110,7 +110,7 @@ export interface CoreOptions< datetime?: unknown number?: unknown } = { - message: LocaleMessage, + message: LocaleMessage, datetime: DateTimeFormat, number: NumberFormat }, @@ -136,7 +136,7 @@ export interface CoreOptions< : Locales extends string ? Locales : Locale, - MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, + MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, Messages extends LocaleMessages< From dd161b3277097cd1fa28158c8fb01187d39d81d6 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Mon, 24 May 2021 02:22:13 +0900 Subject: [PATCH 21/24] update docs --- packages/vue-i18n/src/composer.ts | 48 +++++++++++------ packages/vue-i18n/src/i18n.ts | 87 +++++++++++++++++-------------- packages/vue-i18n/src/index.ts | 1 + packages/vue-i18n/src/legacy.ts | 82 +++++++++++++++++------------ packages/vue-i18n/src/runtime.ts | 15 +++++- scripts/api/processor.js | 5 +- 6 files changed, 147 insertions(+), 91 deletions(-) diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index fba14d6d3..ca791f8ef 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -480,7 +480,7 @@ export interface ComposerTranslation { * Locale message translation for plurals * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, return a pluralized translation message. * @@ -508,7 +508,7 @@ export interface ComposerTranslation { * Locale message translation for missing default message * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, if no translation was found, return a default message. * @@ -534,7 +534,7 @@ export interface ComposerTranslation { * Locale message translation for list interpolations * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, the locale messages should contain a `{0}`, `{1}`, … for each placeholder in the list. * @@ -562,7 +562,7 @@ export interface ComposerTranslation { * Locale message translation for list interpolations and plurals * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, the locale messages should contain a `{0}`, `{1}`, … for each placeholder in the list, and return a pluralized translation message. * @@ -587,7 +587,7 @@ export interface ComposerTranslation { * Locale message translation for list interpolations and missing default message * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, the locale messages should contain a `{0}`, `{1}`, … for each placeholder in the list, and if no translation was found, return a default message. * @@ -611,7 +611,7 @@ export interface ComposerTranslation { * Locale message translation for named interpolations * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, for each placeholder x, the locale messages should contain a `{x}` token. * @@ -639,7 +639,7 @@ export interface ComposerTranslation { * Locale message translation for named interpolations and plurals * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, for each placeholder x, the locale messages should contain a `{x}` token, and return a pluralized translation message. * @@ -664,7 +664,7 @@ export interface ComposerTranslation { * Locale message translation for named interpolations and plurals * * @remarks - * Overloaded `t`. About details, see the [t](composition#t-key) details. + * Overloaded `t`. About details, see the [call signature](composition#key-key-resourcekeys-number-string) details. * * In this overloaded `t`, for each placeholder x, the locale messages should contain a `{x}` token, and if no translation was found, return a default message. * @@ -725,7 +725,7 @@ export interface ComposerResolveLocaleMessageTranslation< * Resolve locale message translation for plurals * * @remarks - * Overloaded `rt`. About details, see the [rt](composition#rt-message) details. + * Overloaded `rt`. About details, see the [call signature](composition#message-messagefunction-message-message-string) details. * * In this overloaded `rt`, return a pluralized translation message. * @@ -752,7 +752,7 @@ export interface ComposerResolveLocaleMessageTranslation< * Resolve locale message translation for list interpolations * * @remarks - * Overloaded `rt`. About details, see the [rt](composition#rt-message) details. + * Overloaded `rt`. About details, see the [call signature](composition#message-messagefunction-message-message-string) details. * * In this overloaded `rt`, return a pluralized translation message. * @@ -779,7 +779,7 @@ export interface ComposerResolveLocaleMessageTranslation< * Resolve locale message translation for named interpolations * * @remarks - * Overloaded `rt`. About details, see the [rt](composition#rt-message) details. + * Overloaded `rt`. About details, see the [call signature](composition#message-messagefunction-message-message-string) details. * * In this overloaded `rt`, for each placeholder x, the locale messages should contain a `{x}` token. * @@ -837,7 +837,7 @@ export interface ComposerDateTimeFormatting< * Datetime formatting * * @remarks - * Overloaded `d`. About details, see the [d](composition#d-value) details. + * Overloaded `d`. About details, see the [call signature](composition#value-number-date-string-string) details. * * In this overloaded `d`, format in datetime format for a key registered in datetime formats. * @@ -861,7 +861,7 @@ export interface ComposerDateTimeFormatting< * Datetime formatting * * @remarks - * Overloaded `d`. About details, see the [d](composition#d-value) details. + * Overloaded `d`. About details, see the [call signature](composition#value-number-date-string-string) details. * * In this overloaded `d`, format in datetime format for a key registered in datetime formats at target locale * @@ -918,7 +918,7 @@ export interface ComposerNumberFormatting< * Number Formatting * * @remarks - * Overloaded `n`. About details, see the [n](composition#n-value) details. + * Overloaded `n`. About details, see the [call signature](composition#value-number-string) details. * * In this overloaded `n`, format in number format for a key registered in number formats. * @@ -941,7 +941,7 @@ export interface ComposerNumberFormatting< * Number Formatting * * @remarks - * Overloaded `n`. About details, see the [n](composition#n-value) details. + * Overloaded `n`. About details, see the [call signature](composition#value-number-string) details. * * In this overloaded `n`, format in number format for a key registered in number formats at target locale. * @@ -1241,6 +1241,8 @@ export interface Composer< * * @param locale - A target locale * + * @typeParam MessageSchema - The locale message schema, default `never` + * * @returns Locale messages */ getLocaleMessage< @@ -1263,6 +1265,8 @@ export interface Composer< * * @param locale - A target locale * @param message - A message + * + * @typeParam MessageSchema - The locale message schema, default `never` */ setLocaleMessage< MessageSchema extends LocaleMessage = never, @@ -1285,6 +1289,8 @@ export interface Composer< * * @param locale - A target locale * @param message - A message + * + * @typeParam MessageSchema - The locale message schema, default `never` */ mergeLocaleMessage< MessageSchema extends LocaleMessage = never, @@ -1307,6 +1313,8 @@ export interface Composer< * * @param locale - A target locale * + * @typeParam DateTimeSchema - The datetime format schema, default `never` + * * @returns Datetime format */ getDateTimeFormat< @@ -1329,6 +1337,8 @@ export interface Composer< * * @param locale - A target locale * @param format - A target datetime format + * + * @typeParam DateTimeSchema - The datetime format schema, default `never` */ setDateTimeFormat< DateTimeSchema extends Record = never, @@ -1351,6 +1361,8 @@ export interface Composer< * * @param locale - A target locale * @param format - A target datetime format + * + * @typeParam DateTimeSchema - The datetime format schema, default `never` */ mergeDateTimeFormat< DateTimeSchema extends Record = never, @@ -1373,6 +1385,8 @@ export interface Composer< * * @param locale - A target locale * + * @typeParam NumberSchema - The number format schema, default `never` + * * @returns Number format */ getNumberFormat< @@ -1395,6 +1409,8 @@ export interface Composer< * * @param locale - A target locale * @param format - A target number format + * + * @typeParam NumberSchema - The number format schema, default `never` */ setNumberFormat< NumberSchema extends Record = never, @@ -1417,6 +1433,8 @@ export interface Composer< * * @param locale - A target locale * @param format - A target number format + * + * @typeParam NumberSchema - The number format schema, default `never` */ mergeNumberFormat< NumberSchema extends Record = never, diff --git a/packages/vue-i18n/src/i18n.ts b/packages/vue-i18n/src/i18n.ts index 8990f7c55..23fb5515d 100644 --- a/packages/vue-i18n/src/i18n.ts +++ b/packages/vue-i18n/src/i18n.ts @@ -318,31 +318,15 @@ export function createI18n< options: Options ): I18n -export function createI18n< - Schema = LocaleMessage, - Locales = 'en-US', - Legacy extends boolean = true, - Options extends I18nOptions< - SchemaParams, - LocaleParams - > = I18nOptions, LocaleParams>, - Messages = Options['messages'] extends object ? Options['messages'] : {}, - DateTimeFormats = Options['datetimeFormats'] extends object - ? Options['datetimeFormats'] - : {}, - NumberFormats = Options['numberFormats'] extends object - ? Options['numberFormats'] - : {}, - OptionLocale = Options['locale'] extends string ? Options['locale'] : Locale ->( - options: Options -): I18n - /** * Vue I18n factory * * @param options - An options, see the {@link I18nOptions} * + * @typeParam Schema - The i18n resources (messages, datetimeFormats, numberFormats) schema, default {@link LocaleMessage} + * @typeParam Locales - The locales of i18n resource schema, default `en-US` + * @typeParam Legacy - Whether legacy mode is enabled or disabled, default `true` + * * @returns {@link I18n} instance * * @remarks @@ -412,6 +396,26 @@ export function createI18n< * * @VueI18nGeneral */ +export function createI18n< + Schema = LocaleMessage, + Locales = 'en-US', + Legacy extends boolean = true, + Options extends I18nOptions< + SchemaParams, + LocaleParams + > = I18nOptions, LocaleParams>, + Messages = Options['messages'] extends object ? Options['messages'] : {}, + DateTimeFormats = Options['datetimeFormats'] extends object + ? Options['datetimeFormats'] + : {}, + NumberFormats = Options['numberFormats'] extends object + ? Options['numberFormats'] + : {}, + OptionLocale = Options['locale'] extends string ? Options['locale'] : Locale +>( + options: Options +): I18n + // eslint-disable-next-line @typescript-eslint/no-explicit-any export function createI18n(options: any = {}): any { type _I18n = I18n & I18nInternal @@ -522,31 +526,14 @@ export function useI18n( NonNullable > -export function useI18n< - Schema = LocaleMessage, - Locales = 'en-US', - Options extends UseI18nOptions< - SchemaParams, - LocaleParams - > = UseI18nOptions< - SchemaParams, - LocaleParams - > ->( - options?: Options -): Composer< - VueMessageType, - NonNullable, - NonNullable, - NonNullable, - NonNullable -> - /** * Use Composition API for Vue I18n * * @param options - An options, see {@link UseI18nOptions} * + * @typeParam Schema - The i18n resources (messages, datetimeFormats, numberFormats) schema, default {@link LocaleMessage} + * @typeParam Locales - The locales of i18n resource schema, default `en-US` + * * @returns {@link Composer} instance * * @remarks @@ -592,6 +579,26 @@ export function useI18n< * * @VueI18nComposition */ +export function useI18n< + Schema = LocaleMessage, + Locales = 'en-US', + Options extends UseI18nOptions< + SchemaParams, + LocaleParams + > = UseI18nOptions< + SchemaParams, + LocaleParams + > +>( + options?: Options +): Composer< + VueMessageType, + NonNullable, + NonNullable, + NonNullable, + NonNullable +> + // eslint-disable-next-line @typescript-eslint/no-explicit-any export function useI18n< Options extends UseI18nOptions = UseI18nOptions, diff --git a/packages/vue-i18n/src/index.ts b/packages/vue-i18n/src/index.ts index d632e770f..0216d0349 100644 --- a/packages/vue-i18n/src/index.ts +++ b/packages/vue-i18n/src/index.ts @@ -55,6 +55,7 @@ export { VueI18nOptions, VueI18n, VueI18nTranslation, + VueI18nTranslationChoice, VueI18nDateTimeFormatting, VueI18nNumberFormatting, VueI18nResolveLocaleMessageTranslation, diff --git a/packages/vue-i18n/src/legacy.ts b/packages/vue-i18n/src/legacy.ts index 51cff4b0c..97ccae0de 100644 --- a/packages/vue-i18n/src/legacy.ts +++ b/packages/vue-i18n/src/legacy.ts @@ -428,7 +428,7 @@ export interface VueI18nTranslation { * Locale message translation. * * @remarks - * Overloaded `t`. About details, see the [t](legacy#t-key) details. + * Overloaded `t`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult) details. * * @param key - A target locale message key * @param locale - A locale, it will be used over than global scope or local scope. @@ -446,7 +446,7 @@ export interface VueI18nTranslation { * Locale message translation. * * @remarks - * Overloaded `t`. About details, see the [t](legacy#t-key) details. + * Overloaded `t`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult) details. * * @param key - A target locale message key * @param locale - A locale, it will be used over than global scope or local scope. @@ -468,7 +468,7 @@ export interface VueI18nTranslation { * Locale message translation. * * @remarks - * Overloaded `t`. About details, see the [t](legacy#t-key) details. + * Overloaded `t`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult) details. * * @param key - A target locale message key * @param locale - A locale, it will be used over than global scope or local scope. @@ -490,7 +490,7 @@ export interface VueI18nTranslation { * Locale message translation. * * @remarks - * Overloaded `t`. About details, see the [t](legacy#t-key) details. + * Overloaded `t`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult) details. * * @param key - A target locale message key * @param list - A values of list interpolation @@ -510,7 +510,7 @@ export interface VueI18nTranslation { * Locale message translation. * * @remarks - * Overloaded `t`. About details, see the [t](legacy#t-key) details. + * Overloaded `t`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult) details. * * @param key - A target locale message key * @param named - A values of named interpolation @@ -578,7 +578,7 @@ export interface VueI18nTranslationChoice { * Locale message pluralization * * @remarks - * Overloaded `tc`. About details, see the [tc](legacy#tc-key) details. + * Overloaded `tc`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult-2) details. * * @param key - A target locale message key * @param locale - A locale, it will be used over than global scope or local scope. @@ -596,7 +596,7 @@ export interface VueI18nTranslationChoice { * Locale message pluralization * * @remarks - * Overloaded `tc`. About details, see the [tc](legacy#tc-key) details. + * Overloaded `tc`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult-2) details. * * @param key - A target locale message key * @param list - A values of list interpolation @@ -614,7 +614,7 @@ export interface VueI18nTranslationChoice { * Locale message pluralization * * @remarks - * Overloaded `tc`. About details, see the [tc](legacy#tc-key) details. + * Overloaded `tc`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult-2) details. * * @param key - A target locale message key * @param named - A values of named interpolation @@ -632,7 +632,7 @@ export interface VueI18nTranslationChoice { * Locale message pluralization * * @remarks - * Overloaded `tc`. About details, see the [tc](legacy#tc-key) details. + * Overloaded `tc`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult-2) details. * * @param key - A target locale message key * @param choice - Which plural string to get. 1 returns the first one. @@ -650,7 +650,7 @@ export interface VueI18nTranslationChoice { * Locale message pluralization * * @remarks - * Overloaded `tc`. About details, see the [tc](legacy#tc-key) details. + * Overloaded `tc`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult-2) details. * * @param key - A target locale message key * @param choice - Which plural string to get. 1 returns the first one. @@ -670,7 +670,7 @@ export interface VueI18nTranslationChoice { * Locale message pluralization * * @remarks - * Overloaded `tc`. About details, see the [tc](legacy#tc-key) details. + * Overloaded `tc`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult-2) details. * * @param key - A target locale message key * @param choice - Which plural string to get. 1 returns the first one. @@ -690,7 +690,7 @@ export interface VueI18nTranslationChoice { * Locale message pluralization * * @remarks - * Overloaded `tc`. About details, see the [tc](legacy#tc-key) details. + * Overloaded `tc`. About details, see the [call signature](legacy#key-key-resourcekeys-translateresult-2) details. * * @param key - A target locale message key * @param choice - Which plural string to get. 1 returns the first one. @@ -741,7 +741,7 @@ export interface VueI18nDateTimeFormatting< * Datetime formatting * * @remarks - * Overloaded `d`. About details, see the [d](legacy#d-value) details. + * Overloaded `d`. About details, see the [call signature](legacy#value-number-date-datetimeformatresult) details. * * @param value - A value, timestamp number or `Date` instance * @param key - A key of datetime formats @@ -760,7 +760,7 @@ export interface VueI18nDateTimeFormatting< * Datetime formatting * * @remarks - * Overloaded `d`. About details, see the [d](legacy#d-value) details. + * Overloaded `d`. About details, see the [call signature](legacy#value-number-date-datetimeformatresult) details. * * @param value - A value, timestamp number or `Date` instance * @param key - A key of datetime formats @@ -781,7 +781,7 @@ export interface VueI18nDateTimeFormatting< * Datetime formatting * * @remarks - * Overloaded `d`. About details, see the [d](legacy#d-value) details. + * Overloaded `d`. About details, see the [call signature](legacy#value-number-date-datetimeformatresult) details. * * @param value - A value, timestamp number or `Date` instance * @param args - An argument values @@ -821,16 +821,16 @@ export interface VueI18nNumberFormatting< */ (value: number): NumberFormatResult /** - * Number formatting - * - * @remarks - * Overloaded `n`. About details, see the [n](legacy#n-value) details. - * - * @param value - A number value - @param key - A key of number formats - * - * @returns Formatted value - */ + * Number formatting + * + * @remarks + * Overloaded `n`. About details, see the [call signature](legacy#value-number-numberformatresult) details. + * + * @param value - A number value + * @param key - A key of number formats + * + * @returns Formatted value + */ < Key extends string = string, ResourceKeys extends PickupFormatKeys = PickupFormatKeys @@ -842,7 +842,7 @@ export interface VueI18nNumberFormatting< * Number formatting * * @remarks - * Overloaded `n`. About details, see the [n](legacy#n-value) details. + * Overloaded `n`. About details, see the [call signature](legacy#value-number-numberformatresult) details. * * @param value - A number value * @param key - A key of number formats @@ -862,7 +862,7 @@ export interface VueI18nNumberFormatting< * Number formatting * * @remarks - * Overloaded `n`. About details, see the [n](legacy#n-value) details. + * Overloaded `n`. About details, see the [call signature](legacy#value-number-numberformatresult) details. * * @param value - A number value * @param args - An argument values @@ -980,26 +980,26 @@ export interface VueI18n< * * @VueI18nSee [Fallbacking](../guide/essentials/fallback) */ - silentTranslationWarn: Composer['missingWarn'] + silentTranslationWarn: Composition['missingWarn'] /** * @remarks * Whether suppress fallback warnings when localization fails. */ - silentFallbackWarn: Composer['fallbackWarn'] + silentFallbackWarn: Composition['fallbackWarn'] /** * @remarks * Whether suppress warnings when falling back to either `fallbackLocale` or root. * * @VueI18nSee [Fallbacking](../guide/essentials/fallback) */ - formatFallbackMessages: Composer['fallbackFormat'] + formatFallbackMessages: Composition['fallbackFormat'] /** * @remarks * Whether synchronize the root level locale to the component localization locale. * * @VueI18nSee [Local Scope](../guide/essentials/scope#local-scope-2) */ - sync: Composer['inheritLocale'] + sync: Composition['inheritLocale'] /** * @remarks * Whether to allow the use locale messages of HTML formatting. @@ -1153,6 +1153,8 @@ export interface VueI18n< * * @param locale - A target locale * + * @typeParam MessageSchema - The locale message schema, default `never` + * * @returns Locale messages */ getLocaleMessage< @@ -1175,6 +1177,8 @@ export interface VueI18n< * * @param locale - A target locale * @param message - A message + * + * @typeParam MessageSchema - The locale message schema, default `never` */ setLocaleMessage< MessageSchema extends LocaleMessage = never, @@ -1197,6 +1201,8 @@ export interface VueI18n< * * @param locale - A target locale * @param message - A message + * + * @typeParam MessageSchema - The locale message schema, default `never` */ mergeLocaleMessage< MessageSchema extends LocaleMessage = never, @@ -1215,7 +1221,7 @@ export interface VueI18n< * Datetime formatting * * @remarks - * About details functions, See the {@link ueI18nDateTimeFormatting} + * About details functions, See the {@link VueI18nDateTimeFormatting} */ d: VueI18nDateTimeFormatting /** @@ -1226,6 +1232,8 @@ export interface VueI18n< * * @param locale - A target locale * + * @typeParam DateTimeSchema - The datetime format schema, default `never` + * * @returns Datetime format */ getDateTimeFormat< @@ -1248,6 +1256,8 @@ export interface VueI18n< * * @param locale - A target locale * @param format - A target datetime format + * + * @typeParam DateTimeSchema - The datetime format schema, default `never` */ setDateTimeFormat< DateTimeSchema extends Record = never, @@ -1270,6 +1280,8 @@ export interface VueI18n< * * @param locale - A target locale * @param format - A target datetime format + * + * @typeParam DateTimeSchema - The datetime format schema, default `never` */ mergeDateTimeFormat< DateTimeSchema extends Record = never, @@ -1299,6 +1311,8 @@ export interface VueI18n< * * @param locale - A target locale * + * @typeParam NumberSchema - The number format schema, default `never` + * * @returns Number format */ getNumberFormat< @@ -1321,6 +1335,8 @@ export interface VueI18n< * * @param locale - A target locale * @param format - A target number format + * + * @typeParam NumberSchema - The number format schema, default `never` */ setNumberFormat< NumberSchema extends Record = never, @@ -1343,6 +1359,8 @@ export interface VueI18n< * * @param locale - A target locale * @param format - A target number format + * + * @typeParam NumberSchema - The number format schema, default `never` */ mergeNumberFormat< NumberSchema extends Record = never, diff --git a/packages/vue-i18n/src/runtime.ts b/packages/vue-i18n/src/runtime.ts index 0cfb4f9f5..f905b33b6 100644 --- a/packages/vue-i18n/src/runtime.ts +++ b/packages/vue-i18n/src/runtime.ts @@ -32,7 +32,12 @@ export { MissingHandler, ComposerOptions, Composer, - CustomBlocks + CustomBlock, + CustomBlocks, + ComposerTranslation, + ComposerDateTimeFormatting, + ComposerNumberFormatting, + ComposerResolveLocaleMessageTranslation } from './composer' export { TranslateResult, @@ -44,7 +49,13 @@ export { NumberFormatResult, Formatter, VueI18nOptions, - VueI18n + VueI18n, + VueI18nTranslation, + VueI18nTranslationChoice, + VueI18nDateTimeFormatting, + VueI18nNumberFormatting, + VueI18nResolveLocaleMessageTranslation, + ComponentInstanceCreatedListener } from './legacy' export { createI18n, diff --git a/scripts/api/processor.js b/scripts/api/processor.js index 8a8491e90..00fbfca48 100644 --- a/scripts/api/processor.js +++ b/scripts/api/processor.js @@ -9,6 +9,7 @@ function escapeTitle(text) { return text .replace(/&/g, '&') .replace(/"/g, '"') + .replace(/\n/g, '') .replace(//g, '>') } @@ -202,7 +203,7 @@ function buildInterface(model, builder) { function buildPropertySignature(model, builder) { model.summary && buildSummary(model, builder) model.signature && buildSignature(model, builder) - model.typeParameters && buildTypeParameters(model, builder) + model.typeParameters && buildTypeParameters(model, builder, 4) model.deprecated && buildDeprecated(model, builder) model.remarks && buildDetails(model, builder) model.tips && buildTips(model, builder) @@ -216,7 +217,7 @@ function buildPropertySignature(model, builder) { function buildMethodSignature(model, builder) { model.summary && buildSummary(model, builder) model.signature && buildSignature(model, builder) - model.typeParameters && buildTypeParameters(model, builder) + model.typeParameters && buildTypeParameters(model, builder, 4) model.deprecated && buildDeprecated(model, builder) model.remarks && buildDetails(model, builder) model.seeAlso && buildSeeAlso(model, builder) From d5462924cc1468a50a8424aa37ef01643f949545 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 25 May 2021 17:40:54 +0900 Subject: [PATCH 22/24] tweak --- package.json | 2 +- packages/core-base/src/context.ts | 12 ++++++------ packages/vue-i18n/src/composer.ts | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index b934297a5..f1e85a22d 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "build:size-core": "rollup -c packages/size-check-core/rollup.config.js", "build:size-vue-i18n": "rollup -c packages/size-check-vue-i18n/rollup.config.js", "build:sourcemap": "yarn build --sourcemap", - "build:type": "yarn build --types && tail -n +20 ./packages/vue-i18n/src/vue.d.ts >> ./packages/vue-i18n/dist/vue-i18n.d.ts", + "build:type": "yarn build --types && tail -n +22 ./packages/vue-i18n/src/vue.d.ts >> ./packages/vue-i18n/dist/vue-i18n.d.ts", "clean": "npm-run-all --parallel clean:*", "clean:cache": "yarn clean:cache:jest", "clean:cache:jest": "jest --clearCache", diff --git a/packages/core-base/src/context.ts b/packages/core-base/src/context.ts index b65cd9a90..6d3c6e4d6 100644 --- a/packages/core-base/src/context.ts +++ b/packages/core-base/src/context.ts @@ -139,20 +139,20 @@ export interface CoreOptions< MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, - Messages extends LocaleMessages< + _Messages extends LocaleMessages< MessageSchema, MessagesLocales, Message > = LocaleMessages, - DateTimeFormats extends DateTimeFormatsType = DateTimeFormatsType, - NumberFormats extends NumberFormatsType = NumberFormatsType, + _DateTimeFormats extends DateTimeFormatsType = DateTimeFormatsType, + _NumberFormats extends NumberFormatsType = NumberFormatsType, > { version?: string locale?: Locale fallbackLocale?: FallbackLocale - messages?: { [K in keyof Messages]: MessageSchema } - datetimeFormats?: { [K in keyof DateTimeFormats]: DateTimeSchema } - numberFormats?: { [K in keyof NumberFormats]: NumberSchema } + messages?: { [K in keyof _Messages]: MessageSchema } + datetimeFormats?: { [K in keyof _DateTimeFormats]: DateTimeSchema } + numberFormats?: { [K in keyof _NumberFormats]: NumberSchema } modifiers?: LinkedModifiers pluralRules?: PluralizationRules missing?: CoreMissingHandler diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index ca791f8ef..d8da0d801 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -171,16 +171,16 @@ export interface ComposerOptions< MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, - Messages extends LocaleMessages< + _Messages extends LocaleMessages< MessageSchema, MessagesLocales, Message > = LocaleMessages, - DateTimeFormats extends DateTimeFormatsType< + _DateTimeFormats extends DateTimeFormatsType< DateTimeSchema, DateTimeFormatsLocales > = DateTimeFormatsType, - NumberFormats extends NumberFormatsType< + _NumberFormats extends NumberFormatsType< NumberSchema, NumberFormatsLocales > = NumberFormatsType @@ -226,7 +226,7 @@ export interface ComposerOptions< * * @defaultValue `{}` */ - messages?: { [K in keyof Messages]: MessageSchema } + messages?: { [K in keyof _Messages]: MessageSchema } /** * @remarks * Allow use flat json messages or not @@ -242,7 +242,7 @@ export interface ComposerOptions< * * @defaultValue `{}` */ - datetimeFormats?: { [K in keyof DateTimeFormats]: DateTimeSchema } + datetimeFormats?: { [K in keyof _DateTimeFormats]: DateTimeSchema } /** * @remarks * The number formats of localization. @@ -251,7 +251,7 @@ export interface ComposerOptions< * * @defaultValue `{}` */ - numberFormats?: { [K in keyof NumberFormats]: NumberSchema } + numberFormats?: { [K in keyof _NumberFormats]: NumberSchema } /** * @remarks * Custom Modifiers for linked messages. From f80e7e59c019530e315b542667da5928942f98f4 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 25 May 2021 18:55:19 +0900 Subject: [PATCH 23/24] more tweaks --- packages/vue-i18n/src/composer.ts | 8 +++-- packages/vue-i18n/src/i18n.ts | 20 +++++++---- packages/vue-i18n/src/index.ts | 1 + packages/vue-i18n/src/vue.d.ts | 56 +++++++++++++++---------------- scripts/api/processor.js | 42 ++++++++++++----------- 5 files changed, 71 insertions(+), 56 deletions(-) diff --git a/packages/vue-i18n/src/composer.ts b/packages/vue-i18n/src/composer.ts index d8da0d801..33ff56de3 100644 --- a/packages/vue-i18n/src/composer.ts +++ b/packages/vue-i18n/src/composer.ts @@ -106,6 +106,10 @@ export const DevToolsMetaSymbol = makeSymbol('__intlifyMeta') /** @VueI18nComposition */ export type VueMessageType = string | VNode + +// TODO: custom locale message as global schema +export interface CustomLocaleMessage extends LocaleMessage {} // eslint-disable-line @typescript-eslint/no-empty-interface + /** @VueI18nComposition */ export type MissingHandler = ( locale: Locale, @@ -168,7 +172,7 @@ export interface ComposerOptions< : Locales extends string ? Locales : Locale, - MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, + MessageSchema = Schema extends { message: infer M } ? M : LocaleMessage, DateTimeSchema = Schema extends { datetime: infer D } ? D : DateTimeFormat, NumberSchema = Schema extends { number: infer N } ? N : NumberFormat, _Messages extends LocaleMessages< @@ -1600,7 +1604,7 @@ export function createComposer< >(options: Options): Composer export function createComposer< - Schema = LocaleMessage, + Schema = LocaleMessage, Locales = 'en-US', Message = VueMessageType, Options extends ComposerOptions< diff --git a/packages/vue-i18n/src/i18n.ts b/packages/vue-i18n/src/i18n.ts index 23fb5515d..febe9b7f4 100644 --- a/packages/vue-i18n/src/i18n.ts +++ b/packages/vue-i18n/src/i18n.ts @@ -44,6 +44,7 @@ import type { } from '@intlify/vue-devtools' import type { VueMessageType, + CustomLocaleMessage, Composer, ComposerOptions, ComposerInternalOptions @@ -313,7 +314,8 @@ export function createI18n< NumberFormats = Options['numberFormats'] extends object ? Options['numberFormats'] : {}, - OptionLocale = Options['locale'] extends string ? Options['locale'] : Locale + OptionLocale = Options['locale'] extends string ? Options['locale'] : Locale, + F = keyof CustomLocaleMessage // eslint-disable-line @typescript-eslint/no-unused-vars >( options: Options ): I18n @@ -411,7 +413,8 @@ export function createI18n< NumberFormats = Options['numberFormats'] extends object ? Options['numberFormats'] : {}, - OptionLocale = Options['locale'] extends string ? Options['locale'] : Locale + OptionLocale = Options['locale'] extends string ? Options['locale'] : Locale, + F = keyof CustomLocaleMessage // eslint-disable-line @typescript-eslint/no-unused-vars >( options: Options ): I18n @@ -516,7 +519,10 @@ export function createI18n(options: any = {}): any { return i18n } -export function useI18n( +export function useI18n< + Options extends UseI18nOptions = UseI18nOptions, + F = keyof CustomLocaleMessage // eslint-disable-line @typescript-eslint/no-unused-vars +>( options?: Options ): Composer< VueMessageType, @@ -588,7 +594,8 @@ export function useI18n< > = UseI18nOptions< SchemaParams, LocaleParams - > + >, + F = keyof CustomLocaleMessage // eslint-disable-line @typescript-eslint/no-unused-vars >( options?: Options ): Composer< @@ -599,13 +606,14 @@ export function useI18n< NonNullable > -// eslint-disable-next-line @typescript-eslint/no-explicit-any +// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types export function useI18n< Options extends UseI18nOptions = UseI18nOptions, Messages = NonNullable, DateTimeFormats = NonNullable, NumberFormats = NonNullable, - OptionLocale = NonNullable + OptionLocale = NonNullable, + F = keyof CustomLocaleMessage // eslint-disable-line @typescript-eslint/no-unused-vars >(options: Options = {} as Options) { const instance = getCurrentInstance() if (instance == null) { diff --git a/packages/vue-i18n/src/index.ts b/packages/vue-i18n/src/index.ts index 0216d0349..f42e772c8 100644 --- a/packages/vue-i18n/src/index.ts +++ b/packages/vue-i18n/src/index.ts @@ -33,6 +33,7 @@ export { } from '@intlify/core-base' export { VueMessageType, + CustomLocaleMessage, MissingHandler, ComposerOptions, Composer, diff --git a/packages/vue-i18n/src/vue.d.ts b/packages/vue-i18n/src/vue.d.ts index 11bb5c149..8e9c1d1d4 100644 --- a/packages/vue-i18n/src/vue.d.ts +++ b/packages/vue-i18n/src/vue.d.ts @@ -82,7 +82,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys + key: Key | ResourceKeys | Path ): TranslateResult /** * Locale message translation @@ -100,7 +100,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys + key: Key | ResourceKeys | Path ): TranslateResult /** * Locale message translation @@ -119,7 +119,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, locale: Locale, list: unknown[] ): TranslateResult @@ -140,7 +140,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, locale: Locale, named: object ): TranslateResult @@ -160,7 +160,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, list: unknown[] ): TranslateResult /** @@ -179,7 +179,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, named: Record ): TranslateResult /** @@ -197,7 +197,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys + key: Key | ResourceKeys | Path ): string /** * Locale message translation @@ -215,7 +215,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, plural: number ): string /** @@ -235,7 +235,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, plural: number, options: TranslateOptions ): string @@ -255,7 +255,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, defaultMsg: string ): string /** @@ -275,7 +275,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Path, + key: Key | ResourceKeys | Path, defaultMsg: string, options: TranslateOptions ): string @@ -295,7 +295,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, list: unknown[] ): string /** @@ -315,7 +315,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, list: unknown[], plural: number ): string @@ -336,7 +336,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, list: unknown[], defaultMsg: string ): string @@ -357,7 +357,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, list: unknown[], options: TranslateOptions ): string @@ -377,7 +377,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, named: NamedValue ): string /** @@ -397,7 +397,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, named: NamedValue, plural: number ): string @@ -418,7 +418,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, named: NamedValue, defaultMsg: string ): string @@ -439,7 +439,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, named: NamedValue, options: TranslateOptions ): string @@ -529,7 +529,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys + key: Key | ResourceKeys | Path ): TranslateResult /** * Locale message pluralization @@ -548,7 +548,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, locale: Locale ): TranslateResult /** @@ -568,7 +568,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, list: unknown[] ): TranslateResult /** @@ -589,7 +589,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, named: Record ): TranslateResult /** @@ -610,7 +610,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, choice: number ): TranslateResult /** @@ -632,7 +632,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, choice: number, locale: Locale ): TranslateResult @@ -655,7 +655,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, choice: number, list: unknown[] ): TranslateResult @@ -678,7 +678,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, choice: number, named: Record ): TranslateResult @@ -699,7 +699,7 @@ declare module '@vue/runtime-core' { Messages extends object = {}, ResourceKeys extends PickupKeys = PickupKeys >( - key: Key | ResourceKeys, + key: Key | ResourceKeys | Path, locale?: Locale ): boolean /** diff --git a/scripts/api/processor.js b/scripts/api/processor.js index 00fbfca48..25ab05cb1 100644 --- a/scripts/api/processor.js +++ b/scripts/api/processor.js @@ -278,14 +278,11 @@ function buildTypeParameters(model, builder, level = 3) { builder.pushline(`| Parameter | Description |`) builder.pushline(`| --- | --- |`) for (const p of model.typeParameters) { - builder.pushline( - `| ${p.name} | ${ p.description } |` - ) + builder.pushline(`| ${p.name} | ${p.description} |`) } builder.newline() } - function buildDeprecated(model, builder) { builder.pushline(`:::danger DEPRECATED`) builder.pushline(model.deprecated) @@ -677,9 +674,7 @@ function getNameSignature(item, type) { type === 'constrcutor' ? 'constructor' : item.displayName }(${item.parameters.map(p => p.name).join(', ')})` } else if (type === 'function') { - const display = item.excerptTokens - .map(token => token.text) - .join('') + const display = item.excerptTokens.map(token => token.text).join('') return escapeTitle(display.slice(display.indexOf('('))) } else { return item.displayName @@ -1171,23 +1166,30 @@ function getSignature(item) { : undefined } -function getTypeParameters(docs, style, model, pkg, resolver, item, customTags) { +function getTypeParameters( + docs, + style, + model, + pkg, + resolver, + item, + customTags +) { if (docs.typeParams && docs.typeParams.count > 0) { return docs.typeParams.blocks.map(b => { return { name: b.parameterName, - description: - b.content - ? getDocSectionContent( - model, - pkg, - b.content, - item, - style, - resolver, - customTags - ) - : '' + description: b.content + ? getDocSectionContent( + model, + pkg, + b.content, + item, + style, + resolver, + customTags + ) + : '' } }) } else { From bc3e5d1646e664611eda2256c6d2ec8aff52e8d7 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 25 May 2021 18:56:00 +0900 Subject: [PATCH 24/24] update type-safe example --- examples/type-safe/package.json | 2 +- examples/type-safe/src/App.vue | 9 ++-- .../type-safe/src/components/GlobalScope.vue | 23 ++++++++ .../type-safe/src/components/HelloWorld.vue | 54 ------------------- .../type-safe/src/components/LocalScope.vue | 48 +++++++++++++++++ examples/type-safe/src/components/en-US.json | 5 ++ examples/type-safe/src/locales/en-US.json | 3 ++ examples/type-safe/src/locales/en.json | 12 ----- examples/type-safe/src/locales/schema.ts | 19 +++++-- examples/type-safe/src/main.ts | 32 ++++++++--- examples/type-safe/yarn.lock | 25 +++++---- 11 files changed, 143 insertions(+), 89 deletions(-) create mode 100644 examples/type-safe/src/components/GlobalScope.vue delete mode 100644 examples/type-safe/src/components/HelloWorld.vue create mode 100644 examples/type-safe/src/components/LocalScope.vue create mode 100644 examples/type-safe/src/components/en-US.json create mode 100644 examples/type-safe/src/locales/en-US.json delete mode 100644 examples/type-safe/src/locales/en.json diff --git a/examples/type-safe/package.json b/examples/type-safe/package.json index 083bb1f78..1c3ffdc99 100644 --- a/examples/type-safe/package.json +++ b/examples/type-safe/package.json @@ -18,4 +18,4 @@ "vite": "^2.3.3", "vue-tsc": "^0.0.24" } -} \ No newline at end of file +} diff --git a/examples/type-safe/src/App.vue b/examples/type-safe/src/App.vue index c8098c159..2434165c8 100644 --- a/examples/type-safe/src/App.vue +++ b/examples/type-safe/src/App.vue @@ -1,15 +1,18 @@ diff --git a/examples/type-safe/src/components/GlobalScope.vue b/examples/type-safe/src/components/GlobalScope.vue new file mode 100644 index 000000000..46f0cb7a9 --- /dev/null +++ b/examples/type-safe/src/components/GlobalScope.vue @@ -0,0 +1,23 @@ + + + diff --git a/examples/type-safe/src/components/HelloWorld.vue b/examples/type-safe/src/components/HelloWorld.vue deleted file mode 100644 index 5e73786dd..000000000 --- a/examples/type-safe/src/components/HelloWorld.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - - - diff --git a/examples/type-safe/src/components/LocalScope.vue b/examples/type-safe/src/components/LocalScope.vue new file mode 100644 index 000000000..ad8d223a7 --- /dev/null +++ b/examples/type-safe/src/components/LocalScope.vue @@ -0,0 +1,48 @@ + + + diff --git a/examples/type-safe/src/components/en-US.json b/examples/type-safe/src/components/en-US.json new file mode 100644 index 000000000..5d72ea763 --- /dev/null +++ b/examples/type-safe/src/components/en-US.json @@ -0,0 +1,5 @@ +{ + "messages": { + "hello": "Hello, {name}!" + } +} diff --git a/examples/type-safe/src/locales/en-US.json b/examples/type-safe/src/locales/en-US.json new file mode 100644 index 000000000..6ce38d94d --- /dev/null +++ b/examples/type-safe/src/locales/en-US.json @@ -0,0 +1,3 @@ +{ + "hello": "hello world!" +} diff --git a/examples/type-safe/src/locales/en.json b/examples/type-safe/src/locales/en.json deleted file mode 100644 index 57f07c054..000000000 --- a/examples/type-safe/src/locales/en.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "hello": "Hello!", - "nest": { - "foo": { - "bar": { - "buz": { - "msg": "nest message!" - } - } - } - } -} \ No newline at end of file diff --git a/examples/type-safe/src/locales/schema.ts b/examples/type-safe/src/locales/schema.ts index 9463fd464..d6200f382 100644 --- a/examples/type-safe/src/locales/schema.ts +++ b/examples/type-safe/src/locales/schema.ts @@ -1,4 +1,17 @@ -import en from './en.json' +/** + * define the resource schema + */ -// define the resource schema from default language resource -export type ResourceSchema = typeof en +import enUS from './en-US.json' + +// define message schema as master mesage schema +export type MessageSchema = typeof enUS + +// define number format schema +export type NumberSchema = { + currency: { + style: 'currency' + currencyDisplay: 'symbol' + currency: string + } +} diff --git a/examples/type-safe/src/main.ts b/examples/type-safe/src/main.ts index f5e704b6a..66708efaf 100644 --- a/examples/type-safe/src/main.ts +++ b/examples/type-safe/src/main.ts @@ -1,19 +1,39 @@ import { createApp } from 'vue' import App from './App.vue' + import { createI18n } from 'vue-i18n' -import en from './locales/en.json' -import type { ResourceSchema } from './locales/schema' +import enUS from './locales/en-US.json' + +import type { MessageSchema, NumberSchema } from './locales/schema' +// type MessageSchema = typeof enUS /** * if you can specify resource schema to type parameter of `createI18n`, * you can make to be type-safe the i18n resources. */ -const i18n = createI18n<[ResourceSchema], 'en' | 'ja', false>({ - locale: 'en', + +// const i18n = createI18n<[MessageSchema], 'en-US'>({ +const i18n = createI18n< + { + message: MessageSchema + number: NumberSchema + }, + 'en-US', + false +>({ + locale: 'en-US', legacy: false, - fallbackLocale: 'en', messages: { - en + 'en-US': enUS + }, + numberFormats: { + 'en-US': { + currency: { + style: 'currency', + currencyDisplay: 'symbol', + currency: 'USD' + } + } } }) diff --git a/examples/type-safe/yarn.lock b/examples/type-safe/yarn.lock index bb43ecb8c..7faf7a498 100644 --- a/examples/type-safe/yarn.lock +++ b/examples/type-safe/yarn.lock @@ -455,13 +455,13 @@ postcss-value-parser@^4.1.0: integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== postcss@^8.1.10, postcss@^8.2.10: - version "8.2.15" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65" - integrity sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q== + version "8.3.0" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.0.tgz#b1a713f6172ca427e3f05ef1303de8b65683325f" + integrity sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ== dependencies: colorette "^1.2.2" nanoid "^3.1.23" - source-map "^0.6.1" + source-map-js "^0.6.2" process-nextick-args@~2.0.0: version "2.0.1" @@ -497,9 +497,9 @@ rimraf@2: glob "^7.1.3" rollup@^2.38.5: - version "2.48.0" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.48.0.tgz#fceb01ed771f991f29f7bd2ff7838146e55acb74" - integrity sha512-wl9ZSSSsi5579oscSDYSzGn092tCS076YB+TQrzsGuSfYyJeep8eEWj0eaRjuC5McuMNmcnR8icBqiE/FWNB1A== + version "2.49.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.49.0.tgz#f0e5bb2b770ddf1be8cc30d4cce3457574c8c871" + integrity sha512-UnrCjMXICx9q0jF8L7OYs7LPk95dW0U5UYp/VANnWqfuhyr66FWi/YVlI34Oy8Tp4ZGLcaUDt4APJm80b9oPWQ== optionalDependencies: fsevents "~2.3.1" @@ -513,6 +513,11 @@ setimmediate@~1.0.4: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= +source-map-js@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" + integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== + source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -572,9 +577,9 @@ util-deprecate@^1.0.2, util-deprecate@~1.0.1: integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= vite@^2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/vite/-/vite-2.3.3.tgz#7e88a71abd03985c647789938d784cce0ee3b0fd" - integrity sha512-eO1iwRbn3/BfkNVMNJDeANAFCZ5NobYOFPu7IqfY7DcI7I9nFGjJIZid0EViTmLDGwwSUPmRAq3cRBbO3+DsMA== + version "2.3.4" + resolved "https://registry.yarnpkg.com/vite/-/vite-2.3.4.tgz#370118e0334725b898ff754ea43d5db4c5e120e3" + integrity sha512-7orxrF65+Q5n/sMCnO91S8OS0gkPJ7g+y3bLlc7CPCXVswK8to1T8YycCk9SZh+AcIc0TuN6YajWTBFS5atMNA== dependencies: esbuild "^0.11.23" postcss "^8.2.10"