Skip to content

Commit

Permalink
fix: cannot redirect when call setLocale (#2307)
Browse files Browse the repository at this point in the history
* fix: cannot redirect when call setLocale

* fix: #2291

* fix: update lock file
  • Loading branch information
kazupon committed Aug 11, 2023
1 parent e33f15b commit 5fc06df
Show file tree
Hide file tree
Showing 14 changed files with 687 additions and 423 deletions.
874 changes: 472 additions & 402 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions specs/fixtures/issues/2288/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<template>
<div>
<NuxtLayout>
<nav>
<nuxt-link id="root" class="link" to="/"> / </nuxt-link>
<nuxt-link id="root-en" class="link" to="/en"> /en </nuxt-link>
<nuxt-link id="about-en" class="link" to="/en/about"> /en/about </nuxt-link>
<nuxt-link class="link" to="/about"> /about </nuxt-link>
<nuxt-link id="about-ar" class="link" to="/ar/about"> /ar/about </nuxt-link>
<nuxt-link id="example-ar" class="link" to="/ar/example"> /ar/example </nuxt-link>
<nuxt-link id="example-en" class="link" to="/en/example"> /en/example </nuxt-link>
<nuxt-link class="link" to="/example"> /example </nuxt-link>
</nav>

<br />
<br />
<br /><br />
<div>
Switch language
<button id="ar" @click="switchLanguage('ar')" style="margin-right: 10px">Arabic</button>
<button id="en" @click="switchLanguage('en')">English</button>
</div>

<br /><br />
<div>
<strong>Current path: </strong>
<code id="route-path">
{{ useRoute().path }}
</code>
</div>

<br />
<div>
<strong>Current locale: </strong>
<code>
{{ currentLocale }}
</code>
</div>

<br /><br /><br /><br />
<NuxtPage />
</NuxtLayout>
</div>
</template>

<script setup lang="ts">
const { setLocale, locale } = useI18n()
const currentLocale = computed(() => locale.value)
async function switchLanguage(lang) {
await setLocale(lang)
}
</script>

<style>
nav {
background-color: #eee;
padding: 10px;
}
.link {
padding: 15px;
}
</style>
3 changes: 3 additions & 0 deletions specs/fixtures/issues/2288/i18n/ar-ar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
title: 'مرحبا.. هذه اللغة العربية'
}
3 changes: 3 additions & 0 deletions specs/fixtures/issues/2288/i18n/en-en.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
title: 'Hello this is English'
}
4 changes: 4 additions & 0 deletions specs/fixtures/issues/2288/i18n/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import ar from './ar-ar'
import en from './en-en'

export default { ar, en }
5 changes: 5 additions & 0 deletions specs/fixtures/issues/2288/layouts/default.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div>
<slot />
</div>
</template>
30 changes: 30 additions & 0 deletions specs/fixtures/issues/2288/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// https://v3.nuxtjs.org/api/configuration/nuxt.config
export default defineNuxtConfig({
modules: ['@nuxtjs/i18n'],
i18n: {
baseUrl: 'https://abwaab.com',
locales: [
{
code: 'en',
country: '',
iso: 'en',
lang: 'en',
file: 'en-en.js',
dir: 'ltr'
},
{
code: 'ar',
country: '',
iso: 'ar',
lang: 'ar',
file: 'ar-ar.js',
dir: 'rtl'
}
],
strategy: 'prefix_and_default',
detectBrowserLanguage: false,
defaultLocale: 'ar',
lazy: true,
langDir: 'i18n/'
}
})
14 changes: 14 additions & 0 deletions specs/fixtures/issues/2288/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"name": "nuxt3-test-issues-2288",
"private": true,
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview"
},
"devDependencies": {
"@nuxtjs/i18n": "latest",
"nuxt": "latest"
}
}
5 changes: 5 additions & 0 deletions specs/fixtures/issues/2288/pages/about.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div>
{{ $t('title') }}
</div>
</template>
5 changes: 5 additions & 0 deletions specs/fixtures/issues/2288/pages/example.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<div>
{{ $t('title') }}
</div>
</template>
3 changes: 3 additions & 0 deletions specs/fixtures/issues/2288/pages/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<template>
<div>Home Page</div>
</template>
41 changes: 41 additions & 0 deletions specs/issues/2288.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { test, expect, describe } from 'vitest'
import { fileURLToPath } from 'node:url'
import { URL } from 'node:url'
import { setup, url, createPage } from '../utils'

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

