sitemap-module
sitemap-module copied to clipboard
i18n: dynamic routes not having language/locale variant
Version
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"
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 Thanks for that solution, it does the trick!
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?
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?
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.
@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.
@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 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
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'] }
]
}
}
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
}
])
}
})
}
}
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
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
}
},
}
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?
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' ]
~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}` },
],
})),
]
},
},