From 00638ab4bd445c509ec79c60455d4ad904c3d9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Sat, 21 Sep 2024 18:31:06 +0200 Subject: [PATCH] fix: move shared types to runtime (#3121) --- src/constants.ts | 18 +- src/module.ts | 88 +--- src/runtime/composables/index.ts | 2 +- src/runtime/internal.ts | 13 +- src/runtime/messages.ts | 2 +- src/runtime/plugins/i18n.ts | 6 +- src/runtime/routing/compatibles/head.ts | 3 +- src/runtime/routing/compatibles/routing.ts | 8 +- src/runtime/routing/compatibles/utils.ts | 2 +- src/runtime/routing/utils.ts | 2 +- src/runtime/shared-types.ts | 508 +++++++++++++++++++++ src/runtime/types.ts | 2 +- src/runtime/utils.ts | 16 +- src/types.ts | 412 +---------------- 14 files changed, 547 insertions(+), 535 deletions(-) create mode 100644 src/runtime/shared-types.ts diff --git a/src/constants.ts b/src/constants.ts index 6adaa39a3..e83815567 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -9,18 +9,16 @@ export const UTILS_PKG = '@intlify/utils' export const UTILS_H3_PKG = '@intlify/utils/h3' export const UFO_PKG = 'ufo' export const IS_HTTPS_PKG = 'is-https' +import { + STRATEGIES, + STRATEGY_PREFIX, + STRATEGY_PREFIX_EXCEPT_DEFAULT, + STRATEGY_PREFIX_AND_DEFAULT, + STRATEGY_NO_PREFIX +} from './runtime/shared-types' // Options -const STRATEGY_PREFIX = 'prefix' -const STRATEGY_PREFIX_EXCEPT_DEFAULT = 'prefix_except_default' -const STRATEGY_PREFIX_AND_DEFAULT = 'prefix_and_default' -const STRATEGY_NO_PREFIX = 'no_prefix' -export const STRATEGIES = { - PREFIX: STRATEGY_PREFIX, - PREFIX_EXCEPT_DEFAULT: STRATEGY_PREFIX_EXCEPT_DEFAULT, - PREFIX_AND_DEFAULT: STRATEGY_PREFIX_AND_DEFAULT, - NO_PREFIX: STRATEGY_NO_PREFIX -} as const +export { STRATEGIES, STRATEGY_PREFIX, STRATEGY_PREFIX_EXCEPT_DEFAULT, STRATEGY_PREFIX_AND_DEFAULT, STRATEGY_NO_PREFIX } export const DEFAULT_DYNAMIC_PARAMS_KEY = 'nuxtI18nInternal' export const DEFAULT_COOKIE_KEY = 'i18n_redirected' diff --git a/src/module.ts b/src/module.ts index 8a5ffe557..5455bd59c 100644 --- a/src/module.ts +++ b/src/module.ts @@ -5,7 +5,7 @@ import { setupNitro } from './nitro' import { extendBundler } from './bundler' import { NUXT_I18N_MODULE_ID, DEFAULT_OPTIONS } from './constants' import type { HookResult } from '@nuxt/schema' -import type { LocaleObject, NuxtI18nOptions } from './types' +import type { I18nPublicRuntimeConfig, LocaleObject, NuxtI18nOptions } from './types' import type { Locale } from 'vue-i18n' import { createContext } from './context' import { prepareOptions } from './prepare/options' @@ -116,91 +116,7 @@ type UserNuxtI18nOptions = Omit & { locales?: string export interface ModuleOptions extends UserNuxtI18nOptions {} export interface ModulePublicRuntimeConfig { - i18n: { - baseUrl: NuxtI18nOptions['baseUrl'] - rootRedirect: NuxtI18nOptions['rootRedirect'] - multiDomainLocales?: NuxtI18nOptions['multiDomainLocales'] - - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - domainLocales: { [key: Locale]: { domain: string | undefined } } - - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - experimental: NonNullable - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - locales: NonNullable>['locales']> - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - differentDomains: Required['differentDomains'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - skipSettingLocaleOnNavigate: Required['skipSettingLocaleOnNavigate'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - defaultLocale: Required['defaultLocale'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - lazy: Required['lazy'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - defaultDirection: Required['defaultDirection'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - detectBrowserLanguage: Required['detectBrowserLanguage'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - strategy: Required['strategy'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - routesNameSeparator: Required['routesNameSeparator'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - defaultLocaleRouteNameSuffix: Required['defaultLocaleRouteNameSuffix'] - /** - * Overwritten at build time, used to pass generated options to runtime - * - * @internal - */ - trailingSlash: Required['trailingSlash'] - } + i18n: I18nPublicRuntimeConfig } export interface ModuleHooks { 'i18n:registerModule': ( diff --git a/src/runtime/composables/index.ts b/src/runtime/composables/index.ts index 1e9fb1aed..a1aeb1191 100644 --- a/src/runtime/composables/index.ts +++ b/src/runtime/composables/index.ts @@ -23,7 +23,7 @@ import { getLocale, getLocales, getComposer } from '../compatibility' import type { Ref } from 'vue' import type { Locale } from 'vue-i18n' import type { RouteLocation, RouteLocationNormalizedLoaded, RouteLocationRaw, Router } from 'vue-router' -import type { I18nHeadMetaInfo, I18nHeadOptions, SeoAttributesOptions } from '../../types' +import type { I18nHeadMetaInfo, I18nHeadOptions, SeoAttributesOptions } from '../shared-types' import type { HeadParam } from '../utils' export * from 'vue-i18n' diff --git a/src/runtime/internal.ts b/src/runtime/internal.ts index 70f74e046..20203c240 100644 --- a/src/runtime/internal.ts +++ b/src/runtime/internal.ts @@ -17,10 +17,10 @@ import { initCommonComposableOptions, type CommonComposableOptions } from './uti import { createLogger } from 'virtual:nuxt-i18n-logger' import type { Locale } from 'vue-i18n' -import type { DetectBrowserLanguageOptions, LocaleObject } from '../types' +import type { DetectBrowserLanguageOptions, LocaleObject } from './shared-types' import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router' import type { CookieRef, NuxtApp } from 'nuxt/app' -import type { ModulePublicRuntimeConfig } from '../module' +import type { I18nPublicRuntimeConfig } from './shared-types' export function formatMessage(message: string) { return NUXT_I18N_MODULE_ID + ' ' + message @@ -350,7 +350,7 @@ export function getDomainFromLocale(localeCode: Locale): string | undefined { const nuxtApp = useNuxtApp() const host = getHost() // lookup the `differentDomain` origin associated with given locale. - const config = runtimeConfig.public.i18n as ModulePublicRuntimeConfig['i18n'] + const config = runtimeConfig.public.i18n as I18nPublicRuntimeConfig const lang = normalizedLocales.find(locale => locale.code === localeCode) const domain = config?.domainLocales?.[localeCode]?.domain || lang?.domain || lang?.domains?.find(v => v === host) @@ -374,7 +374,7 @@ export function getDomainFromLocale(localeCode: Locale): string | undefined { } export const runtimeDetectBrowserLanguage = ( - opts: ModulePublicRuntimeConfig['i18n'] = useRuntimeConfig().public.i18n as ModulePublicRuntimeConfig['i18n'] + opts: I18nPublicRuntimeConfig = useRuntimeConfig().public.i18n as I18nPublicRuntimeConfig ) => { if (opts?.detectBrowserLanguage === false) return false @@ -386,7 +386,7 @@ export const runtimeDetectBrowserLanguage = ( */ export function setupMultiDomainLocales(nuxtContext: NuxtApp, defaultLocaleDomain: string) { const { multiDomainLocales, strategy, routesNameSeparator, defaultLocaleRouteNameSuffix } = nuxtContext.$config.public - .i18n as ModulePublicRuntimeConfig['i18n'] + .i18n as I18nPublicRuntimeConfig // feature disabled if (!multiDomainLocales) return @@ -419,8 +419,7 @@ export function setupMultiDomainLocales(nuxtContext: NuxtApp, defaultLocaleDomai * Returns default locale for the current domain, returns `defaultLocale` by default */ export function getDefaultLocaleForDomain(nuxtContext: NuxtApp) { - const { locales, defaultLocale, multiDomainLocales } = nuxtContext.$config.public - .i18n as ModulePublicRuntimeConfig['i18n'] + const { locales, defaultLocale, multiDomainLocales } = nuxtContext.$config.public.i18n as I18nPublicRuntimeConfig let defaultLocaleDomain: string = defaultLocale || '' diff --git a/src/runtime/messages.ts b/src/runtime/messages.ts index e5c1cb0ca..6de0b496b 100644 --- a/src/runtime/messages.ts +++ b/src/runtime/messages.ts @@ -4,7 +4,7 @@ import { createLogger } from 'virtual:nuxt-i18n-logger' import type { I18nOptions, Locale, FallbackLocale, LocaleMessages, DefineLocaleMessage } from 'vue-i18n' import type { NuxtApp } from '#app' import type { DeepRequired } from 'ts-essentials' -import type { VueI18nConfig, NuxtI18nOptions } from '../types' +import type { VueI18nConfig, NuxtI18nOptions } from './shared-types' import type { CoreContext } from '@intlify/h3' type MessageLoaderFunction = (locale: Locale) => Promise> diff --git a/src/runtime/plugins/i18n.ts b/src/runtime/plugins/i18n.ts index 9ed33fdec..7b0b6dffe 100644 --- a/src/runtime/plugins/i18n.ts +++ b/src/runtime/plugins/i18n.ts @@ -29,8 +29,8 @@ import { createLogger } from 'virtual:nuxt-i18n-logger' import type { NuxtI18nPluginInjections } from '../injections' import type { Locale, I18nOptions } from 'vue-i18n' import type { NuxtApp } from '#app' -import type { LocaleObject } from '../../types' -import type { ModulePublicRuntimeConfig } from '../../module' +import type { LocaleObject } from '../shared-types' +import type { I18nPublicRuntimeConfig } from '../shared-types' // from https://github.com/nuxt/nuxt/blob/2466af53b0331cdb8b17c2c3b08675c5985deaf3/packages/nuxt/src/core/templates.ts#L152 type Decorate> = { [K in keyof T as K extends string ? `$${K}` : never]: T[K] } @@ -59,7 +59,7 @@ export default defineNuxtPlugin({ // Fresh copy per request to prevent reusing mutated options const runtimeI18n = { - ...(nuxtContext.$config.public.i18n as ModulePublicRuntimeConfig['i18n']), + ...(nuxtContext.$config.public.i18n as I18nPublicRuntimeConfig), defaultLocale: defaultLocaleDomain } // @ts-expect-error type incompatible diff --git a/src/runtime/routing/compatibles/head.ts b/src/runtime/routing/compatibles/head.ts index 649421eee..0a37eac07 100644 --- a/src/runtime/routing/compatibles/head.ts +++ b/src/runtime/routing/compatibles/head.ts @@ -7,12 +7,13 @@ import { getRouteBaseName, localeRoute, switchLocalePath } from './routing' import { getComposer, getLocale, getLocales } from '../../compatibility' import type { I18n } from 'vue-i18n' -import type { I18nHeadMetaInfo, MetaAttrs, LocaleObject, I18nHeadOptions } from '../../../types' +import type { I18nHeadMetaInfo, MetaAttrs, LocaleObject, I18nHeadOptions } from '../../shared-types' import type { CommonComposableOptions } from '../../utils' /** * Returns localized head properties for locale-related aspects. * + * @param common - Common options used internally by composable functions. * @param options - An options, see about details {@link I18nHeadOptions}. * * @returns The localized {@link I18nHeadMetaInfo | head properties}. diff --git a/src/runtime/routing/compatibles/routing.ts b/src/runtime/routing/compatibles/routing.ts index 379ed385d..8d17239b7 100644 --- a/src/runtime/routing/compatibles/routing.ts +++ b/src/runtime/routing/compatibles/routing.ts @@ -9,7 +9,7 @@ import { resolve, routeToObject } from './utils' import { getLocaleRouteName, getRouteName } from '../utils' import { extendPrefixable, extendSwitchLocalePathIntercepter, type CommonComposableOptions } from '../../utils' -import type { Strategies, PrefixableOptions, SwitchLocalePathIntercepter } from '../../../types' +import type { Strategies, PrefixableOptions, SwitchLocalePathIntercepter } from '../../shared-types' import type { Locale } from 'vue-i18n' import type { RouteLocation, @@ -20,7 +20,7 @@ import type { RouteLocationNormalizedLoaded, RouteLocationNormalized } from 'vue-router' -import type { ModulePublicRuntimeConfig } from '../../../module' +import type { I18nPublicRuntimeConfig } from '../../shared-types' const RESOLVED_PREFIXED = new Set(['prefix_and_default', 'prefix_except_default']) @@ -114,6 +114,7 @@ export function localeRoute( * @remarks * If `locale` is not specified, uses current locale. * + * @param common - Common options used internally by composable functions. * @param route - A route. * @param locale - A locale, optional. * @@ -133,8 +134,7 @@ export function localeLocation( export function resolveRoute(common: CommonComposableOptions, route: RouteLocationRaw, locale: Locale | undefined) { const { router, i18n } = common const _locale = locale || getLocale(i18n) - const { defaultLocale, strategy, trailingSlash } = common.runtimeConfig.public - .i18n as ModulePublicRuntimeConfig['i18n'] + const { defaultLocale, strategy, trailingSlash } = common.runtimeConfig.public.i18n as I18nPublicRuntimeConfig const prefixable = extendPrefixable(common.runtimeConfig) // if route parameter is a string, check if it's a path or name of route. let _route: RouteLocationPathRaw | RouteLocationNamedRaw diff --git a/src/runtime/routing/compatibles/utils.ts b/src/runtime/routing/compatibles/utils.ts index cf83ec487..8e6433f1c 100644 --- a/src/runtime/routing/compatibles/utils.ts +++ b/src/runtime/routing/compatibles/utils.ts @@ -2,7 +2,7 @@ import { assign } from '@intlify/shared' import type { Locale } from 'vue-i18n' import type { RouteLocationNormalizedLoaded, RouteLocationPathRaw } from 'vue-router' -import type { Strategies } from '../../../types' +import type { Strategies } from '../../shared-types' import type { CommonComposableOptions } from '../../utils' function split(str: string, index: number) { diff --git a/src/runtime/routing/utils.ts b/src/runtime/routing/utils.ts index e40205fd5..9e1daa03a 100644 --- a/src/runtime/routing/utils.ts +++ b/src/runtime/routing/utils.ts @@ -1,6 +1,6 @@ import { isString, isSymbol, isFunction } from '@intlify/shared' -import type { LocaleObject, Strategies, BaseUrlResolveHandler } from '../../types' +import type { LocaleObject, Strategies, BaseUrlResolveHandler } from '../shared-types' import type { Locale } from 'vue-i18n' export const inBrowser = typeof window !== 'undefined' diff --git a/src/runtime/shared-types.ts b/src/runtime/shared-types.ts new file mode 100644 index 000000000..27fd64cc5 --- /dev/null +++ b/src/runtime/shared-types.ts @@ -0,0 +1,508 @@ +import type { Locale, I18nOptions } from 'vue-i18n' +import type { ParsedPath } from 'path' +import type { PluginOptions } from '@intlify/unplugin-vue-i18n' +import type { NuxtPage } from '@nuxt/schema' + +// Options +export const STRATEGY_PREFIX = 'prefix' +export const STRATEGY_PREFIX_EXCEPT_DEFAULT = 'prefix_except_default' +export const STRATEGY_PREFIX_AND_DEFAULT = 'prefix_and_default' +export const STRATEGY_NO_PREFIX = 'no_prefix' +export const STRATEGIES = { + PREFIX: STRATEGY_PREFIX, + PREFIX_EXCEPT_DEFAULT: STRATEGY_PREFIX_EXCEPT_DEFAULT, + PREFIX_AND_DEFAULT: STRATEGY_PREFIX_AND_DEFAULT, + NO_PREFIX: STRATEGY_NO_PREFIX +} as const + +export type RedirectOnOptions = 'all' | 'root' | 'no prefix' + +export interface DetectBrowserLanguageOptions { + alwaysRedirect?: boolean + cookieCrossOrigin?: boolean + cookieDomain?: string | null + cookieKey?: string + cookieSecure?: boolean + fallbackLocale?: Locale | null + redirectOn?: RedirectOnOptions + useCookie?: boolean +} + +export type LocaleType = 'static' | 'dynamic' | 'unknown' + +export type LocaleFile = { path: string; cache?: boolean } + +export type LocaleInfo = { + /** + * NOTE: + * The following fields are for `file` in the nuxt i18n module `locales` option + */ + path?: string // abolute path + hash?: string + type?: LocaleType + /** + * NOTE: + * The following fields are for `files` (excludes nuxt layers) in the nuxt i18n module `locales` option. + */ + paths?: string[] + hashes?: string[] + types?: LocaleType[] +} & Omit & { + code: Locale + files: LocaleFile[] + meta?: (FileMeta & { file: LocaleFile })[] + } + +export type FileMeta = { + path: string + loadPath: string + hash: string + type: LocaleType + parsed: ParsedPath + key: string +} + +export type VueI18nConfigPathInfo = { + relative?: string + absolute?: string + hash?: string + type?: LocaleType + rootDir: string + relativeBase: string + meta: FileMeta +} + +export interface RootRedirectOptions { + path: string + statusCode: number +} + +export type CustomRoutePages = { + [key: string]: + | false + | { + [key: string]: false | string + } +} + +export interface ExperimentalFeatures { + localeDetector?: string + switchLocalePathLinkSSR?: boolean + /** + * Automatically imports/initializes `$t`, `$rt`, `$d`, `$n`, `$tm` and `$te` functions in `