Anki/pylib/anki/lang.py
Damien Elmes b9251290ca run pyupgrade over codebase [python upgrade required]
This adds Python 3.9 and 3.10 typing syntax to files that import
attributions from __future___. Python 3.9 should be able to cope with
the 3.10 syntax, but Python 3.8 will no longer work.

On Windows/Mac, install the latest Python 3.9 version from python.org.
There are currently no orjson wheels for Python 3.10 on Windows/Mac,
which will break the build unless you have Rust installed separately.

On Linux, modern distros should have Python 3.9 available already. If
you're on an older distro, you'll need to build Python from source first.
2021-10-04 15:05:48 +10:00

217 lines
5.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
from __future__ import annotations
import locale
import re
import weakref
import anki
import anki._backend
import anki.i18n_pb2 as _pb
# public exports
TR = anki._backend.LegacyTranslationEnum
FormatTimeSpan = _pb.FormatTimespanRequest
langs = sorted(
[
("Afrikaans", "af_ZA"),
("Bahasa Melayu", "ms_MY"),
("Català", "ca_ES"),
("Dansk", "da_DK"),
("Deutsch", "de_DE"),
("Eesti", "et_EE"),
("English (United States)", "en_US"),
("English (United Kingdom)", "en_GB"),
("Español", "es_ES"),
("Esperanto", "eo_UY"),
("Euskara", "eu_ES"),
("Français", "fr_FR"),
("Galego", "gl_ES"),
("Hrvatski", "hr_HR"),
("Italiano", "it_IT"),
("lo jbobau", "jbo_EN"),
("Lenga d'òc", "oc_FR"),
("Magyar", "hu_HU"),
("Nederlands", "nl_NL"),
("Norsk", "nb_NO"),
("Polski", "pl_PL"),
("Português Brasileiro", "pt_BR"),
("Português", "pt_PT"),
("Română", "ro_RO"),
("Slovenčina", "sk_SK"),
("Slovenščina", "sl_SI"),
("Suomi", "fi_FI"),
("Svenska", "sv_SE"),
("Tiếng Việt", "vi_VN"),
("Türkçe", "tr_TR"),
("简体中文", "zh_CN"),
("日本語", "ja_JP"),
("繁體中文", "zh_TW"),
("한국어", "ko_KR"),
("Čeština", "cs_CZ"),
("Ελληνικά", "el_GR"),
("Български", "bg_BG"),
("Монгол хэл", "mn_MN"),
("Pусский язык", "ru_RU"),
("Српски", "sr_SP"),
("раїнська мова", "uk_UA"),
("Հայերեն", "hy_AM"),
("עִבְרִית", "he_IL"),
("العربية", "ar_SA"),
("فارسی", "fa_IR"),
("ภาษาไทย", "th_TH"),
("Latin", "la_LA"),
("Gaeilge", "ga_IE"),
]
)
# compatibility with old versions
compatMap = {
"af": "af_ZA",
"ar": "ar_SA",
"bg": "bg_BG",
"ca": "ca_ES",
"cs": "cs_CZ",
"da": "da_DK",
"de": "de_DE",
"el": "el_GR",
"en": "en_US",
"eo": "eo_UY",
"es": "es_ES",
"et": "et_EE",
"eu": "eu_ES",
"fa": "fa_IR",
"fi": "fi_FI",
"fr": "fr_FR",
"gl": "gl_ES",
"he": "he_IL",
"hr": "hr_HR",
"hu": "hu_HU",
"hy": "hy_AM",
"it": "it_IT",
"ja": "ja_JP",
"ko": "ko_KR",
"mn": "mn_MN",
"ms": "ms_MY",
"nl": "nl_NL",
"nb": "nb_NL",
"no": "nb_NL",
"oc": "oc_FR",
"pl": "pl_PL",
"pt": "pt_PT",
"ro": "ro_RO",
"ru": "ru_RU",
"sk": "sk_SK",
"sl": "sl_SI",
"sr": "sr_SP",
"sv": "sv_SE",
"th": "th_TH",
"tr": "tr_TR",
"uk": "uk_UA",
"vi": "vi_VN",
}
def lang_to_disk_lang(lang: str) -> str:
"""Normalize lang, then convert it to name used on disk."""
# convert it into our canonical representation first
lang = lang.replace("-", "_")
if lang in compatMap:
lang = compatMap[lang]
# these language/region combinations are fully qualified, but with a hyphen
if lang in (
"en_GB",
"ga_IE",
"hy_AM",
"nb_NO",
"nn_NO",
"pt_BR",
"pt_PT",
"sv_SE",
"zh_CN",
"zh_TW",
):
return lang.replace("_", "-")
# other languages have the region portion stripped
m = re.match("(.*)_", lang)
if m:
return m.group(1)
else:
return lang
# the currently set interface language
currentLang = "en"
# the current Fluent translation instance. Code in pylib/ should
# not reference this, and should use col.tr instead. The global
# instance exists for legacy reasons, and as a convenience for the
# Qt code.
current_i18n: anki._backend.RustBackend | None = None
tr_legacyglobal = anki._backend.Translations(None)
def _(str: str) -> str:
print(f"gettext _() is deprecated: {str}")
return str
def ngettext(single: str, plural: str, n: int) -> str:
print(f"ngettext() is deprecated: {plural}")
return plural
def set_lang(lang: str) -> None:
global currentLang, current_i18n
currentLang = lang
current_i18n = anki._backend.RustBackend(langs=[lang])
tr_legacyglobal.backend = weakref.ref(current_i18n)
def get_def_lang(lang: str | None = None) -> tuple[int, str]:
"""Return lang converted to name used on disk and its index, defaulting to system language
or English if not available."""
try:
(sys_lang, enc) = locale.getdefaultlocale()
except:
# fails on osx
sys_lang = "en_US"
user_lang = lang
if user_lang in compatMap:
user_lang = compatMap[user_lang]
idx = None
lang = None
en = None
for l in (user_lang, sys_lang):
for c, (name, code) in enumerate(langs):
if code == "en_US":
en = c
if code == l:
idx = c
lang = l
if idx is not None:
break
# if the specified language and the system language aren't available, revert to english
if idx is None:
idx = en
lang = "en_US"
return (idx, lang)
def is_rtl(lang: str) -> bool:
return lang in ("he", "ar", "fa")
# strip off unicode isolation markers from a translated string
# for testing purposes
def without_unicode_isolation(s: str) -> str:
return s.replace("\u2068", "").replace("\u2069", "")
def with_collapsed_whitespace(s: str) -> str:
return re.sub(r"\s+", " ", s)