Skip to content

Commit

Permalink
fix: generate an <url> for each i18n language available
Browse files Browse the repository at this point in the history
The "sitemap.i18n.defaultLocale" option is no longer needed.

fix #140
  • Loading branch information
NicoPennec committed Jun 25, 2020
1 parent 74d4b9f commit b6d79c8
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 60 deletions.
15 changes: 13 additions & 2 deletions README.md
Expand Up @@ -373,10 +373,9 @@ Example:
sitemap: {
hostname: 'https://example.com',
// shortcut notation (basic)
i18n: 'en',
i18n: true,
// nuxt-i18n notation (advanced)
i18n: {
defaultLocale: 'en',
locales: ['en', 'es', 'fr'],
routesNameSeparator: '___'
}
Expand All @@ -391,6 +390,18 @@ Example:
<xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/"/>
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>
</url>
<url>
<loc>https://example.com/es/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/"/>
<xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/"/>
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>
</url>
<url>
<loc>https://example.com/fr/</loc>
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/"/>
<xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/"/>
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>
</url>
```

### `defaults` (optional) - object
Expand Down
60 changes: 29 additions & 31 deletions lib/builder.js
Expand Up @@ -44,52 +44,50 @@ function createSitemap(options, routes, base = null, req = null) {
})
}

// Group each route with its alternative languages
// Add alternate i18n routes
if (options.i18n) {
const { defaultLocale, locales, routesNameSeparator } = options.i18n
const { locales, routesNameSeparator } = options.i18n

// Set alternate routes for each page
const i18nRoutes = routes.reduce((i18nRoutes, route, index) => {
routes.reduce((i18nRoutes, route) => {
if (!route.name) {
// Route without alternate link
i18nRoutes[`#${index}`] = route
return i18nRoutes
}

let [page, lang, isDefault] = route.name.split(routesNameSeparator) // eslint-disable-line prefer-const
const [page, lang, isDefault = false] = route.name.split(routesNameSeparator)

// Get i18n route, or init it
const i18nRoute = i18nRoutes[page] || { ...route }

if (lang) {
// Set main link
if (isDefault) {
lang = 'x-default'
}
if (lang === defaultLocale) {
i18nRoute.url = route.url
}
if (!lang) {
return i18nRoutes
}

// Set alternate links
if (!i18nRoute.links) {
i18nRoute.links = []
// Init alternate route
const link = {
lang,
url: join('.', route.url),
}
if (isDefault) {
link.lang = 'x-default'
} else {
const locale = locales.find(({ code }) => code === lang)
if (locale && locale.iso) {
link.lang = locale.iso
}
}

const locale = locales.find(({ code }) => code === lang) || { iso: lang }
i18nRoute.links.push({
lang: locale.iso,
url: join('.', route.url),
})
} else {
// No alternate link found
i18nRoute.url = route.url
// Group alternate routes by page and sorted by lang
if (!i18nRoutes[page]) {
i18nRoutes[page] = []
}
const langs = i18nRoutes[page].map(({ lang }) => lang)
langs.push(link.lang)
const index = langs.sort().indexOf(link.lang)
i18nRoutes[page].splice(index, 0, link)

// Set alternate routes
route.links = i18nRoutes[page]

i18nRoutes[page] = i18nRoute
return i18nRoutes
}, {})

routes = Object.values(i18nRoutes)
}

