def langcode_matches_locale(langcode, locale): """Function that tells if the given langcode matches the given locale. I.e. if all parts of appearing in the langcode (language, territory, script and encoding) are the same as the matching parts of the locale. :param langcode: a langcode (e.g. en, en_US, en_US@latin, etc.) :type langcode: str :param locale: a valid locale (e.g. en_US.UTF-8 or sr_RS.UTF-8@latin, etc.) :type locale: str :return: whether the given langcode matches the given locale or not :rtype: bool """ if not is_valid_langcode(langcode) or not is_valid_langcode(locale): # to match, both need to be valid langcodes (need to have at least # language specified) return False langcode_parsed = langtable.parse_locale(langcode) locale_parsed = langtable.parse_locale(locale) # Check parts one after another. If some part appears in the langcode and # doesn't match the one from the locale (or is missing in the locale), # return False, otherwise they match for lang_val, loc_val in zip(langcode_parsed, locale_parsed): if lang_val and lang_val != loc_val: return False return True
def find_best_locale_match(locale, langcodes): """Find the best match for the locale in a list of langcodes. This is useful when e.g. pt_BR is a locale and there are possibilities to choose an item (e.g. rnote) for a list containing both pt and pt_BR or even also pt_PT. :param locale: a valid locale (e.g. en_US.UTF-8 or sr_RS.UTF-8@latin, etc.) :type locale: str :param langcodes: a list or generator of langcodes (e.g. en, en_US, en_US@latin, etc.) :type langcodes: list(str) or generator(str) :return: the best matching langcode from the list of None if none matches :rtype: str or None """ def score_value_pair(locale_value, langcode_value, weight): if locale_value and langcode_value: if locale_value == langcode_value: # match return weight else: # not match return -weight elif langcode_value and not locale_value: # langcode has something the locale doesn't have return -weight return 0 if not is_valid_langcode(locale): return None scores = [] # get score for each langcode for langcode in langcodes: if not is_valid_langcode(langcode): scores.append((langcode, 0)) else: locale_parsed = langtable.parse_locale(locale) langcode_parsed = langtable.parse_locale(langcode) score = score_value_pair(locale_parsed.language, langcode_parsed.language, 1000) + \ score_value_pair(locale_parsed.territory, langcode_parsed.territory, 100) + \ score_value_pair(locale_parsed.script, langcode_parsed.script, 10) + \ score_value_pair(locale_parsed.variant, langcode_parsed.variant, 10) + \ score_value_pair(locale_parsed.encoding, langcode_parsed.encoding, 1) scores.append((langcode, score)) # find the best one sorted_langcodes = sorted(scores, key=lambda item_score: item_score[1], reverse=True) # matches matching only script or encoding or both are not useful if sorted_langcodes and sorted_langcodes[0][1] > 100: # 100 = requires at least territory to have matched return sorted_langcodes[0][0] else: return None
def is_valid_langcode(langcode): """Check if the given locale has a language specified. :return: whether the language or locale is valid :rtype: bool """ parsed = langtable.parse_locale(langcode) return bool(parsed.language)
def find_best_locale_match(locale, langcodes): """Find the best match for the locale in a list of langcodes. This is useful when e.g. pt_BR is a locale and there are possibilities to choose an item (e.g. rnote) for a list containing both pt and pt_BR or even also pt_PT. :param locale: a valid locale (e.g. en_US.UTF-8 or sr_RS.UTF-8@latin, etc.) :type locale: str :param langcodes: a list or generator of langcodes (e.g. en, en_US, en_US@latin, etc.) :type langcodes: list(str) or generator(str) :return: the best matching langcode from the list of None if none matches :rtype: str or None """ # Parse the locale. if not is_valid_langcode(locale): return None locale_parsed = langtable.parse_locale(locale) # Get a score for each langcode. scores = {} for langcode in langcodes: if not is_valid_langcode(langcode): continue langcode_parsed = langtable.parse_locale(langcode) # Don't match a non-POSIX locale with a POSIX langcode. if langcode_parsed.variant == "POSIX" and locale_parsed.variant != "POSIX": continue score = _evaluate_locales(locale_parsed, langcode_parsed) # Matches matching only script or encoding or both are not useful. # The score of 100 requires at least territory to have matched. if score <= 100: continue scores[langcode] = score # Find the best one. return max(scores.keys(), key=scores.get, default=None)
def get_language_id(locale): """Return language id without territory or anything else.""" return langtable.parse_locale(locale).language