test('change route with setLocale', async () => {
const home = url('/')
const page = await createPage()
await page.goto(home)

// goto to `/en/about`
await page.locator('#about-en').click()
await page.waitForTimeout(10)
expect(await page.url().endsWith('/en/about')).toBe(true)

// change to `ar`
await page.locator('#ar').click()
await page.waitForTimeout(10)
expect(await page.url().endsWith('/about')).toBe(true)

// change to `en`
await page.locator('#en').click()
await page.waitForTimeout(10)
expect(await page.url().endsWith('/en/about')).toBe(true)

// goto to `/ar/example`
await page.locator('#example-ar').click()
await page.waitForTimeout(10)
expect(await page.url().endsWith('/ar/example')).toBe(true)

// goto to `/en/example`
await page.locator('#example-en').click()
await page.waitForTimeout(10)
expect(await page.url().endsWith('/en/example')).toBe(true)
})
})
17 changes: 15 additions & 2 deletions src/runtime/plugins/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,13 @@ export default defineNuxtPlugin(async nuxt => {
notInitialSetup = false
}

const redirectPath = detectRedirect({ to: route }, nuxtContext, locale, getLocaleFromRoute, nuxtI18nOptions)
const redirectPath = detectRedirect({
route: { to: route },
context: nuxtContext,
targetLocale: locale,
routeLocaleGetter: getLocaleFromRoute,
nuxtI18nOptions
})
__DEBUG__ && console.log('redirectPath on setLocale', redirectPath)

await navigate(
Expand Down Expand Up @@ -445,7 +451,14 @@ export default defineNuxtPlugin(async nuxt => {
notInitialSetup = false
}

const redirectPath = detectRedirect({ to, from }, nuxtContext, locale, getLocaleFromRoute, nuxtI18nOptions)
const redirectPath = detectRedirect({
route: { to, from },
context: nuxtContext,
targetLocale: locale,
routeLocaleGetter: getLocaleFromRoute,
nuxtI18nOptions,
calledWithRoutng: true
})
__DEBUG__ && console.log('redirectPath on locale-changing middleware', redirectPath)

routeChangeCount++
Expand Down
44 changes: 25 additions & 19 deletions src/runtime/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,29 +271,43 @@ export function detectLocale<Context extends NuxtApp = NuxtApp>(
return finalLocale
}

export function detectRedirect<Context extends NuxtApp = NuxtApp>(
export function detectRedirect<Context extends NuxtApp = NuxtApp>({
route,
context,
targetLocale,
routeLocaleGetter,
nuxtI18nOptions,
calledWithRoutng = false
}: {
route: {
to: Route | RouteLocationNormalized | RouteLocationNormalizedLoaded
from?: Route | RouteLocationNormalized | RouteLocationNormalizedLoaded
},
context: Context,
targetLocale: Locale,
routeLocaleGetter: ReturnType<typeof createLocaleFromRouteGetter>,
}
context: Context
targetLocale: Locale
routeLocaleGetter: ReturnType<typeof createLocaleFromRouteGetter>
nuxtI18nOptions: DeepRequired<NuxtI18nOptions<Context>>
): string {
calledWithRoutng?: boolean
}): string {
const { strategy, differentDomains } = nuxtI18nOptions
__DEBUG__ && console.log('detectRedirect: targetLocale -> ', targetLocale)
__DEBUG__ && console.log('detectRedirect: route -> ', route)
__DEBUG__ && console.log('detectRedirect: calledWithRoutng -> ', calledWithRoutng, routeLocaleGetter(route.to))

let redirectPath = ''
const isStaticGenerate = isSSG && process.server

// decide whether we should redirect to a different route.
/**
* decide whether we should redirect to a different route.
*
* NOTE: #2288
* If this function is called directly (e.g setLocale) than routing,
* it must be processed regardless of the strategy. because the route is not switched.
*/
if (
!isStaticGenerate &&
!differentDomains &&
strategy !== 'no_prefix' &&
strategy !== 'prefix_and_default' &&
(calledWithRoutng || (strategy !== 'no_prefix' && strategy !== 'prefix_and_default')) &&
routeLocaleGetter(route.to) !== targetLocale
) {
const { fullPath } = route.to
Expand All @@ -310,7 +324,7 @@ export function detectRedirect<Context extends NuxtApp = NuxtApp>(
}
}

if (differentDomains || (isSSG && process.client)) {
if ((differentDomains || (isSSG && process.client)) && routeLocaleGetter(route.to) !== targetLocale) {
/**
* `$router.currentRoute` does not yet reflect the `to` value,
* when the Router middleware handler is executed.
Expand Down Expand Up @@ -349,15 +363,7 @@ type NavigateArgs = {
}

function _navigate(redirectPath: string, status: number) {
if (isSSG && process.client) {
/**
* When in the SSG, nuxt i18n module does not need to redirect in the route middleware (vue-router).
* If we overwrite them with `location.assign`, the route history will be broken.
*/
return
} else {
return navigateTo(redirectPath, { redirectCode: status })
}
return navigateTo(redirectPath, { redirectCode: status })
}

export async function navigate<Context extends NuxtApp = NuxtApp>(
Expand Down

0 comments on commit 5fc06df

Please sign in to comment.