예제 #1
0
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
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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)
예제 #5
0
def get_language_id(locale):
    """Return language id without territory or anything else."""
    return langtable.parse_locale(locale).language