docs: def match_lang(self, el, langs):
          """Match languages."""
  
          match = False
          has_ns = self.supports_namespaces()
          root = self.root
          has_html_namespace = self.has_html_namespace
  
          # Walk parents looking for `lang` (HTML) or `xml:lang` XML property.
          parent = el
          found_lang = None
          last = None
          while not found_lang:
              has_html_ns = self.has_html_ns(parent)
              for k, v in self.iter_attributes(parent):
                  attr_ns, attr = self.split_namespace(parent, k)
                  if (
                      ((not has_ns or has_html_ns) and (util.lower(k) if not self.is_xml else k) == 'lang') or
                      (
                          has_ns and not has_html_ns and attr_ns == NS_XML and
                          (util.lower(attr) if not self.is_xml and attr is not None else attr) == 'lang'
                      )
                  ):
                      found_lang = v
                      break
              last = parent
              parent = self.get_parent(parent, no_iframe=self.is_html)
  
              if parent is None:
                  root = last
                  has_html_namespace = self.has_html_ns(root)
                  parent = last
                  break
  
          # Use cached meta language.
          if not found_lang and self.cached_meta_lang:
              for cache in self.cached_meta_lang:
                  if root is cache[0]:
                      found_lang = cache[1]
  
          # If we couldn't find a language, and the document is HTML, look to meta to determine language.
          if found_lang is None and (not self.is_xml or (has_html_namespace and root.name == 'html')):
              # Find head
              found = False
              for tag in ('html', 'head'):
                  found = False
                  for child in self.get_children(parent, no_iframe=self.is_html):
                      if self.get_tag(child) == tag and self.is_html_tag(child):
                          found = True
                          parent = child
                          break
                  if not found:  # pragma: no cover
                      break
  
              # Search meta tags
              if found:
                  for child in parent:
                      if self.is_tag(child) and self.get_tag(child) == 'meta' and self.is_html_tag(parent):
                          c_lang = False
                          content = None
                          for k, v in self.iter_attributes(child):
                              if util.lower(k) == 'http-equiv' and util.lower(v) == 'content-language':
                                  c_lang = True
                              if util.lower(k) == 'content':
                                  content = v
                              if c_lang and content:
                                  found_lang = content
                                  self.cached_meta_lang.append((root, found_lang))
                                  break
                      if found_lang:
                          break
                  if not found_lang:
                      self.cached_meta_lang.append((root, False))
  
          # If we determined a language, compare.
          if found_lang:
              for patterns in langs:
                  match = False
                  for pattern in patterns:
                      if pattern.match(found_lang):
                          match = True
                  if not match:
                      break
  
          return match