Skip to content
Snippets Groups Projects
Verified Commit 556160b2 authored by Anri Dellal's avatar Anri Dellal Committed by Newbyte
Browse files

pmb.helpers.locale: new module (MR 2497)

Add module that provides utilities and information related to localization.

Initial implementation includes code to generate keyboard configs
for locale set by user.
parent 3e18183a
Branches
No related tags found
No related merge requests found
......@@ -17,4 +17,5 @@ set -x
codespell \
-L crate \
-L hda \
-S "./pmb/helpers/locale.py" \
.
......@@ -100,6 +100,15 @@ pmb.helpers.lint module
:undoc-members:
:show-inheritance:
pmb.helpers.locale module
-------------------------
.. automodule:: pmb.helpers.locale
:members:
:undoc-members:
:show-inheritance:
pmb.helpers.logging module
--------------------------
......
C
a_DJ
aa_DJ
aa_ER
aa_ET
af_ZA
......
from pmb.helpers import logging
"""
Helper used to configure locale-related settings in pmOS installation.
Locale and layout information is taken from:
* https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes
* https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes
* Xkb source code: /usr/share/X11/xkb/rules/base.lst
"""
class XkbLayout:
primary_layouts = [
"at",
"au",
"br",
"ca",
"ch",
"de",
"dk",
"ee",
"es",
"fi",
"fo",
"fr",
"gb",
"ie",
"is",
"it",
"latam",
"lt",
"mt",
"nz",
"pl",
"pt",
"ro",
"se",
"sk",
"tr",
"us",
"vn",
]
def __init__(self, layout: str = "us", variant: str = ""):
self.layout = layout
self.variant = variant
self.options = ""
self.layout_list: list[str] = []
self.variant_list: list[str] = []
if layout in XkbLayout.primary_layouts:
self.layout_list.append(layout)
if variant:
self.variant_list.append(variant)
elif not self.is_default():
self.layout_list.extend(["us", layout])
if variant:
self.variant_list.extend(["", variant])
self.options = "grp:alt_shift_toggle"
def is_default(self) -> bool:
return self.layout == "us" and not self.variant
def get_profile_vars(self) -> str | None:
if self.is_default():
return None
template = "XKB_DEFAULT_LAYOUT=" + ",".join(self.layout_list)
if self.variant_list:
template += "\nXKB_DEFAULT_VARIANT=" + ",".join(self.variant_list)
if self.options:
template += "\nXKB_DEFAULT_OPTIONS=" + self.options
return template
def get_keyboard_config(self) -> str | None:
if self.is_default() or not self.layout_list:
return None
template = f"""Section "InputClass"
\tIdentifier "keyboard"
\tMatchIsKeyboard "on"
\tOption "XkbLayout" "{",".join(self.layout_list)}"\n"""
if self.variant_list:
template += f'\tOption "XkbVariants" "{",".join(self.variant_list)}"\n'
if self.options:
template += f'\tOption "XkbOptions" "{self.options}"\n'
template += "EndSection"
return template
def __eq__(self, other: object) -> bool:
if not isinstance(other, XkbLayout):
return False
return self.layout == other.layout and self.variant == other.variant
def get_xkb_layout(locale: str) -> XkbLayout:
"""
Get Xkb layout for the given locale.
:param locale: Locale to get XkbLayout for.
:return: XkbLayout for the given locale.
"""
try:
(language, territory) = locale.split("_")
except ValueError:
logging.warning(f'Keyboard config for locale "{locale}" cannot be provided')
return XkbLayout()
if language in lang_layouts:
return XkbLayout(language)
elif language in lang_to_layout:
return XkbLayout(lang_to_layout[language])
match language:
case "af":
return XkbLayout("za")
case "ak":
return XkbLayout("gh", "akan")
case "ar":
if territory == "DZ":
return XkbLayout("dz", "ar")
elif territory == "EG":
return XkbLayout("eg")
elif territory == "IQ":
return XkbLayout("iq")
elif territory == "MA":
return XkbLayout("ma")
elif territory == "SY":
return XkbLayout("sy")
else:
return XkbLayout("ara")
case "as":
return XkbLayout("in", "asm-kagapa")
case "ast":
return XkbLayout("es", "ast")
case "ber":
if territory == "DZ":
return XkbLayout("dz")
else: # "MA"
return XkbLayout("ma")
case "bo":
return XkbLayout("cn", "tib")
case "ca":
return XkbLayout("es", "cat")
case "chr":
return XkbLayout("us", "chr")
case "crh":
return XkbLayout("ua", "crh")
case "de":
if territory == "AT":
return XkbLayout("at")
elif territory == "CH":
return XkbLayout("ch")
else:
return XkbLayout("de")
case "en":
if territory == "AU":
return XkbLayout("au")
elif territory == "CA":
return XkbLayout("ca", "eng")
elif territory == "GB":
return XkbLayout("gb")
elif territory == "IN":
return XkbLayout("in", "eng")
elif territory == "NG":
return XkbLayout("ng")
elif territory == "NZ":
return XkbLayout("nz")
elif territory == "ZA":
return XkbLayout("za")
else:
return XkbLayout("us")
case "es":
if territory in latam_es_territories:
return XkbLayout("latam")
else: # "ES", "US"
return XkbLayout("es")
case "fr":
if territory == "CA":
return XkbLayout("ca")
elif territory == "CH":
return XkbLayout("ch", "fr")
else: # "FR"
return XkbLayout("fr")
case "fur":
return XkbLayout("it", "fur")
case "gu":
return XkbLayout("in", "guj")
case "gv":
return XkbLayout("gb", "gla")
case "ha":
return XkbLayout("ng", "hausa")
case "hif" | "hne":
return XkbLayout("in")
case "ig":
return XkbLayout("ng", "igbo")
case "iu":
return XkbLayout("ca", "ike")
case "kab":
return XkbLayout("dz", "azerty-deadkeys")
case "kn":
return XkbLayout("in", "kan")
case "ku":
return XkbLayout("tr", "ku")
case "mhr":
return XkbLayout("ru", "chm")
case "ml":
return XkbLayout("in", "mal")
case "mni":
return XkbLayout("in", "mni")
case "mnw":
return XkbLayout("mm", "mnw")
case "mr":
return XkbLayout("in", "marathi")
case "nan":
return XkbLayout("cn") # Min Nan Chinese
case "nds":
return XkbLayout("de") # Low German
case "oc":
return XkbLayout("fr", "oci")
case "or":
return XkbLayout("in", "ori")
case "os":
return XkbLayout("ru", "os_winkeys")
case "pa":
return XkbLayout("in", "guru")
case "ps":
return XkbLayout("af", "ps")
case "pt":
if territory == "BR":
return XkbLayout("br")
else: # if territory == "PT":
return XkbLayout("pt")
case "sa":
return XkbLayout("in", "sas")
case "sah":
return XkbLayout("ru", "sah")
case "sat":
return XkbLayout("in", "sat")
case "sd":
return XkbLayout("in", "sdh")
case "se":
return XkbLayout("no", "smi")
case "sgs":
return XkbLayout("lt", "sgs")
case "shn":
return XkbLayout("mm", "shn")
case "si":
return XkbLayout("pk", "snd")
case "sw":
if territory == "KE":
return XkbLayout("ke")
else: # "TZ"
return XkbLayout("tz")
case "szl":
return XkbLayout("pl", "szl")
case "ta":
if territory == "LK":
return XkbLayout("lk", "tam_unicode")
else: # "IN"
return XkbLayout("in", "tamilnet")
case "te":
return XkbLayout("in", "tel")
case "tt":
return XkbLayout("ru", "tt")
case "ug":
return XkbLayout("cn", "ug")
case "ur":
return XkbLayout("pak", "urd-nla")
case "yo":
return XkbLayout("ng", "yoruba")
if language not in locales_without_layout:
logging.warning(f'Language "{language}" not found in language list')
return XkbLayout() # return default layout if no layout was found
# Layouts which have same code as language
lang_layouts = [
"az",
"bg",
"csb",
"cv",
"dsb",
"fi",
"fo",
"hr",
"hu",
"id",
"is",
"it",
"lt",
"lv",
"mk",
"mn",
"mt",
"nl",
"pl",
"ro",
"ru",
"sk",
"tg",
"th",
"tr",
"uk",
"uz",
]
lang_to_layout = {
"am": "et",
"be": "by",
"bn": "bd",
"br": "bre",
"bs": "ba",
"cmn": "cn",
"cs": "cz",
"da": "dk",
"dz": "bt",
"el": "gr",
"eo": "epo",
"et": "ee",
"eu": "es",
"fa": "ir",
"fil": "ph",
"ga": "ie",
"gd": "gla",
"hak": "cn",
"he": "il",
"hi": "in",
"hy": "am",
"ja": "jp",
"ka": "ge",
"kk": "kz",
"km": "kh",
"ko": "kr",
"ky": "kg",
"lo": "la",
"lzh": "cn",
"mai": "in",
"mi": "mao",
"ms": "my",
"my": "mm",
"nb": "no",
"ne": "np",
"nn": "no",
"sl": "si",
"sq": "al",
"sr": "rs",
"sv": "se",
"tk": "tm",
"tl": "in",
"tn": "bw",
"vi": "vn",
"wo": "sn",
"yi": "il",
"yue": "cn",
"zh": "cn",
}
# Locales which either have no layout or missing information about one
locales_without_layout = [
"aa", # Afar
"agr", # Aguaruna
"an", # Aragonese
"anp", # Angika
"ayc", # Aymara
"bem", # Bemba
"bhb", # Bhili
"bho", # Bhojpuri
"bi", # Bislama
"bn", # Bengali
"brx", # Bodo (India)
"byn", # Bilin
"ce", # Chechen
"ch", # Chamorro
"cy", # Wales
"doi", # Dogri
"dv", # Divehi
"ff", # Fulah
"fy", # Western Frisian
"gez", # Geez
"gl", # Galician
"hsb", # Upper Sorbian
"ht", # Haitian
"ia", # Interlingua
"ik", # Inupiaq
"kl", # Kalaallisut, Greenlandic
"kok", # Konkani
"ks", # Kashmiri
"kw", # Kinyarwanda
"lb", # Luxembourgish
"lg", # Ganda
"li", # Limburgish
"lij", # Ligurian
"ln", # Lingala
"mfe", # Morisyen
"mg", # Malagasy
"miq", # Miskito
"mjw", # Karbi
"nhn", # Nahuatl
"niu", # Niuean
"nr", # South Ndebele
"nso", # Northern Sotho
"om", # Oromo
"pap", # Papiamento
"quz", # Cusco Quechua
"raj", # Rajasthani
"rw", # Kinyarwanda
"sc", # Sardinian
"shs", # Shuswap
"sid", # Sidamo
"sm", # Samoan
"so", # Somali
"ss", # Swati
"st", # Southern Sotho
"tcy", # Tulu
"the", # Chitwania Tharu
"ti", # Tigrinya
"tig", # Tigre
"to", # Tonga
"tpi", # Tok Pisin
"ts", # Tsonga
"unm", # Unami
"ve", # Venda
"wa", # Walloon
"wae", # Walser
"wal", # Wolaitta
"xh", # Xhosa
"yuw", # Yau (Morobe province)
"zu", # Zulu
]
latam_es_territories = [
"AR",
"BO",
"CL",
"CO",
"CR",
"CU",
"DO",
"EC",
"GT",
"HN",
"MX",
"NI",
"PA",
"PE",
"PR",
"PY",
"SV",
"UY",
"VE",
]
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment