Skip to content

Commit

Permalink
fix: setLocale throws error updating locale cookie from plugin (#2783)
Browse files Browse the repository at this point in the history
  • Loading branch information
BobbieGoede committed Feb 13, 2024
1 parent 0e45dca commit 61d5428
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 43 deletions.
4 changes: 0 additions & 4 deletions specs/basic_usage.spec.ts
Expand Up @@ -355,7 +355,3 @@ test('dynamic parameters', async () => {
const product2dom = getDom(product2Html)
expect(product2dom.querySelector('#i18n-alt-en').href).toEqual('/products/red-mug')
})

test('(#2554) using `setLocale` in plugin should not throw an error', async () => {
await expect($fetch('/?pluginSetLocale')).resolves.to.not.toThrowError()
})
8 changes: 0 additions & 8 deletions specs/fixtures/basic_usage/plugins/set-locale-plugin.ts

This file was deleted.

3 changes: 3 additions & 0 deletions specs/fixtures/issues/2554/app.vue
@@ -0,0 +1,3 @@
<template>
<NuxtPage />
</template>
7 changes: 7 additions & 0 deletions specs/fixtures/issues/2554/nuxt.config.ts
@@ -0,0 +1,7 @@
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
locales: ['en', 'fr'],
strategy: 'no_prefix'
}
})
14 changes: 14 additions & 0 deletions specs/fixtures/issues/2554/package.json
@@ -0,0 +1,14 @@
{
"name": "nuxt3-test-issues-2473",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
},
"devDependencies": {
"@nuxtjs/i18n": "latest",
"nuxt": "latest"
}
}
3 changes: 3 additions & 0 deletions specs/fixtures/issues/2554/pages/index.vue
@@ -0,0 +1,3 @@
<template>
<div>Hello</div>
</template>
8 changes: 8 additions & 0 deletions specs/fixtures/issues/2554/plugins/set-locale-plugin.ts
@@ -0,0 +1,8 @@
import { defineNuxtPlugin } from '#imports'

export default defineNuxtPlugin(async nuxtApp => {
if ('pluginSetLocale' in nuxtApp._route.query && typeof nuxtApp._route.query.pluginSetLocale === 'string') {
const app = useNuxtApp()
await app.$i18n.setLocale(nuxtApp._route.query.pluginSetLocale)
}
})
22 changes: 22 additions & 0 deletions specs/issues/2554.spec.ts
@@ -0,0 +1,22 @@
import { test, expect, describe } from 'vitest'
import { fileURLToPath } from 'node:url'
import { URL } from 'node:url'
import { setup, url } from '../utils'
import { renderPage } from '../helper'

describe('#2554', async () => {
await setup({
rootDir: fileURLToPath(new URL(`../fixtures/issues/2554`, import.meta.url)),
browser: true
})

test('should not throw an error when using `setLocale` from plugin', async () => {
const { page } = await renderPage('/')

const res1 = await page.goto(url('/?pluginSetLocale=fr'))
expect(res1?.ok()).toBeTruthy()

const res2 = await page.goto(url('/?pluginSetLocale=en'))
expect(res2?.ok()).toBeTruthy()
})
})
49 changes: 27 additions & 22 deletions src/runtime/internal.ts
Expand Up @@ -25,6 +25,7 @@ import { initCommonComposableOptions, type CommonComposableOptions } from './uti
import type { Locale } from 'vue-i18n'
import type { DetectBrowserLanguageOptions, LocaleObject } from '#build/i18n.options.mjs'
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router'
import type { CookieRef } from 'nuxt/app'

