javascriptisolang

Get the implicit lang attribute of an HTML element


Suppose you have an HTML page that contains sections in different languages, like this:

<html lang=en>
<div lang="th">
  <p id="test1">ไทย</p>
</div>
<p id="test2">Implicitly English</p>
<div lang="en-CA">
  <p id="test3">As Canadian as possible under the circumstances</p>
</div>
<p lang="en-AU"id="test4">Explicitly Aussie</p>
</html>

Is there a direct way to discover which particular language code applies to a given HTML element? Something like:

// pseudo-code
var lang = myElement.getLang()

Here's what appears to be a very roundabout solution:

function getLang(element) {
  var lang = element.getAttribute("lang")

  if (!lang) {
    var elements
      , languages
      , language
      , ii
      , selector

    // Find all elements with an explicit lang attribute
    elements = [].slice.call(document.querySelectorAll("*[lang]"))

    // Determine which languages are present
    languages = []
    for (ii in elements) {
      lang = elements[ii].getAttribute("lang")
      if (languages.indexOf(lang) < 0) {
        languages.push(lang)
      }
    }

    lang = "" // reset

    for (ii in languages) {
      language = languages[ii]
      selector = ":lang(" + language + ")"
      elements = [].slice.call(document.querySelectorAll(selector))

      if (elements.indexOf(element) > -1) {
        if (lang.length < language.length) {
          lang = language
        }
      }
    }
  }

  return lang
}

Is there a more obvious way? jsFiddle


Solution

  • A much simpler answer: element.closest('[lang]').lang.

    element.closest(selector) will return the first matching ancestor of element that matches the CSS selector selector, or element itself if it matches selector.

    Demo:

    const dn = new Intl.DisplayNames('en-US', { type: 'language' })
    
    document.body.addEventListener('mouseover', (event) => {
        for (const el of document.querySelectorAll('[lang]')) {
            el.style.background = 'white'
        }
    
        const localized = event.target.closest('[lang]')
        localized.style.background = '#cdf'
        document.querySelector('#lang-output').textContent = dn.of(localized.lang)
    })
    <body lang="en">
      <div style="color: firebrick; font-weight: bold;">
        <code>
          Language of currently hovered content:
          <span id="lang-output">[none]</span>
        </code>
      </div>
    
      <div lang="th">
        <p id="test1">ไทย</p>
      </div>
      <p id="test2">Implicitly English</p>
      <div lang="en-CA">
        <p id="test3">As Canadian as possible under the circumstances</p>
      </div>
      <p lang="en-AU" id="test4">Explicitly Aussie</p>
    </body>