guessLanguage = (request) => {
    if (typeof request === 'object') {
      const languageHeader = request.headers
        ? request.headers[languageHeaderName]
        : undefined
      const languages = []
      const regions = []

      request.languages = [defaultLocale]
      request.regions = [defaultLocale]
      request.language = defaultLocale
      request.region = defaultLocale

      // a query parameter overwrites all
      if (queryParameter && request.url) {
        const urlAsString =
          typeof request.url === 'string' ? request.url : request.url.toString()

        /**
         * @todo WHATWG new URL() requires full URL including hostname - that might change
         * @see https://github.com/nodejs/node/issues/12682
         */
        // eslint-disable-next-line node/no-deprecated-api
        const urlObj = url.parse(urlAsString, true)
        const languageQueryParameter = urlObj.query[queryParameter]
        if (languageQueryParameter) {
          let queryLanguage = extractQueryLanguage(languageQueryParameter)
          if (queryLanguage) {
            logDebug('Overriding locale from query: ' + queryLanguage)
            if (preserveLegacyCase) {
              queryLanguage = queryLanguage.toLowerCase()
            }
            return i18n.setLocale(request, queryLanguage)
          }
        }
      }

      // a cookie overwrites headers
      if (cookiename && request.cookies && request.cookies[cookiename]) {
        request.language = request.cookies[cookiename]
        return i18n.setLocale(request, request.language)
      }

      // 'accept-language' is the most common source
      if (languageHeader) {
        const acceptedLanguages = getAcceptedLanguagesFromHeader(languageHeader)
        let match
        let fallbackMatch
        let fallback
        for (let i = 0; i < acceptedLanguages.length; i++) {
          const lang = acceptedLanguages[i]
          const lr = lang.split('-', 2)
          const parentLang = lr[0]
          const region = lr[1]

          // Check if we have a configured fallback set for this language.
          const fallbackLang = getFallback(lang, fallbacks)
          if (fallbackLang) {
            fallback = fallbackLang
            // Fallbacks for languages should be inserted
            // where the original, unsupported language existed.
            const acceptedLanguageIndex = acceptedLanguages.indexOf(lang)
            const fallbackIndex = acceptedLanguages.indexOf(fallback)
            if (fallbackIndex > -1) {
              acceptedLanguages.splice(fallbackIndex, 1)
            }
            acceptedLanguages.splice(acceptedLanguageIndex + 1, 0, fallback)
          }

          // Check if we have a configured fallback set for the parent language of the locale.
          const fallbackParentLang = getFallback(parentLang, fallbacks)
          if (fallbackParentLang) {
            fallback = fallbackParentLang
            // Fallbacks for a parent language should be inserted
            // to the end of the list, so they're only picked
            // if there is no better match.
            if (acceptedLanguages.indexOf(fallback) < 0) {
              acceptedLanguages.push(fallback)
            }
          }

          if (languages.indexOf(parentLang) < 0) {
            languages.push(parentLang.toLowerCase())
          }
          if (region) {
            regions.push(region.toLowerCase())
          }

          if (!match && locales[lang]) {
            match = lang
            break
          }

          if (!fallbackMatch && locales[parentLang]) {
            fallbackMatch = parentLang
          }
        }

        request.language = match || fallbackMatch || request.language
        request.region = regions[0] || request.region
        return i18n.setLocale(request, request.language)
      }
    }

    // last resort: defaultLocale
    return i18n.setLocale(request, defaultLocale)
  }
guess language setting based on http headers