export function formatMessage(message: string) {
return NUXT_I18N_MODULE_ID + ' ' + message
Expand Down Expand Up @@ -93,7 +94,25 @@ export function getBrowserLocale(): string | undefined {
return ret
}

export function getLocaleCookie(): string | undefined {
export function getI18nCookie() {
const detect = nuxtI18nOptions.detectBrowserLanguage
const cookieKey = (detect && detect.cookieKey) || nuxtI18nOptionsDefault.detectBrowserLanguage.cookieKey
const date = new Date()
const cookieOptions: Record<string, any> = {
expires: new Date(date.setDate(date.getDate() + 365)),
path: '/',
sameSite: detect && detect.cookieCrossOrigin ? 'none' : 'lax',
secure: (detect && detect.cookieCrossOrigin) || (detect && detect.cookieSecure)
}

if (detect && detect.cookieDomain) {
cookieOptions.domain = detect.cookieDomain
}

return useNuxtCookie<string | undefined>(cookieKey, cookieOptions)
}

export function getLocaleCookie(cookieRef: CookieRef<string | undefined>): string | undefined {
const detect = nuxtI18nOptions.detectBrowserLanguage

__DEBUG__ &&
Expand All @@ -107,37 +126,22 @@ export function getLocaleCookie(): string | undefined {
return
}

const localeCookie = useNuxtCookie(detect.cookieKey)
const localeCode: string | undefined = localeCookie.value ?? undefined
const localeCode: string | undefined = cookieRef.value ?? undefined
__DEBUG__ && console.log(`getLocaleCookie cookie (${process.client ? 'client' : 'server'}) -`, localeCode)

if (localeCode && localeCodes.includes(localeCode)) {
return localeCode
}
}

export function setLocaleCookie(locale: string) {
const { useCookie, cookieKey, cookieDomain, cookieSecure, cookieCrossOrigin } =
nuxtI18nOptions.detectBrowserLanguage || nuxtI18nOptionsDefault.detectBrowserLanguage
export function setLocaleCookie(cookieRef: CookieRef<string | undefined>, locale: string) {
const { useCookie } = nuxtI18nOptions.detectBrowserLanguage || nuxtI18nOptionsDefault.detectBrowserLanguage

if (!useCookie) {
return
}

const date = new Date()
const cookieOptions: Record<string, any> = {
expires: new Date(date.setDate(date.getDate() + 365)),
path: '/',
sameSite: cookieCrossOrigin ? 'none' : 'lax',
secure: cookieCrossOrigin || cookieSecure
}

if (cookieDomain) {
cookieOptions.domain = cookieDomain
}

const localeCookie = useNuxtCookie(cookieKey, cookieOptions)
localeCookie.value = locale
cookieRef.value = locale
}

export type DetectBrowserLanguageNotDetectReason =
Expand All @@ -160,6 +164,7 @@ export type DetectLocaleContext = {
ssg: DetectLocaleForSSGStatus
callType: DetectLocaleCallType
firstAccess: boolean
localeCookie: CookieRef<string | undefined>
}

export const DefaultDetectBrowserLanguageFromResult: DetectBrowserLanguageFromResult = {
Expand All @@ -176,7 +181,7 @@ export function detectBrowserLanguage(
locale: Locale = ''
): DetectBrowserLanguageFromResult {
const { strategy } = nuxtI18nOptions
const { ssg, callType, firstAccess } = detectLocaleContext
const { ssg, callType, firstAccess, localeCookie } = detectLocaleContext
__DEBUG__ && console.log('detectBrowserLanguage: (ssg, callType, firstAccess) - ', ssg, callType, firstAccess)

// browser detection is ignored if it's a nuxt generate.
Expand Down Expand Up @@ -223,7 +228,7 @@ export function detectBrowserLanguage(

// get preferred language from cookie if present and enabled
if (useCookie) {
matchedLocale = cookieLocale = getLocaleCookie()
matchedLocale = cookieLocale = localeCookie.value
localeFrom = 'cookie'
__DEBUG__ && console.log('detectBrowserLanguage: cookieLocale', cookieLocale)
}
Expand Down
16 changes: 10 additions & 6 deletions src/runtime/plugins/i18n.ts
Expand Up @@ -25,7 +25,8 @@ import {
getLocaleCookie as _getLocaleCookie,
setLocaleCookie as _setLocaleCookie,
detectBrowserLanguage,
DefaultDetectBrowserLanguageFromResult
DefaultDetectBrowserLanguageFromResult,
getI18nCookie
} from '../internal'
import { getComposer, getLocale, setLocale } from '../routing/utils'
import { extendI18n, createLocaleFromRouteGetter } from '../routing/extends'
Expand Down Expand Up @@ -68,6 +69,7 @@ export default defineNuxtPlugin({
const getLocaleFromRoute = createLocaleFromRouteGetter()
const getDefaultLocale = (defaultLocale: string) => defaultLocale || vueI18nOptions.locale || 'en-US'

const localeCookie = getI18nCookie()
// detect initial locale
let initialLocale = detectLocale(
route,
Expand All @@ -77,7 +79,8 @@ export default defineNuxtPlugin({
{
ssg: isSSG && nuxtI18nOptions.strategy === 'no_prefix' ? 'ssg_ignore' : 'normal',
callType: 'setup',
firstAccess: true
firstAccess: true,
localeCookie
}
)
__DEBUG__ && console.log('first detect initial locale', initialLocale)
Expand Down Expand Up @@ -124,7 +127,7 @@ export default defineNuxtPlugin({
? detectBrowserLanguage(
route,
vueI18nOptions.locale,
{ ssg: 'ssg_setup', callType: 'setup', firstAccess: true },
{ ssg: 'ssg_setup', callType: 'setup', firstAccess: true, localeCookie },
initialLocale
)
: DefaultDetectBrowserLanguageFromResult
Expand Down Expand Up @@ -187,8 +190,8 @@ export default defineNuxtPlugin({
composer.differentDomains = nuxtI18nOptions.differentDomains
composer.defaultLocale = nuxtI18nOptions.defaultLocale
composer.getBrowserLocale = () => _getBrowserLocale()
composer.getLocaleCookie = () => _getLocaleCookie()
composer.setLocaleCookie = (locale: string) => _setLocaleCookie(locale)
composer.getLocaleCookie = () => _getLocaleCookie(localeCookie)
composer.setLocaleCookie = (locale: string) => _setLocaleCookie(localeCookie, locale)

composer.onBeforeLanguageSwitch = (oldLocale, newLocale, initialSetup, context) =>
nuxt.callHook('i18n:beforeLocaleSwitch', { oldLocale, newLocale, initialSetup, context })
Expand Down Expand Up @@ -394,7 +397,8 @@ export default defineNuxtPlugin({
{
ssg: isSSGModeInitialSetup() && nuxtI18nOptions.strategy === 'no_prefix' ? 'ssg_ignore' : 'normal',
callType: 'routing',
firstAccess: routeChangeCount === 0
firstAccess: routeChangeCount === 0,
localeCookie
}
)
__DEBUG__ && console.log('detect locale', locale)
Expand Down
5 changes: 2 additions & 3 deletions src/runtime/utils.ts
Expand Up @@ -18,7 +18,6 @@ import {
import {
wrapComposable,
detectBrowserLanguage,
getLocaleCookie,
callVueI18nInterfaces,
getVueI18nPropertyValue,
defineGetter,
Expand Down Expand Up @@ -179,7 +178,7 @@ export function detectLocale(
const initialLocale = isFunction(initialLocaleLoader) ? initialLocaleLoader() : initialLocaleLoader
__DEBUG__ && console.log('detectLocale: initialLocale -', initialLocale)

const { ssg, callType, firstAccess } = detectLocaleContext
const { ssg, callType, firstAccess, localeCookie } = detectLocaleContext
__DEBUG__ && console.log('detectLocale: (ssg, callType, firstAccess) - ', ssg, callType, firstAccess)

const {
Expand Down Expand Up @@ -232,7 +231,7 @@ export function detectLocale(
_detectBrowserLanguage
)
if (!finalLocale && _detectBrowserLanguage && _detectBrowserLanguage.useCookie) {
finalLocale = getLocaleCookie() || ''
finalLocale = localeCookie.value || ''
}

__DEBUG__ && console.log('detectLocale: finalLocale last (finalLocale, defaultLocale) -', finalLocale, defaultLocale)
Expand Down

0 comments on commit 61d5428

Please sign in to comment.