question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Duplicated language in alternate ref path (href)

See original GitHub issue

Describe the bug

If you have 2 languages (one default and one secondary) the alternate refs don’t correctly link back from the secondary language entries of the sitemap the hrefs are broken.

To Reproduce Steps to reproduce the behaviour:

  1. Setup a Next.js project with two languages (one default, one secondary). Sample config:
module.exports = {
  i18n: {
    locales: ['de', 'en'],
    defaultLocale: 'en',
  },
};
  1. Setup next-sitemap with the following config:
/** @type {import('next-sitemap').IConfig} */
module.exports = {
  siteUrl: `https://tree.ly`,
  generateRobotsTxt: true,
  alternateRefs: [
    {
      href: 'https://tree.ly',
      hreflang: 'en',
    },
    {
      href: 'https://tree.ly/de',
      hreflang: 'de',
    },
  ],
};
  1. Generate a sitemap
  2. See that in the sitemap entry for the secondary language the links (hrefs) are broken. In this example, you can see that there is just one /de too much in the link. Example entry:
<url>
    <loc>https://tree.ly/de/app/overview</loc>
    <lastmod>2022-10-18T17:00:36.138Z</lastmod>
    <changefreq>daily</changefreq>
    <priority>0.7</priority>
    <xhtml:link rel="alternate" hreflang="en" href="https://tree.ly/de/app/overview"/>
    <xhtml:link rel="alternate" hreflang="de" href="https://tree.ly/de/de/app/overview"/>
</url>

Expected behaviour

That the generated records for the secondary language look like this:

<url>
    <loc>https://tree.ly/de/app/overview</loc>
    <lastmod>2022-10-18T17:00:36.138Z</lastmod>
    <changefreq>daily</changefreq>
    <priority>0.7</priority>
    <xhtml:link rel="alternate" hreflang="en" href="https://tree.ly/app/overview"/>
    <xhtml:link rel="alternate" hreflang="de" href="https://tree.ly/de/app/overview"/>
</url>

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:3
  • Comments:7 (1 by maintainers)

github_iconTop GitHub Comments

2reactions
rkaliscommented, Oct 24, 2022

Actually it looks like this version of the transformer doesn’t properly catch the “index page”. I ended up changing it to the following, which I think is working correctly now.

      const matches = config.alternateRefs.map((alt) =>
        `${config.siteUrl}${path}/`.replace(`${alt.href}/`, '/').replace(/\/+$/, '')
      );
1reaction
lukasbalscommented, Oct 24, 2022

@rkalis Note that there is a problem in your transformer if you have e.g. /demo in the language /de. Then it replaces the /de from /demo with an empty string. A workaround is to replace /de/ with /. So the updated version of the transformer would be:

const SITE_URL = 'https://revoke.cash';

/** @type {import('next-sitemap').IConfig} */
module.exports = {
  siteUrl: SITE_URL,
  generateIndexSitemap: false,
  alternateRefs: [
    {
      href: SITE_URL,
      hreflang: 'en',
    },
    {
      href: `${SITE_URL}/es`,
      hreflang: 'es',
    },
  ],
  // Custom transform function to de-duplicate path locale strings in alternateRefs
  // Without this we get things like https://<domain>/es/es/about rather than https://<domain>/es/about
  // NOTE: This is made to work for path-based localisation scheme (https://<domain>/<locale>/<path>). It may not
  // work if you're using subdomains or separate domains for localisation.
  transform: async (config, path) => {
    // Remove the locale part of the path (e.g. /es/about -> /about)
    const extractLocaleIndependentPath = (path) => {
      const matches = config.alternateRefs.map((alt) =>
        `${config.siteUrl}${path}`.replace(`${alt.href}/`, '/').replace(/\/$/, '')
      );
      return matches.sort((a, b) => a.length - b.length)[0];
    };

    const localeIndependentPath = extractLocaleIndependentPath(path);

    // Map the locale independent path onto the locale paths
    const alternateRefs = config.alternateRefs.map((alt) => {
      return { ...alt, href: `${alt.href}${localeIndependentPath}`, hrefIsAbsolute: true };
    });

    return {
      loc: path,
      changefreq: config.changefreq,
      priority: config.priority,
      lastmod: config.autoLastmod ? new Date().toISOString() : undefined,
      alternateRefs,
    };
  },
};
Read more comments on GitHub >

github_iconTop Results From Across the Web

`next-sitemap` duplicated language in alternate ref path (href)
In my case I have languages en and en-gb The urls generated are: <xhtml:link rel="alternate" hreflang="en" href="http://localhost:3000/en/en- ...
Read more >
Hreflang 101: How to Avoid International Duplication
If you have specified two different URLs as the alternative for the same language + country then they will both be ignored. Broken/disallowed ......
Read more >
How To Fix the Duplicate Page in Hreflang Error - Sitechecker
When you encounter this error, it means you have used duplicate URLs for more than one language in the hreflang annotations. How To...
Read more >
hreflang & canonical tag: Use them correctly without conflicts
So canonical tags help mark up duplicate URLs within one country/language version and signal which of the duplicates should be the preferred ...
Read more >
International hreflang - will this handle duplicate content? - Moz
hreflang and geo-targeting are in fact two different things. If you have exactly the same content, no changes for the regional variations in...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found