EthicsComputerCourses
Join training +91 90532 10052

Languages, Text Direction & hreflang

HTML · Lesson 41 of 55 Beginner 9 min read Updated

India has 22 scheduled languages written in many different scripts, and plenty of websites mix English with Hindi, Tamil, Marathi or Urdu on the same page. The browser, search engines and screen readers cannot always guess which language a piece of text is in, or which way it should be read. A few attributes tell them.

In this lesson you will set the language of a page and of single phrases, write right-to-left text such as Urdu correctly, protect user names with <bdi>, and connect the English and Hindi versions of a page with hreflang links.

The lang attribute

You put lang on the <html> element in your very first page. It is a global attribute, so you can also put it on any element whose language differs from the page. Its value is a language tag: a short code such as en, optionally followed by a region or script.

TagMeaning
enEnglish
en-INEnglish as used in India
hiHindi
ta, te, kn, mlTamil, Telugu, Kannada, Malayalam
mr, gu, pa, bnMarathi, Gujarati, Punjabi, Bengali
urUrdu
hi-LatnHindi written in Latin letters ("Aap kaise hain?")

What lang changes:

  • Screen readers switch voice and pronunciation. Without lang="hi", an English voice tries to read Devanagari, or skips it.
  • Fonts: the browser can pick a suitable font for the script, and CSS can style languages differently with the :lang() selector.
  • Hyphenation and spell checking: CSS hyphens: auto and the browser's spell checker need to know the language.
  • Translation: browsers offer to translate a page whose language differs from the user's.
HTMLTry it yourself
<!DOCTYPE html>
<html lang="en-IN">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Republic Day Programme | Sunrise Public School, Pune</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 16px; line-height: 1.6; }
    :lang(hi), :lang(mr) { font-size: 1.1em; line-height: 1.8; }
    :lang(ur) { font-size: 1.15em; }
    li { margin-bottom: 8px; }
  </style>
</head>
<body>
  <h1>Republic Day programme, 26 January</h1>
  <ol>
    <li>Flag hoisting and the national anthem</li>
    <li>Hindi poem by class 7: <span lang="hi">"वीर तुम बढ़े चलो"</span></li>
    <li>Marathi song by class 5: <span lang="mr">"जय जय महाराष्ट्र माझा"</span></li>
    <li>Urdu recitation by Farhan, class 9: <span lang="ur" dir="rtl">سارے جہاں سے اچھا</span></li>
    <li>Vote of thanks</li>
  </ol>
  <p>Language of each item:</p>
  <ul id="report"></ul>

  <script>
    for (const span of document.querySelectorAll("[lang]")) {
      if (span === document.documentElement) continue;
      const li = document.createElement("li");
      li.textContent = span.lang + ": " + span.textContent;
      document.querySelector("#report").append(li);
    }
  </script>
</body>
</html>

The :lang() rules make Devanagari text slightly larger and taller, which many designers do because its letters hang from a line and have marks above and below. The script at the end shows that each phrase carries its own language, which is exactly what a screen reader uses.

Google says it works out a page's language from its visible text, not from lang. So lang is not an SEO setting; it is for browsers and assistive technology, and you must still set it correctly on every page.

Right-to-left text with dir

Urdu, Arabic, Persian and Sindhi (in Perso-Arabic script) are written from right to left. The dir attribute sets the base direction:

  • dir="rtl": right to left. Put it on <html> for a whole Urdu page, or on one element.
  • dir="ltr": left to right, the default.
  • dir="auto": the browser looks at the first strong letter and decides. Use it for text you do not control, such as a comment or a search box.

Setting dir does more than align text to the right. It flips the order of inline items, moves the list bullets to the right side, and changes the order of table columns. Never fake right-to-left with text-align: right; the punctuation and mixed text will come out in the wrong order. When you write CSS for pages that may be either direction, use logical properties such as margin-inline-start instead of margin-left; see Logical Properties.

Forms can send the direction too. The dirname attribute on an <input> or <textarea> adds a second value to the submitted data saying whether the user typed ltr or rtl text, so your server can display it correctly later.

HTML
<label for="msg">Message</label>
<textarea id="msg" name="message" dir="auto" dirname="message.dir"></textarea>
<!-- Sends: message=...&message.dir=rtl when the user types in Urdu -->

Mixed directions: bdi and bdo

Trouble starts when right-to-left and left-to-right text meet on one line. The browser's bidirectional algorithm (often called "bidi") arranges the characters, and numbers or punctuation next to an Urdu word can jump to the wrong side. This often happens with user names on leaderboards or comment lists.

<bdi> (bidirectional isolate) wraps text whose direction you do not know, so it cannot disturb the text around it. <bdo dir="rtl"> (bidirectional override) forces a direction for every character; you will rarely need it.

HTMLTry it yourself
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Quiz Leaderboard</title>
  <style>
    body { font-family: system-ui, sans-serif; margin: 16px; }
    li { margin: 6px 0; }
  </style>
</head>
<body>
  <h1>Weekly quiz leaderboard</h1>
  <h2>Without bdi</h2>
  <ul>
    <li>Aarav: 42 points</li>
    <li>فرحان: 39 points</li>
    <li>Kabir: 35 points</li>
  </ul>
  <h2>With bdi</h2>
  <ul>
    <li><bdi>Aarav</bdi>: 42 points</li>
    <li><bdi>فرحان</bdi>: 39 points</li>
    <li><bdi>Kabir</bdi>: 35 points</li>
  </ul>
