Skip to content

Commit

Permalink
fix: update globalLocaleRoutes logic
Browse files Browse the repository at this point in the history
  • Loading branch information
s00d committed Sep 27, 2024
1 parent 3478b2b commit 6346d73
Show file tree
Hide file tree
Showing 15 changed files with 187 additions and 73 deletions.
13 changes: 7 additions & 6 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export default defineNuxtModule<ModuleOptions>({
dateBuild: Date.now(),
baseURL: nuxt.options.app.baseURL,
hashMode: nuxt.options?.router?.options?.hashMode ?? false,
globalLocaleRoutes: options.globalLocaleRoutes ?? {},
}
nuxt.options.runtimeConfig.i18nConfig = {
rootDir: nuxt.options.rootDir,
Expand Down Expand Up @@ -134,12 +135,12 @@ export default defineNuxtModule<ModuleOptions>({

addImportsDir(resolver.resolve('./runtime/composables'))

if (options.includeDefaultLocaleRoute) {
addServerHandler({
middleware: true,
handler: resolver.resolve('./runtime/server/middleware/i18n-redirect'),
})
}
// if (options.includeDefaultLocaleRoute) {
// addServerHandler({
// middleware: true,
// handler: resolver.resolve('./runtime/server/middleware/i18n-redirect'),
// })
// }

addServerHandler({
route: '/_locales/:page/:locale/data.json',
Expand Down
9 changes: 9 additions & 0 deletions src/runtime/plugins/01.plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,15 @@ function getLocalizedRoute(
})
}

if (i18nConfig.includeDefaultLocaleRoute) {
const globalLocaleRoutes = i18nConfig.globalLocaleRoutes ?? {}
if (globalLocaleRoutes[routeName] == false) {
const newParams = resolveParams(to)
delete newParams.locale
return router.resolve({ name: routeName, params: newParams })
}
}

// Determine the new route name based on locale and configuration
const newRouteName
= currentLocale !== i18nConfig.defaultLocale || i18nConfig.includeDefaultLocaleRoute
Expand Down
63 changes: 42 additions & 21 deletions src/runtime/plugins/03.define.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { RouteLocationNormalizedLoaded } from 'vue-router'
import type { ModuleOptionsExtend } from '../../types'
import type { Translations } from '../plugins/01.plugin'
import { defineNuxtPlugin, navigateTo, useNuxtApp, useRuntimeConfig } from '#app'
Expand All @@ -6,12 +7,13 @@ import { useRoute, useRouter } from '#imports'
// Тип для локалей
type LocalesObject = Record<string, Translations>

export default defineNuxtPlugin((_nuxtApp) => {
export default defineNuxtPlugin(async (_nuxtApp) => {
const config = useRuntimeConfig()
const route = useRoute()
const router = useRouter()

const i18nConfig: ModuleOptionsExtend = config.public.i18nConfig as ModuleOptionsExtend
const globalLocaleRoutes = i18nConfig.globalLocaleRoutes ?? {}

// Функция нормализации, которая объединяет массивы и объекты в единый массив строк
const normalizeLocales = (locales?: string[] | LocalesObject): LocalesObject => {
Expand All @@ -29,29 +31,44 @@ export default defineNuxtPlugin((_nuxtApp) => {
return {}
}

useRouter().beforeEach(async (to, from, next) => {
if (i18nConfig.includeDefaultLocaleRoute) {
const currentLocale = (to.params.locale || i18nConfig.defaultLocale!).toString()
const { name } = to
// Логика для редиректа по умолчанию, используем как на сервере, так и на клиенте
const handleRedirect = async (to: RouteLocationNormalizedLoaded) => {
const currentLocale = (to.params.locale || i18nConfig.defaultLocale!).toString()
const { name } = to

let defaultRouteName = name?.toString()
.replace('localized-', '')
.replace(new RegExp(`-${currentLocale}$`), '')
let defaultRouteName = name?.toString()
.replace('localized-', '')
.replace(new RegExp(`-${currentLocale}$`), '')

if (!to.params.locale) {
if (router.hasRoute(`localized-${to.name?.toString()}-${currentLocale}`)) {
defaultRouteName = `localized-${to.name?.toString()}-${currentLocale}`
}
else {
defaultRouteName = `localized-${to.name?.toString()}`
}

const newParams = { ...to.params }
newParams.locale = i18nConfig.defaultLocale!
newParams.name = defaultRouteName
if (!to.params.locale) {
const name = to.name?.toString() ?? ''
if (globalLocaleRoutes[name] === false) {
return
}

await navigateTo({ name: defaultRouteName, params: newParams }, { redirectCode: 301, external: true })
if (router.hasRoute(`localized-${to.name?.toString()}-${currentLocale}`)) {
defaultRouteName = `localized-${to.name?.toString()}-${currentLocale}`
}
else {
defaultRouteName = `localized-${to.name?.toString()}`
}

const newParams = { ...to.params }
newParams.locale = i18nConfig.defaultLocale!

return navigateTo({ name: defaultRouteName, params: newParams }, { redirectCode: 301, external: true })
}
}

if (import.meta.server) {
if (i18nConfig.includeDefaultLocaleRoute) {
await handleRedirect(route)
}
}

router.beforeEach(async (to, from, next) => {
if (i18nConfig.includeDefaultLocaleRoute) {
await handleRedirect(to)
}
next()
})
Expand All @@ -72,7 +89,7 @@ export default defineNuxtPlugin((_nuxtApp) => {
nuxtApp.$mergeTranslations(translation)
}

// Если текущей локали есть в объекте locales
// Если текущей локали нет в объекте locales
if (!normalizedLocales[currentLocale]) {
let defaultRouteName = route.name?.toString()
.replace('localized-', '')
Expand All @@ -82,6 +99,10 @@ export default defineNuxtPlugin((_nuxtApp) => {
delete newParams.locale

if (i18nConfig.includeDefaultLocaleRoute) {
const name = route.name?.toString() ?? ''
if (globalLocaleRoutes[name] === false) {
return
}
if (router.hasRoute(`localized-${defaultRouteName}-${currentLocale}`)) {
defaultRouteName = `localized-${defaultRouteName}-${currentLocale}`
}
Expand Down
40 changes: 0 additions & 40 deletions src/runtime/server/middleware/i18n-redirect.ts

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/dynamic/locales/pages/index/de.json

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/dynamic/locales/pages/index/en.json

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/dynamic/locales/pages/index/ru.json

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/dynamic/locales/pages/page/de.json

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/dynamic/locales/pages/page/en.json

This file was deleted.

1 change: 0 additions & 1 deletion test/fixtures/dynamic/locales/pages/page/ru.json

This file was deleted.

8 changes: 8 additions & 0 deletions test/fixtures/undefault/nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ export default defineNuxtConfig({
routesLocaleLinks: {
'dir1-slug': 'index',
},
globalLocaleRoutes: {
page2: {
en: '/custom-page2-en',
de: '/custom-page2-de',
ru: '/custom-page2-ru',
},
unlocalized: false, // Unlocalized page should not be localized
},
},

compatibilityDate: '2024-08-16',
Expand Down
20 changes: 20 additions & 0 deletions test/fixtures/undefault/pages/page2.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<template>
<div>
<h1>Subpage with route param</h1>
<p>{{ useRoute().params.id }}</p>
<NuxtLink to="/">
Home
</NuxtLink>

<hr>

<NuxtLink
id="unlocalized"
:to="$localeRoute({ name: 'unlocalized' })"
>
unlocalized
</NuxtLink>
</div>
</template>
<script setup lang="ts">

Check failure on line 19 in test/fixtures/undefault/pages/page2.vue

View workflow job for this annotation

GitHub Actions / lint

Expected blank line before this block
</script>
52 changes: 52 additions & 0 deletions test/fixtures/undefault/pages/unlocalized.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<template>
<div>
<p id="content">
{{ $t('page.content') }}
</p>
<p id="locale">
Current Locale: {{ $getLocale() }}
</p>

<!-- Display additional info for testing -->
<p id="locales">
{{ $getLocales().map(locale => locale.code).join(', ') }}
</p>

<!-- Links for switching locales -->
<div id="locale-links">
<NuxtLink
id="link-en"
:to="$localeRoute({ name: 'page2' }, 'en')"
>
Switch to English
</NuxtLink>
<NuxtLink
id="link-de"
:to="$localeRoute({ name: 'page2' }, 'de')"
>
Switch to German
</NuxtLink>
</div>
</div>
</template>

<script setup>
import { useNuxtApp } from '#imports'
const { $t, $getLocale, $getLocales, $tc, $localeRoute } = useNuxtApp()

Check failure on line 36 in test/fixtures/undefault/pages/unlocalized.vue

View workflow job for this annotation

GitHub Actions / lint

'$tc' is assigned a value but never used. Allowed unused vars must match /^_/u
const customPluralRule = (key, count, _locale, t) => {

Check failure on line 38 in test/fixtures/undefault/pages/unlocalized.vue

View workflow job for this annotation

GitHub Actions / lint

'customPluralRule' is assigned a value but never used. Allowed unused vars must match /^_/u
const translation = t(key)
if (!translation) {
return null
}
const forms = translation.toString().split('|')
if (count === 0 && forms.length > 2) {
return forms[0].trim() // Case for "no apples"
}
if (count === 1 && forms.length > 1) {
return forms[1].trim() // Case for "one apple"
}
return (forms.length > 2 ? forms[2].trim() : forms[forms.length - 1].trim()).replace('{count}', count.toString())
}
</script>
4 changes: 4 additions & 0 deletions test/redirect.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ test.use({
nuxt: {
rootDir: fileURLToPath(new URL('./fixtures/redirect', import.meta.url)),
},
// launchOptions: {
// headless: false, // Показывать браузер
// slowMo: 500, // Замедлить выполнение шагов (в миллисекундах) для лучшей видимости
// },
})

test('test language detection and redirect based on navigator.languages', async ({ page, goto }) => {
Expand Down
45 changes: 45 additions & 0 deletions test/undefault.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { fileURLToPath } from 'node:url'
import { expect, test } from '@nuxt/test-utils/playwright'

test.use({
nuxt: {
rootDir: fileURLToPath(new URL('./fixtures/undefault', import.meta.url)),
},
// launchOptions: {
// headless: false, // Показывать браузер
// slowMo: 500, // Замедлить выполнение шагов (в миллисекундах) для лучшей видимости
// },
})

// Тест для английского языка
test('test redirection and link clicks in English', async ({ page, goto }) => {
await goto('/', { waitUntil: 'hydration' })
// Переход на страницу /page2, должно произойти редирект на /en/custom-page2-en
await goto('/page2', { waitUntil: 'hydration' })

await expect(page).toHaveURL('/en/custom-page2-en')

// Клик по ссылке 'unlocalized', должно редиректнуть на /unlocalized
await page.click('#unlocalized')
await expect(page).toHaveURL('/unlocalized')

// Клик по ссылке 'page2', должно вернуться на /en/custom-page2-en
await page.click('#link-en')
await expect(page).toHaveURL('/en/custom-page2-en')
})

// Тест для немецкого языка
test('test redirection and link clicks in German', async ({ page, goto }) => {
await goto('/', { waitUntil: 'hydration' })
// Переход на страницу /page2, должно произойти редирект на /de/custom-page2-de
await goto('/de/custom-page2-de', { waitUntil: 'hydration' })
await expect(page).toHaveURL('/de/custom-page2-de')

// Клик по ссылке 'unlocalized', должно редиректнуть на /unlocalized
await page.click('#unlocalized')
await expect(page).toHaveURL('/unlocalized')

// Клик по ссылке 'page2', должно вернуться на /en/custom-page2-en
await page.click('#link-de')
await expect(page).toHaveURL('/de/custom-page2-de')
})

0 comments on commit 6346d73

Please sign in to comment.