Как преобразовать языковой идентификатор IETF BCP 47 в ISO-639-2?

Я пишу серверный API для приложения iOS. Как часть процесса инициализации, приложение должно отправить язык интерфейса телефона на сервер через вызов API.

Проблема заключается в том, что Apple использует в своем языке что-то под названием IETF BCP 47. NSLocale preferredLanguages функция

Возвращаемые значения имеют разную длину (например, [aa, ab, ace, ach, ada, ady, ae, af, afa, afh, agq, ...] и я нашел очень мало парсеров, которые могут преобразовать этот код в правильный идентификатор языка.

Я хотел бы использовать более распространенный трехбуквенный языковой идентификатор ISO-639-2, который повсеместен, имеет много синтаксических анализаторов на многих языках и имеет стандартное трехбуквенное представление языков.

Как я могу преобразовать идентификатор языка IETF BCP 47 в трехбуквенный идентификатор языка ISO-639-2, предпочтительно в Python?

2 ответа

Решение

Идентификаторы BCP 47 начинаются с двухбуквенного кода языка ISO 639-1 или трехбуквенного кода 639-2, 639-3 или 639-5; см. раздел Синтаксис RFC 5646:

Language-Tag  = langtag             ; normal language tags
              / privateuse          ; private use tag
              / grandfathered       ; grandfathered tags

langtag       = language
                ["-" script]
                ["-" region]
                *("-" variant)
                *("-" extension)
                ["-" privateuse]

language      = 2*3ALPHA            ; shortest ISO 639 code
                ["-" extlang]       ; sometimes followed by
                                    ; extended language subtags
              / 4ALPHA              ; or reserved for future use
              / 5*8ALPHA            ; or registered language subtag

Я не ожидаю, что Apple будет использовать privateuse или же grandfathered формы, так что вы можете предположить, что вы смотрите здесь языковые коды ISO 639-1, ISO 639-2, ISO 639-3 или ISO 639-5. Просто сопоставьте 2-буквенные коды ISO-639-1 с 3-буквенными кодами ISO 639-*.

Вы можете использовать pycountry пакет для этого:

import pycountry

lang = pycountry.languages.get(alpha2=two_letter_code)
three_letter_code = lang.terminology

Демо-версия:

>>> import pycountry
>>> lang = pycountry.languages.get(alpha2='aa')
>>> lang.terminology
u'aar'

где терминологическая форма является предпочтительным трехбуквенным кодом; Существует также библиографическая форма, которая отличается только для 22 записей. См. ISO 639-2 B и T коды. Пакет не включает записи из ISO 639-5, однако; этот список частично совпадает с 639-2, и я не думаю, что Apple вообще использует такие коды.

Из RFC5646 / BCP47:

Language-Tag  = langtag             ; normal language tags
              / privateuse          ; private use tag
              / grandfathered       ; grandfathered tags

langtag       = language
                ["-" script]
                ["-" region]
                *("-" variant)
                *("-" extension)
                ["-" privateuse]

language      = 2*3ALPHA            ; shortest ISO 639 code
                ["-" extlang]       ; sometimes followed by
                                    ; extended language subtags
              / 4ALPHA              ; or reserved for future use
              / 5*8ALPHA            ; or registered language subtag

privateuse    = "x" 1*("-" (1*8alphanum))

grandfathered = irregular           ; non-redundant tags registered
              / regular             ; during the RFC 3066 era

Похоже, что первый сегмент большинства кодов BCP-47 должен быть действительными кодами ISO-639, хотя они могут не быть трехбуквенными вариантами. Код языка BCP-47 имеет несколько вариантов, которые не являются кодами ISO-639, а именно те, которые начинаются с x- или же i- а также ряд устаревших кодов, которые соответствуют grandfathered часть грамматики:

irregular     = "en-GB-oed"         ; irregular tags do not match
              / "sgn-BE-FR"         ; also includes i- prefixed codes
              / "sgn-BE-NL"
              / "sgn-CH-DE"

regular       = "art-lojban"        ; these tags match the 'langtag'
              / "cel-gaulish"       ; production, but their subtags
              / "no-bok"            ; are not extended language
              / "no-nyn"            ; or variant subtags: their meaning
              / "zh-guoyu"          ; is defined by their registration
              / "zh-hakka"          ; and all of these are deprecated
              / "zh-min"            ; in favor of a more modern
              / "zh-min-nan"        ; subtag or sequence of subtags
              / "zh-xiang"

Хорошим началом было бы что-то вроде следующего:

def extract_iso_code(bcp_identifier):
    language, _ = bcp_identifier.split('-', 1)
    if 2 <= len(language) <=3:
        # this is a valid ISO-639 code or is grandfathered
    else:
        # handle non-ISO codes
        raise ValueError(bcp_identifier)

Преобразование из двухсимвольного варианта в трехсимвольный вариант должно быть достаточно простым для обработки, поскольку отображение хорошо известно.

Другие вопросы по тегам