</body>
</html>

In the first list, the score after the Urdu name can appear in a confusing place, because the browser treats the name, the colon and the number as one right-to-left run. Inside <bdi>, the name is isolated and "39 points" stays in its normal place. When you print user-supplied names into a template, wrap them in <bdi> and you never need to think about it again.

Connecting translated pages with hreflang

If your site has the same page in several languages, for example an English and a Hindi version of a railway timetable, tell search engines that they belong together. Then a user searching in Hindi can be shown the Hindi page. Add <link rel="alternate" hreflang="..."> tags to the head of every version:

HTML
<!-- In the head of BOTH the English and the Hindi page -->
<link rel="alternate" hreflang="en-IN" href="https://www.example.com/en/timetable">
<link rel="alternate" hreflang="hi-IN" href="https://www.example.com/hi/timetable">
<link rel="alternate" hreflang="x-default" href="https://www.example.com/timetable">

Google's rules for hreflang:

  • Each version lists itself and all the other versions, and the set is the same on every version. If page A points to page B but B does not point back, the tags are ignored.
  • Use full URLs, including https://.
  • The code is a language (ISO 639-1, such as hi), optionally followed by a region (ISO 3166-1, such as IN). A region alone is not allowed: in does not mean India, so write hi-IN or en-IN.
  • x-default names the page for everyone else, often a page that lets users choose a language.
  • The same information can go in an HTTP header or the XML sitemap instead, which suits large sites; pick one method.

Each version also keeps its own canonical link pointing to itself. Do not point the Hindi page's canonical at the English page; that tells search engines to ignore the Hindi page.

A language switcher people can use

Do not redirect visitors automatically by their location: a Tamil speaker in Delhi or a tourist in Kochi gets the wrong page, and crawlers may never see the other versions. Offer a visible switcher made of normal links. Write each language's name in its own script, and mark it with lang so screen readers pronounce it correctly.

HTML
<nav aria-label="Language">
  <ul>
    <li><a href="/en/timetable" hreflang="en" lang="en" aria-current="true">English</a></li>
    <li><a href="/hi/timetable" hreflang="hi" lang="hi">हिन्दी</a></li>
    <li><a href="/ta/timetable" hreflang="ta" lang="ta">தமிழ்</a></li>
  </ul>
</nav>

The hreflang attribute on an <a> is only a hint about the linked page's language. A national flag is a poor symbol for a language: India alone has many languages under one flag.

Common mistakes

  • Missing or wrong lang on <html>. Hindi pages marked lang="en" are read aloud with an English voice.
  • Foreign phrases without their own lang. Mark them with <span lang="...">.
  • text-align: right instead of dir="rtl". Alignment does not fix the order of mixed text.
  • User names printed without <bdi>. Numbers and punctuation jump around next to Urdu or Arabic names.
  • One-way hreflang links or relative URLs. Every version must list all versions with full URLs.
  • Canonical of a translated page pointing to the English page. Each translation is its own canonical.

Key points

  • lang tells browsers, screen readers, spell checkers and translators which language text is in; set it on <html> and on phrases in other languages.
  • Use language tags such as en-IN, hi, ta or hi-Latn for romanised Hindi.
  • dir="rtl" sets right-to-left text for Urdu and Arabic; dir="auto" suits user-written text.
  • Wrap user-supplied names in <bdi> so mixed directions cannot scramble the line.
  • hreflang alternate links connect translations; every version lists all versions, including itself, with full URLs.
  • Offer a language switcher made of normal links instead of redirecting by location.

Exercise

Meera runs a recipe site with English and Tamil versions of each recipe. For the "Lemon rice" page, write: the start of the Tamil page (the <html> element and the hreflang links in its head, with x-default pointing to the English page), and a sentence on the English page that includes the Tamil name எலுமிச்சை சாதம் marked correctly. Use the URLs https://www.example.com/en/lemon-rice and https://www.example.com/ta/lemon-rice.

Show solution
HTML
<!DOCTYPE html>
<html lang="ta">
<head>
  <meta charset="utf-8">
  <link rel="canonical" href="https://www.example.com/ta/lemon-rice">
  <link rel="alternate" hreflang="en" href="https://www.example.com/en/lemon-rice">
  <link rel="alternate" hreflang="ta" href="https://www.example.com/ta/lemon-rice">
  <link rel="alternate" hreflang="x-default" href="https://www.example.com/en/lemon-rice">
HTML
<p>Lemon rice, called <span lang="ta">எலுமிச்சை சாதம்</span> in Tamil, is a quick lunchbox favourite.</p>

The Tamil page lists both versions and itself, keeps its own canonical, and uses lang="ta". The English page must carry the same three hreflang links. On the English page, the Tamil name gets its own lang so a screen reader switches voice.

Quick Quiz

1. Which language tag describes Hindi written in Latin letters?

2. What does Google use to decide the language of a page?

3. Why wrap user names in <bdi>?

4. An English page links to its Hindi version with hreflang, but the Hindi page has no hreflang tags. What happens?

Learn HTML with a mentor

Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.

  • Project-based learning
  • Mentor code reviews
  • Free counselling call