Skip to content
Neaptidestudio
blog

Next.js hreflang with missing translations: a tested setup

Neaptide · October 4, 2026 · 9 min read

A reproducible Next.js experiment for partial translations, plus checks of 18 live URLs. Keep hreflang, canonical, sitemap and the language switcher consistent.

On this page
The full profile exists in en, ru, fr, es, it and zh; partial exists in en, ru and fr; original exists only in en. Ten published combinations and eight missing combinations.

Build a page’s language links from its published translations, not from every language your site supports. Use that same availability record for hreflang, the sitemap and the language switcher. A missing French translation should not become a French URL simply because French appears in your global locale list.

We tested this on October 4, 2026. A deliberately faulty Next.js fixture produced 14 hreflang links and 14 navigation links to missing translations, plus eight missing URLs in its sitemap. Using page-specific availability removed all three mismatches. Separately, 18 published Neaptide URLs passed the checks described below. Neither dataset measures Google rankings or indexing.

Two evidence sets, with different jobs

The live sample covers three routes in six languages: the GEO service, multilingual website guide and B2B catalog article. We made two HTTP passes and checked each rendered page and one language-switcher action. One request had a connection reset; a separately logged retry succeeded. That means 37 attempts and 36 successful responses, not an error-free first pass.

Published Neaptide pages: six language URLs per route
RouteURLs checkedMetadata + sitemapSwitcher actions
/services/geo66 / 66 / 6
/blog/multilingual-website-guide66 / 66 / 6
/blog/b2b-catalog-seo66 / 66 / 6

All 18 URLs returned 200, kept self-canonicals and agreed with their language annotations in the sitemap. Each declared six language alternatives plus English as x-default. All 18 tested switcher actions preserved the route. This covers one action per source URL, not every possible language pair or the whole website. The check used the live B2B article, not its newer local research draft.

A controlled test of incomplete translations

We built a separate App Router fixture with Next.js 15.5.22, React 19.2.6 and Node.js v25.2.1. We fixed three profiles before measuring: six published translations, three published translations and only the English original. Each phase has 18 route/language combinations: 10 available pages and eight missing ones. Two HTTP passes across before and after produced 72 observations; we also opened all 36 combinations in a browser.

The full profile exists in en, ru, fr, es, it and zh; partial exists in en, ru and fr; original exists only in en. Ten published combinations and eight missing combinations.
Controlled fixture, not a market sample. Green cells have published content; empty cells remained 404 in both phases.

In the faulty phase, all three outputs used the global six-language list. In the corrected phase, they used the actual translation records. Available pages kept self-canonicals throughout. We did not create replacement content or redirect missing translations to the home page.

Measured mismatches in the intentionally faulty fixture
ProfileBad hreflang links: before → afterBad switcher links: before → afterMissing sitemap URLs: before → after
6 languages0 → 00 → 00 → 0
3 languages9 → 09 → 03 → 0
1 language5 → 05 → 05 → 0

These are different units: a link counts once per source page, whereas a sitemap URL counts once per entry. Do not add them into a count of broken pages. Both HTTP passes agreed, and all 36 DOM checks matched the HTML. Five representative clicks confirmed three valid transitions and two deliberately bad links reaching 404. This experiment does not estimate how common the fault is.

Use one availability map

In the fixture, TRANSLATIONS contains only published content. availableLocales reads its keys, and generateStaticParams creates only those routes. Missing combinations stay unavailable with dynamicParams = false; page and metadata functions also guard against missing records. The excerpt below uses the same helpers as the tested fixture. The downloadable project contains both phases; use the corrected after branch when studying the solution.

export const availableLocales = profile => Object.keys(TRANSLATIONS[profile] || {});
export const translation = (profile, locale) => TRANSLATIONS[profile]?.[locale];
export const pageUrl = (profile, locale, phase) => `${ORIGIN}/${locale}/${phase}/${profile}`;
export async function generateMetadata({ params }) {
  const { phase, profile, locale } = await params;
  const content = translation(profile, locale);
  if (!PHASES.includes(phase) || !content) notFound();
  return {
    title: content.title,
    alternates: { canonical: pageUrl(profile, locale, phase), languages: languageAlternates(profile, phase) },
  };
}

The fixture’s languageAlternates helper returns only published equivalents in the after branch. It adds English as x-default for multilingual profiles and omits language annotations for the English-only profile. That fallback is our explicit choice. If your original is another language, select an existing fallback for that translation group. If slugs differ across languages, store the equivalent URLs rather than replacing a prefix; translated slugs were not part of this test.

Canonical, hreflang and navigation have separate roles

Canonical identifies the preferred URL; hreflang connects localized equivalents. Our translated pages use self-canonicals. The switcher must take the reader to the equivalent content that exists, while an optional, clearly labeled link to another language’s home page remains ordinary navigation—not a translation of the missing page.

Google documents reciprocal, absolute language links with self-reference. HTML and sitemap annotations are alternative methods; we compared both because this project uses both.

What to do when the translation is not ready

Remove the unavailable version from the translation cluster and from the switcher’s list of equivalent pages. Keep any draft out of the public sitemap. If you offer an English original, label that link as English and point to its real English URL. A 200 response with English copy under a French path is not evidence of a completed French translation.

In our static fixture, all eight missing combinations returned 404 and noindex in both phases. We checked the actual responses. A different dynamic or streaming setup needs its own status check; calling notFound() in source code alone is not the observation.

Check the rendered result after each translation release

  1. Open every published equivalent and inspect its status, final URL, language and canonical.
  2. Resolve each announced alternate against the availability map, then check the target and its return links.
  3. Compare the sitemap’s actual entries with published content. If it includes language annotations, compare those with the HTML.
  4. Click the switcher from the affected pages. Check missing-language behavior as well as a successful translation.
  5. Repeat after publishing or withdrawing a translation. Keep date, route and output evidence; use Search Console separately for indexing observations.

Reproduce the test

Download the source fixture, observed results and full method. The ZIP excludes dependencies and build output. Build and run it locally on the documented port, then run the supplied HTTP collector. The original browser checks are recorded separately; the collector does not pretend to repeat them.

This is a same-day technical test by one researcher. It checks a three-route production sample and controlled static fixtures, not translation quality across the site, Google-selected canonicals, indexing, rankings, traffic or AI citations.

faq

The short version

Should hreflang list all languages supported by the website?

List published equivalents of the specific page. A site-wide language list is not evidence that every page exists in each language.

Should every translation use the English canonical?

Our translated pages keep their own canonical URLs. Do not treat an English original as the canonical for every distinct translation merely because it was published first.

Must x-default point to English?

No. English is the existing fallback we chose for this fixture. Choose an appropriate available destination for your users and translation group.

Did removing the invalid links improve rankings?

We did not measure rankings. The observed result was that invalid language links and missing sitemap entries disappeared while the intended pages remained accessible.