Issue Check
Hugo Version Check
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
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
Issue Check
Hugo Version Check
Describe the Bug
Blowfish correctly generates
hreflangalternate tags for translated pages via theIsTranslatedcheck inhead.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
hreflangat all.On a multilingual site (e.g. EN + IT + FR), Google expects every page to declare its language affinity via
hreflang. Pages without anyhreflangtag 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-defaulttag 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:
Expected Behaviour
layouts/partials/head.htmlshould generate bothScreenshots
No response
Platform
No platform-dependent
Hugo Version
hugo v0.160.1+extended+withdeploy darwin/arm64 BuildDate=2026-04-08T14:02:42Z VendorInfo=HomebrewBlowfish Version
v2.88.1Additional Context
Workaround via
extend-head-uncached.htmlSince
extend-head.htmlis called withpartialCached .Site(no page context), it cannot be used for per-page tags. However, Blowfish already providesextend-head-uncached.htmlwhich is called with full pagecontext. 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
https://developers.google.com/search/docs/specialty/international/localization
x-defaulttag spec:https://developers.google.com/search/blog/2013/04/x-default-hreflang-for-international-pages
AllTranslationson a monolingual site returns only the page itself, and.IsPagescopes the change away from home/section/taxonomy pages where Blowfish may handle things differently.Code of Conduct