Page translations and multi-language selects

Multi-language sites are straight up hard to do. You can automate, plugin and redirect all you like, but you’ll still be left with the reality that you’ll be dealing with multiple instances of the same thing. I’ve worked on multi-language sites before, back in my WordPress saga days, and it sure got complicated.

You would think there’s standard HTML spec thingers to handle this kinda stuff? Well, there is! I’ve recently been expanding our catalog of tutorials for Ghost and one of them was a guide on using multiple languages in Ghost. While working on this, Kym from the team enlightened me about <link> elements that denote alternate versions of the same page.

<link rel="alternate" href="" />

This <link> element would reside within the <head> element of the page. I guess it acts a bit like canonical, but not to the extent of saying “this is the original”. Examples can be found on

Using rel="alternate" with translations

So, what can this attribute (and value) do to help our multi-language pain points? When the rel="alternate" attribute is used in conjunction with the hreflang="" attribute, it can denote translated versions of the currently viewed page.

Search engines, like Google, will index the pages, along with the translated counterparts that’ve been referenced with the <link> element. There’s a bit more info here on this Google Support page. Google will then serve the user whatever page is right for them, depending on their region, using the hreflang value as a reference.

Further details on applying this kind of meta information to your web pages can be found in the Moz learning resources. Additionally, Nomensa have covered these attributes, as well as other microformats for creating accessible multi-lingual sites.

Building a language select dropdown

Let’s circle back to the original point of this tutorial: creating a language select. I’ve approached this in the same fashion I do most interactions - I’m using JavaScript to enhance what already exists on the page.

I’m using the existing <link> elements that state the translations for the page to generate a list of links that’ll take the user to one of those translations. Rather than give a full breakdown of the code, I’ve provided an annotated version of the core functionality below. Check out this CodePen to see everything in action, including an accessible method of toggling the language select (thanks Andy Bell).

  <!-- all my translations for the currently viewed page -->
  <link rel="alternate" hreflang="fr" href="" />
  <link rel="alternate" hreflang="jp" href="" />
  <link rel="alternate" hreflang="de" href="" />
<!-- Details element in markup, ready for JavaScript -->
<div data-language-select></div>
// Grab the details element that will be the language select
const langSelect = document.querySelector("[data-language-select]");

// Grab all the alternate translations as an array
const translations = [...document.querySelectorAll("head [hreflang]")];

// Check if both select and translations exist
if (langSelect && translations.length) {
  // Build a list of anchors from the translations
  const links = translations
    .map(link => {
      return `
        <a href="${link.href}" hreflang="${link.hreflang}">${link.hreflang}</a>

  // Insert a summary showing the current language
  // and insert the links into a unordered list
  langSelect.innerHTML = `
    <button type="button" aria-expanded="false">Language: ${document.documentElement.lang}</button>

One thing I should note is that the above assumes you’ve set a lang="" attribute on the <html> element, which you should definitely do so users know what language the content is in.


What I really like about this method is that if feels like the ‘right way’. We’re using standard methods of marking our content and our translated versions alongside them.

We’re also not trying to be clever. I worked way too hard in trying to automate translations on those WordPress sites; there’s a reason professional translators exist. The same subject is covered, amongst others, here in this Tuts+ article on building a multi-lingual site. Get a professional to translate your content and when it’s done, add the <link> elements in later.

Let me know your thoughts on Twitter. If you’re feeling kind, give this article a share. Thanks for reading ✌