Plugin screenshot thumbnail 1/8
Plugin screenshot thumbnail 2/8
Plugin screenshot thumbnail 3/8
Plugin screenshot thumbnail 4/8
Plugin screenshot thumbnail 5/8
Plugin screenshot thumbnail 6/8
Plugin screenshot thumbnail 7/8
Plugin screenshot thumbnail 8/8

🌐 🔤 🤖 AI Hreflang

README · Getting started · How it works · Settings

AI Hreflang, for multi-site Craft websites where pages aren't always in their site's language, with Anthropic, OpenAI, Langdock and OpenRouter, on Craft 5 with SEOmatic and Blitz. The French site of Le Faux Gras, a made-up vegan bistro, whose page is in English, with its hreflang corrected from fr-FR to en-FR.

For multi-site Craft websites where pages aren't always in their site's language.

Some pages are waiting on a translator. Others stay in English on purpose: because most of their audience speaks it as a second language and translating every page isn't worth the budget, or because they're legal or regulatory text that must keep its original wording. Either way, AI Hreflang detects the language each page is really written in, and sets its hreflang to match.

Plugin Store | GitHub Repository

🤔 The problem

Multi-site launches rarely translate everything at once. Until a page is translated, the French site shows the English copy, while SEOmatic tells search engines it's fr-FR. Google sees a French page in English, and French searchers get the wrong result. AI Hreflang finds those pages and announces them as en-FR, so each page is listed for the language it's actually in. Translated pages keep their site's hreflang, and nobody has to keep track by hand.

✨ What you get

  • Untranslated pages caught automatically. With Detect when a page is saved turned on, a page is detected after it's saved, on each site the save changed, once caches such as Blitz's are cleared. As soon as it's translated, the next save puts its hreflang back.
  • Reach new audiences before everything's translated. Copy content across your sites, with Craft's propagation or a plugin such as Site Copy X, and go live. Each page's hreflang stays truthful while translation catches up.
  • English on purpose, labelled honestly. In the Netherlands, 93% of people can hold a conversation in English; in Sweden it's 90%, and in Denmark 87% (Special Eurobarometer 540, 2023). Pages you keep in English for those audiences are labelled en-NL, en-SE or en-DK, so search engines know exactly who they're for.
  • Reads the live page, like a visitor. The plugin fetches the live page and reads its main content, <main> or any element you choose, so hidden fields, notes for editors, menus and cookie banners can't skew the result.
  • Works with any AI provider. Use Anthropic or OpenAI directly, Langdock (hosted in the EU), or OpenRouter. The plugin sends the page's text itself, rather than its URL, so it works the same with every provider, and on local and staging sites the provider can't reach. See why.
  • Costs next to nothing. A small model is all it takes, only the first 2,000 characters of a page are sent, and a page whose text hasn't changed is never sent again.
  • Entries, categories and more. Entries and categories in sections and groups with URLs, Craft Commerce products, and other plugins' elements with their own URLs are supported. Add the field to a field layout and its pages are detected. Assets, tags, users, addresses and globals have no pages of their own, so they're skipped.
  • Automatic, one click, or in bulk. On save, from an entry's or category's action menu, or for a whole site from the utility. Everything runs through Craft's queue.
  • Editors stay in control. Any page's language can be chosen from a searchable list of every language, and a chosen language is kept by every save and re-detection, unless an admin chooses Re-detect all.
  • SEOmatic's hreflang tags, fixed. Alternate links are rewritten for every site, in your sites' own format, such as en-GB, or as the language alone, such as en.
  • No duplicate hreflang values. Two URLs can't share an hreflang, so an untranslated page that would get the same value as another site's page, such as an es-US page still in English next to the en-US site's, keeps its site's own hreflang. The clash is shown in the field and the utility.
  • See every site's coverage, and a free translation to-do list. The utility shows how many pages each site has detected, the hreflang values in use, and every page that's still in another language, ready to hand to translators.

How it works, in four steps. 1, saved: a page is saved, and once caches such as Blitz's are cleared, a queue job is added for each site the save changed. 2, fetched: the live page is requested from your site, like a visitor would, and the text of its main content is taken. 3, detected: the text is sent to Anthropic, OpenAI, Langdock or OpenRouter, which replies with its language. 4, announced: SEOmatic's hreflang for that site becomes the detected language with the site's region, such as en-FR.

🚀 Quick start

Craft CMS 5.0 or later, PHP 8.2 or later, and an API key for Anthropic, OpenAI, Langdock or OpenRouter. SEOmatic is recommended, as it outputs the hreflang tags for you.

composer require heavymetalavo/craft-ai-hreflang
./craft plugin/install ai-hreflang
  1. Choose a provider and add its API key under Settings → AI Hreflang.
  2. Add the Content Language field, created when the plugin is installed, to the field layouts of your entry types and category groups with public pages.
  3. Detect your existing pages from Utilities → AI Hreflang → Detect missing. To detect new and changed pages when they're saved too, turn on Detect when a page is saved in the plugin's settings.
  4. Output the hreflang tags in your layout's <head>, unless you use SEOmatic (see below):

    {% set alternates = craft.aiHreflang.alternates(entry) %}
    {% for alternate in alternates %}
      <link rel="alternate" hreflang="{{ alternate.hreflang }}" href="{{ alternate.url }}">
    {% endfor %}
    {# x-default, for visitors whose language none of the alternates match, here the primary site's page #}
    {% for alternate in alternates|filter(a => a.site.primary) %}
      <link rel="alternate" hreflang="x-default" href="{{ alternate.url }}">
    {% endfor %}
    

    craft.aiHreflang.alternates() gives the page's live copy on each site, with its URL and hreflang: the page's language with its site's region, such as en-FR, or the site's own hreflang when it hasn't been detected, is in the site's language, or would clash with another copy. It works for entries, categories and any other element with pages.

Using SEOmatic

There's nothing to add to your templates. SEOmatic outputs the hreflang tags as usual, and the plugin rewrites their values for every site from each page's Content Language, with the same rules as craft.aiHreflang.alternates(). Skip step 4.

Using Blitz

There's nothing to set up. Pages are detected once Blitz has refreshed their cache, and the plugin's jobs run after Blitz's refresh and generate jobs by default. Blitz's Expire refresh modes are the exception, as they can serve an old copy while it's read. See Page caches.

📚 Documentation

  • Getting started - requirements, installation, the Content Language field, page caches and detecting your first pages
  • How it works - how pages are read and detected, how hreflang values are written, and limitations
  • Settings - every setting, the AI providers, the prompt and the hreflang format

⚠️ Disclaimer

Each detection is a request to your AI provider, billed to your account. The defaults keep that cost down, with a small model, 2,000 characters per page and unchanged pages skipped, but we take no responsibility for API usage that results from mistakes, bugs or security vulnerabilities in this plugin, so use it at your own risk.

🙋 Support

If you have any issues or questions, please submit them on GitHub.

Standard

Plus $9/year after one year.

Installation Instructions

To install this plugin, copy the command above to your terminal.

Reviews

This plugin doesn't have any reviews.

Active Installs
0
Version
1.0.4
License
Craft
Compatibility
Craft 5
Last release
November 12, 2026