All files / utils/algorithms get-lang-from-element.util.js

91.07% Statements 51/56
77.77% Branches 14/18
100% Functions 3/3
91.07% Lines 51/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 571x 1x 1x 1x 1x 1x 2x 2x 2x       2x 2x 2x 1x 1x 1x 1x 1x 1x 5x 5x 1x 5x 2x 2x 2x 2x 1x 1x 1x 1x 1x 1x 1x 308x     308x 769x 769x 307x 307x 307x 769x 296x 296x 6x 769x 5x 5x 769x 1x 1x 1x  
import { traverseUpDomWithSlots } from './traverse-up-dom.js'
 
/**
 * @param {Element} element - target element
 * @returns {string} fallback language
 */
function getFallbackLanguage (element) {
  const root = element.ownerDocument.defaultView ?? globalThis
  if (!root.navigator) {
    // OS/node/browser independent way of obtaining the default locale
    return Intl.DateTimeFormat().resolvedOptions().locale
  }
  const langs = root.navigator.languages || [root.navigator.language]
  return langs[0]
}
 
/**
 * @param {Element} element - element with invalid lang attribute
 * @param {string} invalidLanguage - the invalid language detected
 * @returns {string} corrected language
 */
function handleInvalidLanguage (element, invalidLanguage) {
  if (element === element.ownerDocument.documentElement) {
    return getFallbackLanguage(element)
  } else if (element.parentNode instanceof ShadowRoot) {
    return getLanguageFromElement(element.parentNode.host)
  }
  return getLanguageFromElement(element.parentElement)
}
 
/**
 * Gets the currently applied language of element, get default locale otherwise
 * @param {Element | null} element - target element
 * @returns {string} element language
 */
export function getLanguageFromElement (element) {
  if (element == null) {
    return Intl.DateTimeFormat().resolvedOptions().locale
  }
  for (const node of traverseUpDomWithSlots(element)) {
    const langValue = node.getAttribute('lang')
    if (!langValue) continue
    try {
      const locale = new Intl.Locale(langValue)
      const { language, region } = locale
      if (region == null) {
        return language
      }
      return `${language}-${region}`
    } catch {
      return handleInvalidLanguage(node, langValue)
    }
  }
 
  return getFallbackLanguage(element)
}