From a7d298f3747693e71841eb2f69d6abc6253bb875 Mon Sep 17 00:00:00 2001 From: Bobbie Goede Date: Fri, 13 Dec 2024 15:51:48 +0100 Subject: [PATCH] refactor: extract duplicate detection logic into function --- src/runtime/messages.ts | 2 +- src/runtime/plugins/i18n.ts | 116 +++++++++++++++--------------------- 2 files changed, 49 insertions(+), 69 deletions(-) diff --git a/src/runtime/messages.ts b/src/runtime/messages.ts index c30a3cb3c..c4f1d6547 100644 --- a/src/runtime/messages.ts +++ b/src/runtime/messages.ts @@ -26,7 +26,7 @@ export async function loadVueI18nOptions( for (const configFile of vueI18nConfigs) { const { default: resolver } = await configFile() - const resolved = isFunction(resolver) ? await nuxt.runWithContext(async () => await resolver()) : resolver + const resolved = isFunction(resolver) ? await nuxt.runWithContext(() => resolver()) : resolver deepCopy(resolved, vueI18nOptions) } diff --git a/src/runtime/plugins/i18n.ts b/src/runtime/plugins/i18n.ts index a7f5c56d1..75cf17bbe 100644 --- a/src/runtime/plugins/i18n.ts +++ b/src/runtime/plugins/i18n.ts @@ -1,6 +1,6 @@ import { computed, ref, watch } from 'vue' import { createI18n } from 'vue-i18n' -import { defineNuxtPlugin, useRoute, addRouteMiddleware, defineNuxtRouteMiddleware, useNuxtApp } from '#imports' +import { defineNuxtPlugin, addRouteMiddleware, defineNuxtRouteMiddleware, useNuxtApp } from '#imports' import { localeCodes, vueI18nConfigs, @@ -32,6 +32,7 @@ import type { Locale, I18nOptions } from 'vue-i18n' import type { NuxtApp } from '#app' import type { LocaleObject } from '#internal-i18n-types' import type { I18nPublicRuntimeConfig } from '#internal-i18n-types' +import type { CompatRoute } from '../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] } @@ -47,14 +48,14 @@ export default defineNuxtPlugin({ parallel: parallelPlugin, async setup(nuxt) { const logger = /*#__PURE__*/ createLogger('plugin:i18n') - const nuxtContext = nuxt as unknown as NuxtApp + const nuxtApp = nuxt as unknown as NuxtApp - const defaultLocaleDomain = getDefaultLocaleForDomain(nuxtContext) - setupMultiDomainLocales(nuxtContext, defaultLocaleDomain) + const defaultLocaleDomain = getDefaultLocaleForDomain(nuxtApp) + setupMultiDomainLocales(nuxtApp, defaultLocaleDomain) // Fresh copy per request to prevent reusing mutated options const runtimeI18n = { - ...(nuxtContext.$config.public.i18n as I18nPublicRuntimeConfig), + ...(nuxtApp.$config.public.i18n as I18nPublicRuntimeConfig), defaultLocale: defaultLocaleDomain } // @ts-expect-error type incompatible @@ -76,12 +77,11 @@ export default defineNuxtPlugin({ // create i18n instance const i18n = createI18n({ ...vueI18nOptions, locale: 'en' }) - let firstAccessHandled = false + let firstAccess = true // extend i18n instance extendI18n(i18n, { extendComposer(composer) { - const route = useRoute() const _locales = ref(runtimeI18n.locales) const _localeCodes = ref(localeCodes) const _baseUrl = ref('') @@ -95,12 +95,12 @@ export default defineNuxtPlugin({ watch( composer.locale, () => { - _baseUrl.value = resolveBaseUrl(runtimeI18n.baseUrl!, nuxtContext) + _baseUrl.value = resolveBaseUrl(runtimeI18n.baseUrl!, nuxtApp) }, { immediate: true } ) } else { - _baseUrl.value = resolveBaseUrl(runtimeI18n.baseUrl!, nuxtContext) + _baseUrl.value = resolveBaseUrl(runtimeI18n.baseUrl!, nuxtApp) } composer.strategy = runtimeI18n.strategy @@ -108,7 +108,7 @@ export default defineNuxtPlugin({ () => normalizedLocales.find(l => l.code === composer.locale.value) || { code: composer.locale.value } ) composer.setLocale = async (locale: string) => { - await loadAndSetLocale(locale, i18n, runtimeI18n, !firstAccessHandled) + await loadAndSetLocale(locale, i18n, runtimeI18n, firstAccess) if (!hasPages) { return @@ -120,9 +120,10 @@ export default defineNuxtPlugin({ return } - const redirectPath = await nuxtContext.runWithContext(() => + const route = nuxtApp.$router.currentRoute.value + const redirectPath = await nuxtApp.runWithContext(() => detectRedirect({ - route: { to: nuxtContext.$router.currentRoute.value }, + route: { to: route }, locale, routeLocale: getLocaleFromRoute(route), strategy: runtimeI18n.strategy @@ -131,18 +132,8 @@ export default defineNuxtPlugin({ __DEBUG__ && logger.log('redirectPath on setLocale', redirectPath) - await nuxtContext.runWithContext( - async () => - await navigate( - { - nuxtApp: nuxtContext, - i18n, - redirectPath, - locale: locale, - route: nuxtContext.$router.currentRoute.value - }, - { enableNavigate: true } - ) + await nuxtApp.runWithContext(() => + navigate({ nuxtApp, i18n, redirectPath, locale: locale, route }, { enableNavigate: true }) ) } composer.loadLocaleMessages = async (locale: string) => { @@ -248,27 +239,40 @@ export default defineNuxtPlugin({ nuxt.vueApp.use(i18n) // TODO: should implement `{ inject: false } via `nuxtjs/i18n` configuration // inject for nuxt helpers - injectNuxtHelpers(nuxtContext, i18n) - - // router is enabled and project has pages - if (!hasPages) { - const currentRoute = nuxtContext.$router.currentRoute - const detected = detectLocale( - currentRoute.value, - getLocaleFromRoute(currentRoute.value), - undefined, + injectNuxtHelpers(nuxtApp, i18n) + + async function handleRouteDetect(to: CompatRoute) { + const routeLocale = getLocaleFromRoute(to) + let detected = detectLocale( + to, + routeLocale, + getLocale(i18n), { - ssg: 'normal', - callType: 'setup', - firstAccess: true, + ssg: isSSG && firstAccess && runtimeI18n.strategy === 'no_prefix' ? 'ssg_ignore' : 'normal', + callType: !hasPages ? 'setup' : 'routing', + firstAccess, localeCookie: getLocaleCookie(localeCookie, _detectBrowserLanguage, runtimeI18n.defaultLocale) }, runtimeI18n ) + __DEBUG__ && logger.log('detect locale', detected) + + if (firstAccess) { + setLocaleProperty(i18n, detected) + await getI18nTarget(i18n).loadLocaleMessages(detected) + } - await loadAndSetLocale(detected, i18n, runtimeI18n, true) - await getI18nTarget(i18n).loadLocaleMessages(detected) + const mod = await nuxtApp.runWithContext(() => loadAndSetLocale(detected, i18n, runtimeI18n, firstAccess)) + if (mod) { + detected = getLocale(i18n) + } + + return detected + } + // router is enabled and project has pages + if (!hasPages) { + await handleRouteDetect(nuxtApp.$router.currentRoute.value) return } @@ -278,42 +282,18 @@ export default defineNuxtPlugin({ defineNuxtRouteMiddleware(async (to, from) => { __DEBUG__ && logger.log('locale-changing middleware', to, from) - const routeLocale = getLocaleFromRoute(to) - let locale = detectLocale( - to, - routeLocale, - getLocale(i18n), - { - ssg: isSSG && !firstAccessHandled && runtimeI18n.strategy === 'no_prefix' ? 'ssg_ignore' : 'normal', - callType: 'routing', - firstAccess: !firstAccessHandled, - localeCookie: getLocaleCookie(localeCookie, _detectBrowserLanguage, runtimeI18n.defaultLocale) - }, - runtimeI18n - ) - __DEBUG__ && logger.log('detect locale', locale) - - if (!firstAccessHandled) { - setLocaleProperty(i18n, locale) - await getI18nTarget(i18n).loadLocaleMessages(locale) - } + const locale = await nuxtApp.runWithContext(() => handleRouteDetect(to)) - const _modified = await loadAndSetLocale(locale, i18n, runtimeI18n, !firstAccessHandled) - if (_modified) { - locale = getLocale(i18n) - } - - const redirectPath = await nuxtContext.runWithContext(() => - detectRedirect({ route: { to, from }, locale: locale, routeLocale, strategy: runtimeI18n.strategy }, true) + const routeLocale = getLocaleFromRoute(to) + const redirectPath = await nuxtApp.runWithContext(() => + detectRedirect({ route: { to, from }, locale, routeLocale, strategy: runtimeI18n.strategy }, true) ) - firstAccessHandled ||= true + firstAccess = false __DEBUG__ && logger.log('redirectPath on locale-changing middleware', redirectPath) - return await nuxtContext.runWithContext( - async () => await navigate({ nuxtApp: nuxtContext, i18n, redirectPath, locale: locale, route: to }) - ) + return await nuxtApp.runWithContext(() => navigate({ nuxtApp, i18n, redirectPath, locale, route: to })) }), { global: true } )