// Enable the custom filter function for each declared route
Expand Down
9 changes: 4 additions & 5 deletions lib/options.js
Expand Up @@ -16,6 +16,7 @@ function setDefaultSitemapOptions(options, nuxtInstance, isLinkedToSitemapIndex
const defaults = {
path: '/sitemap.xml',
hostname:
// TODO: remove support of "build.publicPath" on release 3.0
nuxtInstance.options.build.publicPath !== DEFAULT_NUXT_PUBLIC_PATH
? nuxtInstance.options.build.publicPath
: undefined,
Expand Down Expand Up @@ -48,16 +49,14 @@ function setDefaultSitemapOptions(options, nuxtInstance, isLinkedToSitemapIndex
)
}

// Shortcut notation
/* istanbul ignore if */
if (typeof sitemapOptions.i18n === 'string') {
sitemapOptions.i18n = {
defaultLocale: sitemapOptions.i18n,
}
// TODO: remove support of "string" as shortcut notation on release 3.0
sitemapOptions.i18n = true
}

// Set default i18n options
sitemapOptions.i18n = {
defaultLocale: '',
locales: [],
routesNameSeparator: '___',
...sitemapOptions.i18n,
Expand Down
52 changes: 30 additions & 22 deletions test/module.test.js
Expand Up @@ -350,7 +350,7 @@ describe('sitemap - advanced configuration', () => {
const sitemapConfig = {
hostname: 'https://example.com',
trailingSlash: true,
i18n: 'en',
i18n: true,
routes: ['foo', { url: 'bar' }],
}

Expand Down Expand Up @@ -386,14 +386,18 @@ describe('sitemap - advanced configuration', () => {
sitemap: sitemapConfig,
})

const links = [
'<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/"/>',
'<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>',
].join('')

const xml = await get('/sitemap.xml')
expect(xml).not.toContain('<loc>https://example.com/</loc>')
expect(xml).toContain('<loc>https://example.com/en/</loc>')
expect(xml).not.toContain('<loc>https://example.com/fr/</loc>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="en" href="https://example.com/"/>')
expect(xml).toContain('<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/"/>')
expect(xml).toContain('<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>')
expect(xml).toContain(`<url><loc>https://example.com/en/</loc>${links}</url>`)
expect(xml).toContain(`<url><loc>https://example.com/fr/</loc>${links}</url>`)
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/"/>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/"/>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/fr/"/>')
})

test('strategy "prefix_except_default"', async () => {
Expand All @@ -407,14 +411,18 @@ describe('sitemap - advanced configuration', () => {
sitemap: sitemapConfig,
})

const links = [
'<xhtml:link rel="alternate" hreflang="en" href="https://example.com/"/>',
'<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>',
].join('')

const xml = await get('/sitemap.xml')
expect(xml).toContain('<loc>https://example.com/</loc>')
expect(xml).not.toContain('<loc>https://example.com/en/</loc>')
expect(xml).not.toContain('<loc>https://example.com/fr/</loc>')
expect(xml).toContain('<xhtml:link rel="alternate" hreflang="en" href="https://example.com/"/>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/"/>')
expect(xml).toContain('<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>')
expect(xml).toContain(`<url><loc>https://example.com/</loc>${links}</url>`)
expect(xml).toContain(`<url><loc>https://example.com/fr/</loc>${links}</url>`)
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/"/>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/"/>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/fr/"/>')
})

test('strategy "prefix_and_default"', async () => {
Expand All @@ -427,20 +435,21 @@ describe('sitemap - advanced configuration', () => {
},
sitemap: {
...sitemapConfig,
i18n: {
defaultLocale: 'x-default',
},
},
})

const links = [
'<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/"/>',
'<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>',
'<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/"/>',
].join('')

const xml = await get('/sitemap.xml')
expect(xml).toContain('<loc>https://example.com/</loc>')
expect(xml).not.toContain('<loc>https://example.com/en/</loc>')
expect(xml).not.toContain('<loc>https://example.com/fr/</loc>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="en" href="https://example.com/"/>')
expect(xml).toContain('<xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/"/>')
expect(xml).toContain('<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/"/>')
expect(xml).toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/"/>')
expect(xml).toContain(`<url><loc>https://example.com/</loc>${links}</url>`)
expect(xml).toContain(`<url><loc>https://example.com/fr/</loc>${links}</url>`)
expect(xml).toContain(`<url><loc>https://example.com/en/</loc>${links}</url>`)
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/en/"/>')
expect(xml).not.toContain('<xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/fr/"/>')
})

test('locales with iso values', async () => {
Expand All @@ -458,7 +467,6 @@ describe('sitemap - advanced configuration', () => {
sitemap: {
...sitemapConfig,
i18n: {
defaultLocale: 'en',
locales,
},
},
Expand Down

0 comments on commit b6d79c8

Please sign in to comment.