From b0659002d2e555aea53d818b36d7e198cdfafe32 Mon Sep 17 00:00:00 2001 From: kazuya kawaguchi Date: Tue, 22 Nov 2022 01:00:06 +0900 Subject: [PATCH] fix: alwaysRedirect in detectBrowserLanguage (#1668) --- playground/nuxt.config.ts | 20 ++++--- playground/pages/category/[id].vue | 3 + src/runtime/internal.ts | 90 ++++++++++++++++++++++-------- src/runtime/plugin.ts | 2 +- src/runtime/utils.ts | 29 +++++++--- 5 files changed, 103 insertions(+), 41 deletions(-) diff --git a/playground/nuxt.config.ts b/playground/nuxt.config.ts index 5ce12d269..6c8dd2502 100644 --- a/playground/nuxt.config.ts +++ b/playground/nuxt.config.ts @@ -52,8 +52,8 @@ export default defineNuxtConfig({ defaultLocale: 'en', // strategy: 'no_prefix', // strategy: 'prefix', + strategy: 'prefix_and_default', // rootRedirect: '/ja/about-ja', - // strategy: 'prefix_and_default', // parsePages: false, dynamicRouteParams: true, pages: { @@ -62,15 +62,17 @@ export default defineNuxtConfig({ } }, // differentDomains: true, - skipSettingLocaleOnNavigate: true, + // skipSettingLocaleOnNavigate: true, detectBrowserLanguage: false, - // detectBrowserLanguage: { - // useCookie: true, - // alwaysRedirect: false - // // cookieKey: 'i18n_redirected', - // // cookieKey: 'my_custom_cookie_name', - // // redirectOn: 'root' - // }, + /* + detectBrowserLanguage: { + useCookie: true, + // alwaysRedirect: true, + cookieKey: 'i18n_redirected', + // cookieKey: 'my_custom_cookie_name', + redirectOn: 'root' + }, + //*/ onBeforeLanguageSwitch: (oldLocale: string, newLocale: string, initial: boolean, nuxt: NuxtApp) => { console.log('onBeforeLanguageSwitch', oldLocale, newLocale, initial) }, diff --git a/playground/pages/category/[id].vue b/playground/pages/category/[id].vue index f6634b607..924bb4123 100644 --- a/playground/pages/category/[id].vue +++ b/playground/pages/category/[id].vue @@ -24,6 +24,9 @@ definePageMeta({ {{ locale.name }} | + + + diff --git a/src/runtime/internal.ts b/src/runtime/internal.ts index 012c9df1d..1b09ee08c 100644 --- a/src/runtime/internal.ts +++ b/src/runtime/internal.ts @@ -251,6 +251,19 @@ export function setLocaleCookie( } } +export type DetectBrowserLanguageNotDetectReason = + | 'unknown' + | 'not_found_match' + | 'not_redirect_on_root' + | 'not_redirect_on_no_prefix' +export type DetectBrowserLanguageFrom = 'unknown' | 'cookie' | 'navigator_or_header' | 'fallback' +export type DetectBrowserLanguageFromResult = { + locale: string + stat: boolean + reason?: DetectBrowserLanguageNotDetectReason + from?: DetectBrowserLanguageFrom +} + export function detectBrowserLanguage( route: string | Route | RouteLocationNormalized | RouteLocationNormalizedLoaded, context: any, @@ -258,59 +271,92 @@ export function detectBrowserLanguage( nuxtI18nInternalOptions: DeepRequired, localeCodes: string[] = [], locale: Locale = '' -): string { - __DEBUG__ && console.log('detectBrowserLanguage: locale params', locale) +): DetectBrowserLanguageFromResult { const { strategy } = nuxtI18nOptions const { redirectOn, alwaysRedirect, useCookie, fallbackLocale } = nuxtI18nOptions.detectBrowserLanguage as DetectBrowserLanguageOptions const path = isString(route) ? route : route.path - __DEBUG__ && console.log('detectBrowserLanguage check route, strategy and redirectOn', path, strategy, redirectOn) + __DEBUG__ && + console.log( + 'detectBrowserLanguage: (path, strategy, alwaysRedirect, redirectOn, locale) -', + path, + strategy, + alwaysRedirect, + redirectOn, + locale + ) if (strategy !== 'no_prefix') { if (redirectOn === 'root') { if (path !== '/') { __DEBUG__ && console.log('detectBrowserLanguage: not root') - return '' + return { locale: '', stat: false, reason: 'not_redirect_on_root' } } } else if (redirectOn === 'no prefix') { if (!alwaysRedirect && path.match(getLocalesRegex(localeCodes as string[]))) { __DEBUG__ && console.log('detectBrowserLanguage: no prefix') - return '' + return { locale: '', stat: false, reason: 'not_redirect_on_no_prefix' } } } } - const cookieLocale = getLocaleCookie(context, { ...nuxtI18nOptions.detectBrowserLanguage, localeCodes }) - __DEBUG__ && console.log('detectBrowserLanguage cookieLocale', cookieLocale) - __DEBUG__ && console.log('detectBrowserLanguage browserLocale', getBrowserLocale(nuxtI18nInternalOptions, context)) + let localeFrom: DetectBrowserLanguageFrom = 'unknown' + let cookieLocale: string | undefined + let matchedLocale: string | undefined - let matchedLocale - if (useCookie && (matchedLocale = cookieLocale)) { - // get preferred language from cookie if present and enabled - } else { - // try to get locale from either navigator or header detection + // get preferred language from cookie if present and enabled + if (useCookie) { + matchedLocale = cookieLocale = getLocaleCookie(context, { ...nuxtI18nOptions.detectBrowserLanguage, localeCodes }) + localeFrom = 'cookie' + __DEBUG__ && console.log('detectBrowserLanguage: cookieLocale', cookieLocale) + } + // try to get locale from either navigator or header detection + if (!matchedLocale) { matchedLocale = getBrowserLocale(nuxtI18nInternalOptions, context) + localeFrom = 'navigator_or_header' + __DEBUG__ && console.log('detectBrowserLanguage: browserLocale', matchedLocale) } - __DEBUG__ && console.log('detectBrowserLanguage matchedLocale', matchedLocale) - + __DEBUG__ && + console.log( + 'detectBrowserLanguage: (matchedLocale, cookieLocale, localeFrom) -', + matchedLocale, + cookieLocale, + localeFrom + ) + + // set fallback locale if that is not matched locale const finalLocale = matchedLocale || fallbackLocale + if (!matchedLocale && fallbackLocale) { + localeFrom = 'fallback' + } + __DEBUG__ && + console.log( + 'detectBrowserLanguage: first finaleLocale (finaleLocale, lcoaleForm) -', + finalLocale, + cookieLocale, + localeFrom + ) + const vueI18nLocale = locale || (nuxtI18nOptions.vueI18n as I18nOptions).locale - __DEBUG__ && console.log('detectBrowserLanguage first finaleLocale', finalLocale) - __DEBUG__ && console.log('detectBrowserLanguage vueI18nLocale', vueI18nLocale) + __DEBUG__ && console.log('detectBrowserLanguage: vueI18nLocale', vueI18nLocale) // handle cookie option to prevent multiple redirections if (finalLocale && (!useCookie || alwaysRedirect || !cookieLocale)) { if (strategy === 'no_prefix') { - return finalLocale + return { locale: finalLocale, stat: true, from: localeFrom } } else { - if (finalLocale !== vueI18nLocale && path !== '/') { - __DEBUG__ && console.log('detectBrowserLanguage finalLocale !== vueI18nLocale', finalLocale) - return finalLocale + if (finalLocale !== vueI18nLocale /* && path !== '/'*/) { + __DEBUG__ && console.log('detectBrowserLanguage: finalLocale !== vueI18nLocale', finalLocale) + return { locale: finalLocale, stat: true, from: localeFrom } + } else { + if (alwaysRedirect && path === '/') { + return { locale: finalLocale, stat: true, from: localeFrom } + } } } } - return '' + return { locale: '', stat: false, reason: 'not_found_match' } } export function getHost() { diff --git a/src/runtime/plugin.ts b/src/runtime/plugin.ts index e87dfdd1d..df53d1c52 100644 --- a/src/runtime/plugin.ts +++ b/src/runtime/plugin.ts @@ -99,7 +99,7 @@ export default defineNuxtPlugin(async nuxt => { normalizedLocales, localeCodes ) - __DEBUG__ && console.log('first detect locale', initialLocale) + __DEBUG__ && console.log('first detect initial locale', initialLocale) // load initial vue-i18n locale messages vueI18nOptions.messages = await loadInitialMessages(nuxtContext, vueI18nOptions.messages, { diff --git a/src/runtime/utils.ts b/src/runtime/utils.ts index 0b279943c..240a9891f 100644 --- a/src/runtime/utils.ts +++ b/src/runtime/utils.ts @@ -42,6 +42,7 @@ import type { import type { NuxtApp } from '#imports' import type { I18n, Locale, FallbackLocale, LocaleMessages, DefineLocaleMessage } from 'vue-i18n' import type { NuxtI18nOptions, DetectBrowserLanguageOptions, RootRedirectOptions } from '#build/i18n.options.mjs' +import type { DetectBrowserLanguageFromResult } from '#build/i18n.internal.mjs' import type { DeepRequired } from 'ts-essentials' export function setCookieLocale(i18n: I18n, locale: Locale) { @@ -217,14 +218,23 @@ export function detectLocale( const { strategy, defaultLocale, differentDomains } = nuxtI18nOptions const initialLocale = isFunction(initialLocaleLoader) ? initialLocaleLoader() : initialLocaleLoader - __DEBUG__ && console.log('detectLocale: initialLocale -> ', initialLocale) - const browserLocale = nuxtI18nOptions.detectBrowserLanguage + __DEBUG__ && console.log('detectLocale: initialLocale -', initialLocale) + + // prettier-ignore + const { locale: browserLocale, stat, reason, from } = nuxtI18nOptions.detectBrowserLanguage ? detectBrowserLanguage(route, context, nuxtI18nOptions, nuxtI18nInternalOptions, localeCodes, initialLocale) - : '' - __DEBUG__ && console.log('detectLocale: browserLocale -> ', browserLocale) + : { locale: '', stat: false, reason: 'unknown', from: 'unknown' } as DetectBrowserLanguageFromResult + __DEBUG__ && + console.log( + 'detectLocale: detectBrowserLanguage (browserLocale, stat, reason, from) -', + browserLocale, + stat, + reason, + from + ) let finalLocale: string | undefined = browserLocale - __DEBUG__ && console.log('detectLocale: first check finaleLocale on stragety', strategy, finalLocale) + __DEBUG__ && console.log('detectLocale: finaleLocale first (finaleLocale, strategy) -', finalLocale, strategy) if (!finalLocale) { if (differentDomains) { finalLocale = getLocaleDomain(normalizedLocales) @@ -235,19 +245,20 @@ export function detectLocale( __DEBUG__ && console.log( - 'detectLocale: finaleLocale on detectBrowserLanguage', - nuxtI18nOptions.detectBrowserLanguage, - finalLocale + 'detectLocale: finaleLocale second (finaleLocale, detectBrowserLanguage) -', + finalLocale, + nuxtI18nOptions.detectBrowserLanguage ) if (!finalLocale && nuxtI18nOptions.detectBrowserLanguage && nuxtI18nOptions.detectBrowserLanguage.useCookie) { finalLocale = getLocaleCookie(context, { ...nuxtI18nOptions.detectBrowserLanguage, localeCodes }) } - __DEBUG__ && console.log('detectLocale: finaleLocale on defailtLocale', defaultLocale, finalLocale) + __DEBUG__ && console.log('detectLocale: finalLocale last (finalLocale, defaultLocale) -', finalLocale, defaultLocale) if (!finalLocale) { finalLocale = defaultLocale || '' } + __DEBUG__ && console.log('detectLocale: finalLocale -', finalLocale) return finalLocale }