nuxt-modules / i18n

I18n module for Nuxt
https://i18n.nuxtjs.org
MIT License
1.75k stars 483 forks source link

Dynamic Links in Subfolders not Working Properly with Routes #3077

Closed d-kirkland closed 1 month ago

d-kirkland commented 2 months ago

Hi. I have a problem with dynamic links in subfolders in the pages directory. I have gone through the documentation a number of times, and I have not been able to solve this, so I am posting the question here. I have a repository with the problem here: https://github.com/d-kirkland/i18n-dynamic-link-problem

The problem: I have a link on the index.vue page that should direct to pages/customers/challenges/[slug].vue. I have set up the routes like so:

'customer/challenges/[slug]': {
        en: '/customers/challenges/[slug]',
        de: '/kunden/challenges/[slug]',
    },

And the link looks like this:

<NuxtLink :to="localePath({ name: 'customers-challenges-slug', params: { slug: currentRoute }})"> {{ t('links.challenge') }} </NuxtLink>

The problem is that when I click on the link when I am the EN locale, I am directed to /en/customers/challenges/food. That is not a problem, but when I click on the link in the DE locale, I am directed to /de/customers/challenges/lebensmittel. This is where the problem is. I would expect the link in the DE locale to link to /de/kunden/challenges/lebensmittel. NuxtLink/localePath is picking up the slug, but it is not getting the route correct. I have provided all of the content of the files, and the link to the repository is above. Is there something that I am doing wrong?

Here is the index.vue page:

script setup lang="ts">
    const { localeProperties, setLocale } = useI18n()
    const localePath = useLocalePath()
    const { t } = useI18n({ inheritLocale: true })
    const source = {
        en: {
            route: 'food'
        },
        de: {
            route: 'lebensmittel'
        }
    }
    const code = localeProperties.value.code
    const currentRoute = computed(() => {
        if (localeProperties.value.code === 'de') return source.de.route
        else return source.en.route
    })
</script>

<template>
    <div>
        <div class="flex justify-center my-6">
            <NuxtLink :to="localePath({ name: 'customers-challenges-slug', params: { slug: currentRoute }})">{{ t('link.name') }}</NuxtLink>
        </div>
        <div class="flex justify-center my-10 gap-x-10">
            <button @click="setLocale('en')">en</button>
            <button @click="setLocale('de')">de</button>
        </div>
    </div>
</template>

<i18n lang="yaml">
    en:
        link: 
            name: Challenges
    de:
        link: 
            name: Herausforderungen
</i18n>

I am pulling the data in from a headless CMS, so the source object is meant as a substitute from data from the CMS.

There is then a pages/customers/challenges/[slug].vue page that looks like this:

<script setup lang="ts">
    const { t } = useI18n({ inheritLocale: true })
</script>

<template>
    <h1>{{ t('welcome')}}</h1>
</template>

<i18n lang="yaml">
    en: 
        welcome: Welcome to the Challenge 
    de:
        welcome: Willkommen zur Herausforderung
</i18n>

Then the nuxt.config.ts file:

import pages from './locales/routes'

export default defineNuxtConfig({
    compatibilityDate: '2024-04-03',
    devtools: { enabled: true },
    modules: [
        '@nuxtjs/i18n',
        '@nuxtjs/tailwindcss',
    ],
    i18n: {
        locales: [
            {
                code: 'en',
                iso: 'en-DE',
                languageCode: 'EN',
                countryCode: 'US',
                regionCode: 'EU',
                countryName: 'United States',
                currency: 'EUR',
            },
            {
                code: 'de',
                iso: 'de-DE',
                languageCode: 'DE',
                countryCode: 'DE',
                regionCode: 'EU',
                countryName: 'Deutschland',
                currency: 'EUR',
            },
        ],
        defaultLocale: 'en',
        strategy: 'prefix',
        detectBrowserLanguage: false,
        pages: pages,
        customRoutes: 'config',
    },
})

And then the locales/routes/index.js file:

const pages = {
    'index': {
        en: '/',
        de: '/',
    },
    'customer/challenges/index': {
        en: '/customers/challenges',
        de: '/kunden/challenges',
    },
    'customer/challenges/[slug]': {
        en: '/customers/challenges/[slug]',
        de: '/kunden/challenges/[slug]',
    },
}
export default pages;

package.json:

{
  "name": "nuxt-app",
  "private": true,
  "type": "module",
  "scripts": {
    "build": "nuxt build",
    "dev": "nuxt dev",
    "generate": "nuxt generate",
    "preview": "nuxt preview",
    "postinstall": "nuxt prepare"
  },
  "dependencies": {
    "@nuxtjs/i18n": "^8.5.1",
    "nuxt": "^3.13.0",
    "vue": "latest"
  },
  "packageManager": "pnpm@8.15.6+sha1.8105075ad0aa306138be128c017e9c41e28ecffa",
  "devDependencies": {
    "@nuxtjs/tailwindcss": "^6.12.1"
  }
}
BobbieGoede commented 1 month ago

The issue in your reproduction appears to be that you're not using the route names in the pages configuration object, so the custom route paths are not applied.

const pages = {
    'index': {
        en: '/',
        de: '/',
    },
    // use route name
-  'customer/challenges/index': {
+  'customers-challenges': {
        en: '/customers/challenges',
        de: '/kunden/challenges',
    },
    // use route name
-   'customer-challenges-slug': {
+   'customers-challenges-slug': {
        en: '/customers/challenges/[slug]',
        de: '/kunden/challenges/[slug]',
    },
}
export default pages;

Sorry for the late response! Perhaps you already resolved this issue on your own, but if you have any questions let me know and I'll reopen this issue šŸ™