Skip to content

[Bug]: hreflang missing for untranslated pages #2916

@fabiograsso

Description

@fabiograsso

Issue Check

  • I have checked existing Issues and I feel this bug has not been raised

Hugo Version Check

  • My Hugo version is within the supported range

Describe the Bug

Blowfish correctly generates hreflang alternate tags for translated pages via the IsTranslated check in head.html:

{{ if .IsTranslated }}
  {{ range .AllTranslations }}
    {{ $hreflang := .Language.LanguageCode | default .Language.Lang }}
    {{ if $hreflang }}
      
    {{ end }}
  {{ end }}
{{ end }}

This works correctly when a page has translations. However, it has two gaps:

1. Pages that exist only in the default language get no hreflang at all.

On a multilingual site (e.g. EN + IT + FR), Google expects every page to declare its language affinity via hreflang. Pages without any hreflang tag on a multilingual site can be deprioritized for indexing. This is likely a contributing factor to the common "Crawled - currently not indexed" status reported by Search Console users on multilingual Blowfish sites.

2. hreflang="x-default" is never emitted.

Google's hreflang specification recommends a x-default tag to indicate the fallback URL when no language match is found. Without it, Google has to guess which version is canonical for international users.

To Reproduce

Check the HTML code in a situation where:

  • The website is multilingual
  • Some posts have not translation

Expected Behaviour

layouts/partials/head.html should generate both

    <link rel="alternate" hreflang="x-default" href="...">
    <link rel="alternate" hreflang="xx" href="...">

Screenshots

No response

Platform

No platform-dependent

Hugo Version

hugo v0.160.1+extended+withdeploy darwin/arm64 BuildDate=2026-04-08T14:02:42Z VendorInfo=Homebrew

Blowfish Version

v2.88.1

Additional Context

Workaround via extend-head-uncached.html

Since extend-head.html is called with partialCached .Site (no page context), it cannot be used for per-page tags. However, Blowfish already provides extend-head-uncached.html which is called with full page
context. Users can work around the gap today by creating:

layouts/partials/extend-head-uncached.html:

{{ if .IsPage }}
  {{ $defaultLang := (index .Site.Languages 0).Lang }}
  {{ $defaultPermalink := "" }}

  {{ range .AllTranslations }}
    {{ if or (eq .Language.Lang $defaultLang) (not .Language.Lang) }}
      {{ $defaultPermalink = .Permalink }}
    {{ end }}
  {{ end }}

  {{ with $defaultPermalink }}
    <link rel="alternate" hreflang="x-default" href="{{ . }}">
  {{ end }}
  
  {{ if not .Translations }}
    <link rel="alternate" hreflang="{{ .Language.Lang }}" href="{{ .Permalink }}">
  {{ end }}
  
{{ end }}

This works but requires every multilingual Blowfish user to discover and implement it manually. The fix belongs in the theme itself.

Additional context

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions