Skip to content

Commit 61d5428

Browse files
authored
fix: setLocale throws error updating locale cookie from plugin (#2783)
1 parent 0e45dca commit 61d5428

File tree

11 files changed

+96
-43
lines changed

11 files changed

+96
-43
lines changed

specs/basic_usage.spec.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,3 @@ test('dynamic parameters', async () => {
355355
const product2dom = getDom(product2Html)
356356
expect(product2dom.querySelector('#i18n-alt-en').href).toEqual('/products/red-mug')
357357
})
358-
359-
test('(#2554) using `setLocale` in plugin should not throw an error', async () => {
360-
await expect($fetch('/?pluginSetLocale')).resolves.to.not.toThrowError()
361-
})

specs/fixtures/basic_usage/plugins/set-locale-plugin.ts

Lines changed: 0 additions & 8 deletions
This file was deleted.

specs/fixtures/issues/2554/app.vue

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
<NuxtPage />
3+
</template>
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export default defineNuxtConfig({
2+
modules: ['@nuxtjs/i18n'],
3+
i18n: {
4+
locales: ['en', 'fr'],
5+
strategy: 'no_prefix'
6+
}
7+
})
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"name": "nuxt3-test-issues-2473",
3+
"private": true,
4+
"scripts": {
5+
"build": "nuxt build",
6+
"dev": "nuxt dev",
7+
"generate": "nuxt generate",
8+
"preview": "nuxt preview"
9+
},
10+
"devDependencies": {
11+
"@nuxtjs/i18n": "latest",
12+
"nuxt": "latest"
13+
}
14+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<template>
2+
<div>Hello</div>
3+
</template>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { defineNuxtPlugin } from '#imports'
2+
3+
export default defineNuxtPlugin(async nuxtApp => {
4+
if ('pluginSetLocale' in nuxtApp._route.query && typeof nuxtApp._route.query.pluginSetLocale === 'string') {
5+
const app = useNuxtApp()
6+
await app.$i18n.setLocale(nuxtApp._route.query.pluginSetLocale)
7+
}
8+
})

specs/issues/2554.spec.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { test, expect, describe } from 'vitest'
2+
import { fileURLToPath } from 'node:url'
3+
import { URL } from 'node:url'
4+
import { setup, url } from '../utils'
5+
import { renderPage } from '../helper'
6+
7+
describe('#2554', async () => {
8+
await setup({
9+
rootDir: fileURLToPath(new URL(`../fixtures/issues/2554`, import.meta.url)),
10+
browser: true
11+
})
12+
13+
test('should not throw an error when using `setLocale` from plugin', async () => {
14+
const { page } = await renderPage('/')
15+
16+
const res1 = await page.goto(url('/?pluginSetLocale=fr'))
17+
expect(res1?.ok()).toBeTruthy()
18+
19+
const res2 = await page.goto(url('/?pluginSetLocale=en'))
20+
expect(res2?.ok()).toBeTruthy()
21+
})
22+
})

src/runtime/internal.ts

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { initCommonComposableOptions, type CommonComposableOptions } from './uti
2525
import type { Locale } from 'vue-i18n'
2626
import type { DetectBrowserLanguageOptions, LocaleObject } from '#build/i18n.options.mjs'
2727
import type { RouteLocationNormalized, RouteLocationNormalizedLoaded } from 'vue-router'
28+
import type { CookieRef } from 'nuxt/app'
2829

2930
export function formatMessage(message: string) {
3031
return NUXT_I18N_MODULE_ID + ' ' + message
@@ -93,7 +94,25 @@ export function getBrowserLocale(): string | undefined {
9394
return ret
9495
}
9596

96-
export function getLocaleCookie(): string | undefined {
97+
export function getI18nCookie() {
98+
const detect = nuxtI18nOptions.detectBrowserLanguage
99+
const cookieKey = (detect && detect.cookieKey) || nuxtI18nOptionsDefault.detectBrowserLanguage.cookieKey
100+
const date = new Date()
101+
const cookieOptions: Record<string, any> = {
102+
expires: new Date(date.setDate(date.getDate() + 365)),
103+
path: '/',
104+
sameSite: detect && detect.cookieCrossOrigin ? 'none' : 'lax',
105+
secure: (detect && detect.cookieCrossOrigin) || (detect && detect.cookieSecure)
106+
}
107+
108+
if (detect && detect.cookieDomain) {
109+
cookieOptions.domain = detect.cookieDomain
110+
}
111+
112+
return useNuxtCookie<string | undefined>(cookieKey, cookieOptions)
113+
}
114+
115+
export function getLocaleCookie(cookieRef: CookieRef<string | undefined>): string | undefined {
97116
const detect = nuxtI18nOptions.detectBrowserLanguage
98117

99118
__DEBUG__ &&
@@ -107,37 +126,22 @@ export function getLocaleCookie(): string | undefined {
107126
return
108127
}
109128

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

114132
if (localeCode && localeCodes.includes(localeCode)) {
115133
return localeCode
116134
}
117135
}
118136

119-
export function setLocaleCookie(locale: string) {
120-
const { useCookie, cookieKey, cookieDomain, cookieSecure, cookieCrossOrigin } =
121-
nuxtI18nOptions.detectBrowserLanguage || nuxtI18nOptionsDefault.detectBrowserLanguage
137+
export function setLocaleCookie(cookieRef: CookieRef<string | undefined>, locale: string) {
138+
const { useCookie } = nuxtI18nOptions.detectBrowserLanguage || nuxtI18nOptionsDefault.detectBrowserLanguage
122139

123140
if (!useCookie) {
124141
return
125142
}
126143

127-
const date = new Date()
128-
const cookieOptions: Record<string, any> = {
129-
expires: new Date(date.setDate(date.getDate() + 365)),
130-
path: '/',
131-
sameSite: cookieCrossOrigin ? 'none' : 'lax',
132-
secure: cookieCrossOrigin || cookieSecure
133-
}
134-
135-
if (cookieDomain) {
136-
cookieOptions.domain = cookieDomain
137-
}
138-
139-
const localeCookie = useNuxtCookie(cookieKey, cookieOptions)
140-
localeCookie.value = locale
144+
cookieRef.value = locale
141145
}
142146

143147
export type DetectBrowserLanguageNotDetectReason =
@@ -160,6 +164,7 @@ export type DetectLocaleContext = {
160164
ssg: DetectLocaleForSSGStatus
161165
callType: DetectLocaleCallType
162166
firstAccess: boolean
167+
localeCookie: CookieRef<string | undefined>
163168
}
164169

165170
export const DefaultDetectBrowserLanguageFromResult: DetectBrowserLanguageFromResult = {
@@ -176,7 +181,7 @@ export function detectBrowserLanguage(
176181
locale: Locale = ''
177182
): DetectBrowserLanguageFromResult {
178183
const { strategy } = nuxtI18nOptions
179-
const { ssg, callType, firstAccess } = detectLocaleContext
184+
const { ssg, callType, firstAccess, localeCookie } = detectLocaleContext
180185
__DEBUG__ && console.log('detectBrowserLanguage: (ssg, callType, firstAccess) - ', ssg, callType, firstAccess)
181186

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

224229
// get preferred language from cookie if present and enabled
225230
if (useCookie) {
226-
matchedLocale = cookieLocale = getLocaleCookie()
231+
matchedLocale = cookieLocale = localeCookie.value
227232
localeFrom = 'cookie'
228233
__DEBUG__ && console.log('detectBrowserLanguage: cookieLocale', cookieLocale)
229234
}

src/runtime/plugins/i18n.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import {
2525
getLocaleCookie as _getLocaleCookie,
2626
setLocaleCookie as _setLocaleCookie,
2727
detectBrowserLanguage,
28-
DefaultDetectBrowserLanguageFromResult
28+
DefaultDetectBrowserLanguageFromResult,
29+
getI18nCookie
2930
} from '../internal'
3031
import { getComposer, getLocale, setLocale } from '../routing/utils'
3132
import { extendI18n, createLocaleFromRouteGetter } from '../routing/extends'
@@ -68,6 +69,7 @@ export default defineNuxtPlugin({
6869
const getLocaleFromRoute = createLocaleFromRouteGetter()
6970
const getDefaultLocale = (defaultLocale: string) => defaultLocale || vueI18nOptions.locale || 'en-US'
7071

72+
const localeCookie = getI18nCookie()
7173
// detect initial locale
7274
let initialLocale = detectLocale(
7375
route,
@@ -77,7 +79,8 @@ export default defineNuxtPlugin({
7779
{
7880
ssg: isSSG && nuxtI18nOptions.strategy === 'no_prefix' ? 'ssg_ignore' : 'normal',
7981
callType: 'setup',
80-
firstAccess: true
82+
firstAccess: true,
83+
localeCookie
8184
}
8285
)
8386
__DEBUG__ && console.log('first detect initial locale', initialLocale)
@@ -124,7 +127,7 @@ export default defineNuxtPlugin({
124127
? detectBrowserLanguage(
125128
route,
126129
vueI18nOptions.locale,
127-
{ ssg: 'ssg_setup', callType: 'setup', firstAccess: true },
130+
{ ssg: 'ssg_setup', callType: 'setup', firstAccess: true, localeCookie },
128131
initialLocale
129132
)
130133
: DefaultDetectBrowserLanguageFromResult
@@ -187,8 +190,8 @@ export default defineNuxtPlugin({
187190
composer.differentDomains = nuxtI18nOptions.differentDomains
188191
composer.defaultLocale = nuxtI18nOptions.defaultLocale
189192
composer.getBrowserLocale = () => _getBrowserLocale()
190-
composer.getLocaleCookie = () => _getLocaleCookie()
191-
composer.setLocaleCookie = (locale: string) => _setLocaleCookie(locale)
193+
composer.getLocaleCookie = () => _getLocaleCookie(localeCookie)
194+
composer.setLocaleCookie = (locale: string) => _setLocaleCookie(localeCookie, locale)
192195

193196
composer.onBeforeLanguageSwitch = (oldLocale, newLocale, initialSetup, context) =>
194197
nuxt.callHook('i18n:beforeLocaleSwitch', { oldLocale, newLocale, initialSetup, context })
@@ -394,7 +397,8 @@ export default defineNuxtPlugin({
394397
{
395398
ssg: isSSGModeInitialSetup() && nuxtI18nOptions.strategy === 'no_prefix' ? 'ssg_ignore' : 'normal',
396399
callType: 'routing',
397-
firstAccess: routeChangeCount === 0
400+
firstAccess: routeChangeCount === 0,
401+
localeCookie
398402
}
399403
)
400404
__DEBUG__ && console.log('detect locale', locale)

0 commit comments

Comments
 (0)