sitemap-module icon indicating copy to clipboard operation
sitemap-module copied to clipboard

i18n: dynamic routes not having language/locale variant

Open miteyema opened this issue 5 years ago • 15 comments

Version

2.3.0

Reproduction link

https://github.com/miteyema/nuxt-i18n-demo

Steps to reproduce

Add i18n Add sitemap Configure both according to doc

What is expected ?

  • the dynamic routes show xhtml:link rel="alternate" for all locales

What is actually happening?

  • the dynamic routes do not show xhtml:link rel="alternate"
This bug report is available on Nuxt community (#c94)

miteyema avatar May 19 '20 00:05 miteyema

Yes, that's a good point 🤔

Currently the sitemap-module supports i18n routes from the nuxt-i18n module, but as before only for the static routes... (see features list)

As workaround, you can generate manually your dynamics routes with the links attribute as follows:

// nuxt.config.js

  i18n: {
    locales: ['en', 'de', 'fr'],
    defaultLocale: 'en',
  },
  sitemap: [
    {
      i18n: 'en',
      routes: [
        {
          url: 'test',
          links: ['en', 'fr', 'de'].map((lang) => ({ lang, url: `${lang}/test` })),
        },
      ],
    },

I will try to check deeper in the code of nux-i18n to find an easier solution.

NicoPennec avatar May 25 '20 07:05 NicoPennec

@NicoPennec Thanks for that solution, it does the trick!

miteyema avatar Jun 08 '20 00:06 miteyema

Thanks for your suggestion @NicoPennec. I'm not sure this would work in our case as we currently have over 4000 dynamic routes.

What about simply using localePath (https://nuxt-community.github.io/nuxt-i18n/api/#localepath) for each of the active languages?

Or what challenges do you foresee currently regarding this implementation?

simplenotezy avatar Jun 16 '20 08:06 simplenotezy

I think https://github.com/nuxt-community/sitemap-module/issues/140 will complicate @NicoPennec solution when handling dynamic routes... Isn't there a solution for dynamic routes using the nuxt crawler?

miteyema avatar Jun 30 '20 00:06 miteyema

I think #140 will complicate @NicoPennec solution when handling dynamic routes... Isn't there a solution for dynamic routes using the nuxt crawler?

Still works the same as before for me.

ems1985 avatar Jun 30 '20 06:06 ems1985

@miteyema the #140 respect the sitemap specs. It's a fact.

I started to experiment with the new "static" mode and its crawler. But it is not "magic"... the crawler is not a soothsayer. It parses the html page content of each generated page to find all the anchors with a link to another page <a href="/another-page">. So It cannot therefore find all the dynamic routes, but only those exposed on the html content. It's not the solution.

NicoPennec avatar Jun 30 '20 07:06 NicoPennec

@ems1985 @NicoPennec I meant that the given workaround on this issue does not solve what has been solved for https://github.com/nuxt-community/sitemap-module/issues/140. I just wanted to link both issues and think if nuxt crawler could help us out.

So It cannot therefore find all the dynamic routes, but only those exposed on the html content. It's not the solution.

That would already be awesome with all "exposed" dynamic routes. Why would you need links in a sitemap that appear nowhere in the html content of the site?

miteyema avatar Jun 30 '20 08:06 miteyema

@miteyema i believe that's the whole purpose of a sitemap. Nevertheless, I'd prefer not to stick with the crawler approach. just fetch the URLs from generate.routes

simplenotezy avatar Jun 30 '20 09:06 simplenotezy

I also think the crawler approach is not the best way to go.

For example, when working with nuxt generate, you have to specify your routes anyways in the generate.routes property of nuxt.config.js (https://nuxtjs.org/api/configuration-generate/#routes).

So I also think the way to go would be to change generate.routes in such a way that it not only accepts an array of strings, but also objects.

Currently it works as follows:

export default {
  generate: {
    routes: [
      '/users/1',
      '/de/users/1',
      '/users/2',
      '/de/users/2',
    ]
  }
}

In the future, in addition to the legacy approach it should accept also something like this:

export default {
  generate: {
    routes: [
      { route: '/users/1', locales: ['en', 'de'] },
      { route: '/users/2', locales: ['en', 'de'] }
    ]
  }
}

ems1985 avatar Jun 30 '20 09:06 ems1985

static export with crawler + i18n with prefix_except_default + manual work. It looks inconvenient but makes the sitemap the way I want it. 😅

sitemap: {
  hostname: BASE_URL,
  i18n: true,
  routes: async () => {
    const { $content } = require('@nuxt/content')
    const articles = await $content('/', { deep: true })
      .only(['path', 'slug'])
      .fetch()
    return articles.map((article) => ({
      url: article.path.split('/')[1] === 'en' ? article.slug : article.path,
      links: [
        { lang: 'en', url: article.slug },
        { lang: 'tr', url: `tr/${article.slug}` },
        { lang: 'x-default', url: article.slug }
      ]
    }))
  },
  filter({ routes }) {
    return routes.map((route) => {
      if (!route.name) return route
      const page = route.name.split('__')[0]
      return {
        url: route.url,
        links: route.links.concat([
          {
            lang: 'x-default',
            url: page === 'index' ? '/' : page
          }
        ])
      }
    })
  }
}

atemiz avatar Jul 16 '20 12:07 atemiz

  i18n: {
    locales: [
      { name: '简体中文', code: 'zh', iso: 'zh-CN', file: 'zh.js' },
      { name: 'English', code: 'en', iso: 'en-US', file: 'en.js' }
    ],
    strategy: 'prefix',
    rootRedirect: 'zh',
    defaultLocale: 'zh',
    lazy: true,
    langDir: 'i18n/',
    seo: true,
    detectBrowserLanguage: {
      useCookie: true,
      cookieKey: 'i18n_redirected'
    },
    vueI18n: {
      fallbackLocale: 'zh'
    }
  },
  sitemap: {
    hostname: 'https://hanzi.press',
    i18n: true
  }

sitemap generated:

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:mobile="http://www.google.com/schemas/sitemap-mobile/1.0" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
  <url>
    <loc>https://hanzi.press/about</loc>
  </url>
  <url>
    <loc>https://hanzi.press/ar</loc>
  </url>
  <url>
    <loc>https://hanzi.press/card</loc>
  </url>
  <url>
    <loc>https://hanzi.press/story</loc>
  </url>
  <url>
    <loc>https://hanzi.press/surround</loc>
  </url>
  <url>
    <loc>https://hanzi.press/</loc>
  </url>
</urlset>

i have no idea about this problem

willin avatar Aug 24 '20 06:08 willin

Having the same problem as @willin. Any teporarely solution to this?

sitemap: {
    hostname: 'https://ilanvivanco.com',
    i18n: true
},
i18n: {
    locales: [
    {
      code: 'es',
      iso: 'es-ES',
      name: 'Español',
      icon: 'svg/flag-es.svg'
    },
    {
      code: 'en',
      iso: 'en-US',
      name: 'English',
      icon: 'svg/flag-en.svg'
    },
    ],
    defaultLocale: 'es',
    detectBrowserLanguage: false,
    vueI18n: {
    fallbackLocale: 'es',
    messages: {
        en: enUS,
        es: esAR
      }
    },
}

IlanVivanco avatar Feb 28 '21 13:02 IlanVivanco

Hello,

are there any news about this issue?

Is it right that I have to define all links for all available languages like this:

routes.push({
  url: '/artikel/'+article.slug,
  links: [
    {
      lang: 'de',
      url: '/artikel/'+article.slug,
    },
    {
      lang: 'en',
      url: '/articles/'+article.slug,
    },
  ],
});

routes.push({
  url: '/articles/'+article.slug,
  links: [
    {
      lang: 'de',
      url: '/artikel/'+article.slug,
    },
    {
      lang: 'en',
      url: '/articles/'+article.slug,
    },
  ],
});

Is this the only way to handle this or is there an more elegant approach, maybe with localPath, named routes or something?

iparker avatar Mar 23 '21 04:03 iparker

I had the same issue as @willin and @IlanVivanco, was resolved by moving the declaration of the @nuxtjs/sitemap to after the declaration of the nuxt-i18n module:

modules: [ 'nuxt-i18n', '@nuxtjs/sitemap' ]

avatarbabe avatar Jun 30 '21 12:06 avatarbabe

~Unfortunately, that was the way I had this set up already.~

Edit: After bumping to 6.27.2 this seems to be resolved.

This is what my config looks like now:

sitemap: {
hostname: ENV.base_url,
i18n: {
  locales: ['en', 'es'],
  defaultLocale: 'es',
},

routes: async () => {
  const { $content } = require('@nuxt/content')
  const postsES = await $content(`es/blog`).only(['path', 'slug', 'languages']).where({ show: true }).fetch()
  
  return [
    ...postsES.map((article) => ({
      url: article.path.replace('/es/', '/'),
      links: [
        { lang: 'es', url: `/blog/${article.slug}` },
        { lang: 'en', url: `/en/blog/${article.slug}` },
      ],
    })),
  ]
},
},

IlanVivanco avatar Jul 01 '21 18:07 IlanVivanco