Skip to content

Commit

Permalink
fix: alwaysRedirect in detectBrowserLanguage (#1668)
Browse files Browse the repository at this point in the history
  • Loading branch information
kazupon committed Nov 21, 2022
1 parent 493bb8f commit b065900
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 41 deletions.
20 changes: 11 additions & 9 deletions playground/nuxt.config.ts
Expand Up @@ -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: {
Expand All @@ -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)
},
Expand Down
3 changes: 3 additions & 0 deletions playground/pages/category/[id].vue
Expand Up @@ -24,6 +24,9 @@ definePageMeta({
<span v-for="locale in availableLocales" :key="locale.code">
<NuxtLink :to="switchLocalePath(locale.code) || ''">{{ locale.name }}</NuxtLink> |
</span>
<i18n-t keypath="hello">
<template #name>nuxtjs/i18n</template>
</i18n-t>
</nav>
</div>
</template>
90 changes: 68 additions & 22 deletions src/runtime/internal.ts
Expand Up @@ -251,66 +251,112 @@ 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<Context extends NuxtApp = NuxtApp>(
route: string | Route | RouteLocationNormalized | RouteLocationNormalizedLoaded,
context: any,
nuxtI18nOptions: DeepRequired<NuxtI18nOptions<Context>>,
nuxtI18nInternalOptions: DeepRequired<NuxtI18nInternalOptions>,
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() {
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/plugin.ts
Expand Up @@ -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, {
Expand Down
29 changes: 20 additions & 9 deletions src/runtime/utils.ts
Expand Up @@ -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) {
Expand Down Expand Up @@ -217,14 +218,23 @@ export function detectLocale<Context extends NuxtApp = NuxtApp>(
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)
Expand All @@ -235,19 +245,20 @@ export function detectLocale<Context extends NuxtApp = NuxtApp>(

__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
}

Expand Down

0 comments on commit b065900

Please sign in to comment.