refactor: refactor for language id
This commit is contained in:
@@ -0,0 +1,219 @@
|
||||
import re
|
||||
from typing import ClassVar, Optional
|
||||
import pycountry
|
||||
|
||||
|
||||
class PoLang:
|
||||
"""
|
||||
Represents a valid Gettext PO file Language field value.
|
||||
|
||||
Supported formats:
|
||||
ll - ISO 639 language code (2 or 3 letters, lowercase)
|
||||
ll_CC - language code + ISO 3166 country code (uppercase)
|
||||
ll_CC@variant - language code + country code + variant (lowercase)
|
||||
|
||||
Examples:
|
||||
PoLang("en") # valid
|
||||
PoLang("zh_CN") # valid
|
||||
PoLang("sr_Cyrl") # valid (3-letter language code)
|
||||
PoLang("de_DE@euro") # invalid (@euro is not a valid variant)
|
||||
PoLang("EN") # invalid (language code must be lowercase)
|
||||
"""
|
||||
|
||||
__PATTERN: ClassVar[re.Pattern] = re.compile(
|
||||
r"^(?P<language>[a-z]{2,3})"
|
||||
r"(?:_(?P<country>[A-Z]{2})"
|
||||
r"(?:@(?P<variant>[a-z][a-z0-9-]*))?"
|
||||
r")?$"
|
||||
)
|
||||
|
||||
__language_code: str
|
||||
"""ISO 639 two-letter or three-letter language code (lowercase)."""
|
||||
__country_code: Optional[str]
|
||||
"""ISO 3166 two-letter country code (uppercase) or no presented."""
|
||||
__variant: Optional[str]
|
||||
"""The variant designator.
|
||||
The variant designator (lowercase) can be a script designator,
|
||||
such as ‘latin’ or ‘cyrillic’.
|
||||
"""
|
||||
|
||||
def __init__(self, value: str):
|
||||
match = self.__PATTERN.match(value)
|
||||
if not match:
|
||||
raise ValueError(
|
||||
f"Invalid Language field format: {value!r}. "
|
||||
f"Expected 'll', 'll_CC' or 'll_CC@variant'"
|
||||
)
|
||||
|
||||
self.__language_code = match.group("language")
|
||||
self.__country_code = match.group("country") # may be None
|
||||
self.__variant = match.group("variant") # may be None
|
||||
|
||||
self.__validate_language(self.__language_code)
|
||||
if self.__country_code:
|
||||
self.__validate_country(self.__country_code)
|
||||
|
||||
# region: Internal validation helpers
|
||||
|
||||
@staticmethod
|
||||
def __validate_language(language_code: str) -> None:
|
||||
"""Validate the language code as an ISO 639 code using pycountry."""
|
||||
lang = pycountry.languages.get(alpha_2=language_code)
|
||||
if lang is None:
|
||||
lang = pycountry.languages.get(alpha_3=language_code)
|
||||
if lang is None:
|
||||
raise ValueError(f"Invalid language code: {language_code!r}")
|
||||
|
||||
@staticmethod
|
||||
def __validate_country(country_code: str) -> None:
|
||||
"""Validate the country code as an ISO 3166 alpha-2 code using pycountry."""
|
||||
country = pycountry.countries.get(alpha_2=country_code)
|
||||
if country is None:
|
||||
raise ValueError(f"Invalid country code: {country_code!r}")
|
||||
|
||||
# endregion
|
||||
|
||||
# region: Properties
|
||||
|
||||
@property
|
||||
def language(self) -> str:
|
||||
"""The lowercase language code."""
|
||||
return self.__language_code
|
||||
|
||||
@property
|
||||
def country(self) -> str | None:
|
||||
"""The uppercase country code, or None if not specified."""
|
||||
return self.__country_code
|
||||
|
||||
@property
|
||||
def variant(self) -> str | None:
|
||||
"""The lowercase variant identifier, or None if not specified."""
|
||||
return self.__variant
|
||||
|
||||
@property
|
||||
def value(self) -> str:
|
||||
"""The canonical string representation, rebuilt from the components."""
|
||||
result = self.__language_code
|
||||
if self.__country_code is not None:
|
||||
result += f"_{self.__country_code}"
|
||||
if self.__variant is not None:
|
||||
result += f"@{self.__variant}"
|
||||
return result
|
||||
|
||||
# endregion
|
||||
|
||||
# region: Object methods
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"PoLang({self.value!r})"
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if self is other:
|
||||
return True
|
||||
if not isinstance(other, PoLang):
|
||||
return NotImplemented
|
||||
return (
|
||||
self.__language_code == other.__language_code
|
||||
and self.__country_code == other.__country_code
|
||||
and self.__variant == other.__variant
|
||||
)
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash((self.__language_code, self.__country_code, self.__variant))
|
||||
|
||||
# endregion
|
||||
|
||||
|
||||
class WinLcid:
|
||||
"""
|
||||
Represents a Windows language identifier (LANGID), the 2-byte language
|
||||
component of a Windows LCID (see [MS-LCID] section 2.2).
|
||||
|
||||
A LANGID combines a 10-bit primary language identifier and a 6-bit
|
||||
sublanguage identifier. This is the value used by the LANGUAGE statement of
|
||||
RC STRINGTABLE resources and the "Translation" value of VERSIONINFO
|
||||
resources, so unlike a full 4-byte LCID it carries no sort identifier.
|
||||
|
||||
The value is only loosely validated: it must fit into 2 bytes, but it is
|
||||
not checked against the identifiers actually assigned by Microsoft.
|
||||
|
||||
Examples:
|
||||
WinLcid(0x0409) # valid
|
||||
WinLcid(0x7C14) # valid
|
||||
WinLcid(0x10000) # invalid (exceeds the 2-byte range)
|
||||
"""
|
||||
|
||||
__value: int
|
||||
"""The LANGID value, from 0x0000 to 0xFFFF."""
|
||||
|
||||
def __init__(self, value: int):
|
||||
if not 0 <= value <= 0xFFFF:
|
||||
raise ValueError(
|
||||
f"Invalid language identifier value: {value:#x}. "
|
||||
f"Expected a 2-byte integer between 0x0000 and 0xFFFF"
|
||||
)
|
||||
self.__value = value
|
||||
|
||||
@classmethod
|
||||
def from_parts(cls, primary: int, sublanguage: int) -> "WinLcid":
|
||||
"""
|
||||
Create a language identifier from a primary/sublanguage pair, as used
|
||||
by the two-number form of the RC LANGUAGE statement.
|
||||
|
||||
:param primary: The primary language identifier (10 bits).
|
||||
:param sublanguage: The sublanguage identifier (6 bits).
|
||||
:return: The combined language identifier.
|
||||
"""
|
||||
if not 0 <= primary <= 0x3FF:
|
||||
raise ValueError(
|
||||
f"Invalid primary language identifier: {primary:#x}. "
|
||||
f"Expected a 10-bit integer between 0x000 and 0x3FF"
|
||||
)
|
||||
if not 0 <= sublanguage <= 0x3F:
|
||||
raise ValueError(
|
||||
f"Invalid sublanguage identifier: {sublanguage:#x}. "
|
||||
f"Expected a 6-bit integer between 0x00 and 0x3F"
|
||||
)
|
||||
return cls((sublanguage << 10) | primary)
|
||||
|
||||
# region: Properties
|
||||
|
||||
@property
|
||||
def value(self) -> int:
|
||||
"""The LANGID value as an integer."""
|
||||
return self.__value
|
||||
|
||||
@property
|
||||
def primary(self) -> int:
|
||||
"""The primary language identifier (the low-order 10 bits)."""
|
||||
return self.__value & 0x3FF
|
||||
|
||||
@property
|
||||
def sublanguage(self) -> int:
|
||||
"""The sublanguage identifier (the high-order 6 bits)."""
|
||||
return self.__value >> 10
|
||||
|
||||
# endregion
|
||||
|
||||
# region: Object methods
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"0x{self.__value:04X}"
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"WinLcid(0x{self.__value:04X})"
|
||||
|
||||
def __eq__(self, other) -> bool:
|
||||
if self is other:
|
||||
return True
|
||||
if not isinstance(other, WinLcid):
|
||||
return NotImplemented
|
||||
return self.__value == other.__value
|
||||
|
||||
def __hash__(self) -> int:
|
||||
return hash(self.__value)
|
||||
|
||||
# endregion
|
||||
@@ -0,0 +1,524 @@
|
||||
from ..langid import PoLang, WinLcid
|
||||
|
||||
# YYC MARK: The table below is transcribed from the 'Language ID' table in
|
||||
# [MS-LCID] section 2.2 (revision 2024-04-23). Underscore separators in the
|
||||
# original language tags have been normalized to hyphens
|
||||
# (e.g. 'es-ES_tradnl' -> 'es-ES-tradnl').
|
||||
# YYC MARK: Rows whose tags are marked 'reserved' in the document are kept
|
||||
# for transcription fidelity but commented out with a leading '#', so they
|
||||
# carry no runtime effect and lookups on them fail.
|
||||
# YYC MARK: Rows without a usable language tag are omitted entirely: values
|
||||
# that are neither defined nor reserved, the invariant-locale value 0x007F,
|
||||
# the user-default and unspecified placeholders 0x0C00/0x1000 (harmful
|
||||
# process-local values that must never be persisted into RC resources), and
|
||||
# the transient LCIDs 0x2000-0x4C00.
|
||||
# YYC MARK: Rows carrying multiple tags for one value (e.g.
|
||||
# 'ff-NG, ff-Latn-NG') are expanded into consecutive entries sharing the
|
||||
# same WinLcid.
|
||||
# YYC MARK: The alternate-sort table of section 2.2 (full 4-byte LCIDs with
|
||||
# sort identifiers, e.g. 'de-DE_phoneb' 0x00010407) is not transcribed:
|
||||
# WinLcid only models the 2-byte language identifier used by RC resources.
|
||||
# YYC MARK: Known contradiction inside the document: the appendix assigns
|
||||
# 'quc' -> 0x0086 and 'quc-Latn-GT' -> 0x0486, while the section 2.2 registry
|
||||
# has 'qut' -> 0x0086 and marks 'quc' (0x0093), 'qut-GT' (0x0486) and
|
||||
# 'quc-CO' (0x0493) as reserved. The section 2.2 registry wins here.
|
||||
|
||||
_LCID_TAGS: dict[str, WinLcid] = {
|
||||
"ar": WinLcid(0x0001),
|
||||
"bg": WinLcid(0x0002),
|
||||
"ca": WinLcid(0x0003),
|
||||
"zh-Hans": WinLcid(0x0004),
|
||||
"cs": WinLcid(0x0005),
|
||||
"da": WinLcid(0x0006),
|
||||
"de": WinLcid(0x0007),
|
||||
"el": WinLcid(0x0008),
|
||||
"en": WinLcid(0x0009),
|
||||
"es": WinLcid(0x000A),
|
||||
"fi": WinLcid(0x000B),
|
||||
"fr": WinLcid(0x000C),
|
||||
"he": WinLcid(0x000D),
|
||||
"hu": WinLcid(0x000E),
|
||||
"is": WinLcid(0x000F),
|
||||
"it": WinLcid(0x0010),
|
||||
"ja": WinLcid(0x0011),
|
||||
"ko": WinLcid(0x0012),
|
||||
"nl": WinLcid(0x0013),
|
||||
"no": WinLcid(0x0014),
|
||||
"pl": WinLcid(0x0015),
|
||||
"pt": WinLcid(0x0016),
|
||||
"rm": WinLcid(0x0017),
|
||||
"ro": WinLcid(0x0018),
|
||||
"ru": WinLcid(0x0019),
|
||||
"hr": WinLcid(0x001A),
|
||||
"sk": WinLcid(0x001B),
|
||||
"sq": WinLcid(0x001C),
|
||||
"sv": WinLcid(0x001D),
|
||||
"th": WinLcid(0x001E),
|
||||
"tr": WinLcid(0x001F),
|
||||
"ur": WinLcid(0x0020),
|
||||
"id": WinLcid(0x0021),
|
||||
"uk": WinLcid(0x0022),
|
||||
"be": WinLcid(0x0023),
|
||||
"sl": WinLcid(0x0024),
|
||||
"et": WinLcid(0x0025),
|
||||
"lv": WinLcid(0x0026),
|
||||
"lt": WinLcid(0x0027),
|
||||
"tg": WinLcid(0x0028),
|
||||
"fa": WinLcid(0x0029),
|
||||
"vi": WinLcid(0x002A),
|
||||
"hy": WinLcid(0x002B),
|
||||
"az": WinLcid(0x002C),
|
||||
"eu": WinLcid(0x002D),
|
||||
"hsb": WinLcid(0x002E),
|
||||
"mk": WinLcid(0x002F),
|
||||
"st": WinLcid(0x0030),
|
||||
"ts": WinLcid(0x0031),
|
||||
"tn": WinLcid(0x0032),
|
||||
"ve": WinLcid(0x0033),
|
||||
"xh": WinLcid(0x0034),
|
||||
"zu": WinLcid(0x0035),
|
||||
"af": WinLcid(0x0036),
|
||||
"ka": WinLcid(0x0037),
|
||||
"fo": WinLcid(0x0038),
|
||||
"hi": WinLcid(0x0039),
|
||||
"mt": WinLcid(0x003A),
|
||||
"se": WinLcid(0x003B),
|
||||
"ga": WinLcid(0x003C),
|
||||
# "yi": WinLcid(0x003D), # reserved
|
||||
"ms": WinLcid(0x003E),
|
||||
"kk": WinLcid(0x003F),
|
||||
"ky": WinLcid(0x0040),
|
||||
"sw": WinLcid(0x0041),
|
||||
"tk": WinLcid(0x0042),
|
||||
"uz": WinLcid(0x0043),
|
||||
"tt": WinLcid(0x0044),
|
||||
"bn": WinLcid(0x0045),
|
||||
"pa": WinLcid(0x0046),
|
||||
"gu": WinLcid(0x0047),
|
||||
"or": WinLcid(0x0048),
|
||||
"ta": WinLcid(0x0049),
|
||||
"te": WinLcid(0x004A),
|
||||
"kn": WinLcid(0x004B),
|
||||
"ml": WinLcid(0x004C),
|
||||
"as": WinLcid(0x004D),
|
||||
"mr": WinLcid(0x004E),
|
||||
"sa": WinLcid(0x004F),
|
||||
"mn": WinLcid(0x0050),
|
||||
"bo": WinLcid(0x0051),
|
||||
"cy": WinLcid(0x0052),
|
||||
"km": WinLcid(0x0053),
|
||||
"lo": WinLcid(0x0054),
|
||||
"my": WinLcid(0x0055),
|
||||
"gl": WinLcid(0x0056),
|
||||
"kok": WinLcid(0x0057),
|
||||
# "mni": WinLcid(0x0058), # reserved
|
||||
"sd": WinLcid(0x0059),
|
||||
"syr": WinLcid(0x005A),
|
||||
"si": WinLcid(0x005B),
|
||||
"chr": WinLcid(0x005C),
|
||||
"iu": WinLcid(0x005D),
|
||||
"am": WinLcid(0x005E),
|
||||
"tzm": WinLcid(0x005F),
|
||||
"ks": WinLcid(0x0060),
|
||||
"ne": WinLcid(0x0061),
|
||||
"fy": WinLcid(0x0062),
|
||||
"ps": WinLcid(0x0063),
|
||||
"fil": WinLcid(0x0064),
|
||||
"dv": WinLcid(0x0065),
|
||||
# "bin": WinLcid(0x0066), # reserved
|
||||
"ff": WinLcid(0x0067),
|
||||
"ha": WinLcid(0x0068),
|
||||
# "ibb": WinLcid(0x0069), # reserved
|
||||
"yo": WinLcid(0x006A),
|
||||
"quz": WinLcid(0x006B),
|
||||
"nso": WinLcid(0x006C),
|
||||
"ba": WinLcid(0x006D),
|
||||
"lb": WinLcid(0x006E),
|
||||
"kl": WinLcid(0x006F),
|
||||
"ig": WinLcid(0x0070),
|
||||
# "kr": WinLcid(0x0071), # reserved
|
||||
"om": WinLcid(0x0072),
|
||||
"ti": WinLcid(0x0073),
|
||||
"gn": WinLcid(0x0074),
|
||||
"haw": WinLcid(0x0075),
|
||||
# "la": WinLcid(0x0076), # reserved
|
||||
# "so": WinLcid(0x0077), # reserved
|
||||
"ii": WinLcid(0x0078),
|
||||
# "pap": WinLcid(0x0079), # reserved
|
||||
"arn": WinLcid(0x007A),
|
||||
"moh": WinLcid(0x007C),
|
||||
"br": WinLcid(0x007E),
|
||||
"ug": WinLcid(0x0080),
|
||||
"mi": WinLcid(0x0081),
|
||||
"oc": WinLcid(0x0082),
|
||||
"co": WinLcid(0x0083),
|
||||
"gsw": WinLcid(0x0084),
|
||||
"sah": WinLcid(0x0085),
|
||||
"qut": WinLcid(0x0086),
|
||||
"rw": WinLcid(0x0087),
|
||||
"wo": WinLcid(0x0088),
|
||||
"prs": WinLcid(0x008C),
|
||||
"gd": WinLcid(0x0091),
|
||||
"ku": WinLcid(0x0092),
|
||||
# "quc": WinLcid(0x0093), # reserved
|
||||
"ar-SA": WinLcid(0x0401),
|
||||
"bg-BG": WinLcid(0x0402),
|
||||
"ca-ES": WinLcid(0x0403),
|
||||
"zh-TW": WinLcid(0x0404),
|
||||
"cs-CZ": WinLcid(0x0405),
|
||||
"da-DK": WinLcid(0x0406),
|
||||
"de-DE": WinLcid(0x0407),
|
||||
"el-GR": WinLcid(0x0408),
|
||||
"en-US": WinLcid(0x0409),
|
||||
"es-ES-tradnl": WinLcid(0x040A),
|
||||
"fi-FI": WinLcid(0x040B),
|
||||
"fr-FR": WinLcid(0x040C),
|
||||
"he-IL": WinLcid(0x040D),
|
||||
"hu-HU": WinLcid(0x040E),
|
||||
"is-IS": WinLcid(0x040F),
|
||||
"it-IT": WinLcid(0x0410),
|
||||
"ja-JP": WinLcid(0x0411),
|
||||
"ko-KR": WinLcid(0x0412),
|
||||
"nl-NL": WinLcid(0x0413),
|
||||
"nb-NO": WinLcid(0x0414),
|
||||
"pl-PL": WinLcid(0x0415),
|
||||
"pt-BR": WinLcid(0x0416),
|
||||
"rm-CH": WinLcid(0x0417),
|
||||
"ro-RO": WinLcid(0x0418),
|
||||
"ru-RU": WinLcid(0x0419),
|
||||
"hr-HR": WinLcid(0x041A),
|
||||
"sk-SK": WinLcid(0x041B),
|
||||
"sq-AL": WinLcid(0x041C),
|
||||
"sv-SE": WinLcid(0x041D),
|
||||
"th-TH": WinLcid(0x041E),
|
||||
"tr-TR": WinLcid(0x041F),
|
||||
"ur-PK": WinLcid(0x0420),
|
||||
"id-ID": WinLcid(0x0421),
|
||||
"uk-UA": WinLcid(0x0422),
|
||||
"be-BY": WinLcid(0x0423),
|
||||
"sl-SI": WinLcid(0x0424),
|
||||
"et-EE": WinLcid(0x0425),
|
||||
"lv-LV": WinLcid(0x0426),
|
||||
"lt-LT": WinLcid(0x0427),
|
||||
"tg-Cyrl-TJ": WinLcid(0x0428),
|
||||
"fa-IR": WinLcid(0x0429),
|
||||
"vi-VN": WinLcid(0x042A),
|
||||
"hy-AM": WinLcid(0x042B),
|
||||
"az-Latn-AZ": WinLcid(0x042C),
|
||||
"eu-ES": WinLcid(0x042D),
|
||||
"hsb-DE": WinLcid(0x042E),
|
||||
"mk-MK": WinLcid(0x042F),
|
||||
"st-ZA": WinLcid(0x0430),
|
||||
"ts-ZA": WinLcid(0x0431),
|
||||
"tn-ZA": WinLcid(0x0432),
|
||||
"ve-ZA": WinLcid(0x0433),
|
||||
"xh-ZA": WinLcid(0x0434),
|
||||
"zu-ZA": WinLcid(0x0435),
|
||||
"af-ZA": WinLcid(0x0436),
|
||||
"ka-GE": WinLcid(0x0437),
|
||||
"fo-FO": WinLcid(0x0438),
|
||||
"hi-IN": WinLcid(0x0439),
|
||||
"mt-MT": WinLcid(0x043A),
|
||||
"se-NO": WinLcid(0x043B),
|
||||
"yi-001": WinLcid(0x043D),
|
||||
"ms-MY": WinLcid(0x043E),
|
||||
"kk-KZ": WinLcid(0x043F),
|
||||
"ky-KG": WinLcid(0x0440),
|
||||
"sw-KE": WinLcid(0x0441),
|
||||
"tk-TM": WinLcid(0x0442),
|
||||
"uz-Latn-UZ": WinLcid(0x0443),
|
||||
"tt-RU": WinLcid(0x0444),
|
||||
"bn-IN": WinLcid(0x0445),
|
||||
"pa-IN": WinLcid(0x0446),
|
||||
"gu-IN": WinLcid(0x0447),
|
||||
"or-IN": WinLcid(0x0448),
|
||||
"ta-IN": WinLcid(0x0449),
|
||||
"te-IN": WinLcid(0x044A),
|
||||
"kn-IN": WinLcid(0x044B),
|
||||
"ml-IN": WinLcid(0x044C),
|
||||
"as-IN": WinLcid(0x044D),
|
||||
"mr-IN": WinLcid(0x044E),
|
||||
"sa-IN": WinLcid(0x044F),
|
||||
"mn-MN": WinLcid(0x0450),
|
||||
"bo-CN": WinLcid(0x0451),
|
||||
"cy-GB": WinLcid(0x0452),
|
||||
"km-KH": WinLcid(0x0453),
|
||||
"lo-LA": WinLcid(0x0454),
|
||||
"my-MM": WinLcid(0x0455),
|
||||
"gl-ES": WinLcid(0x0456),
|
||||
"kok-IN": WinLcid(0x0457),
|
||||
# "mni-IN": WinLcid(0x0458), # reserved
|
||||
# "sd-Deva-IN": WinLcid(0x0459), # reserved
|
||||
"syr-SY": WinLcid(0x045A),
|
||||
"si-LK": WinLcid(0x045B),
|
||||
"chr-Cher-US": WinLcid(0x045C),
|
||||
"iu-Cans-CA": WinLcid(0x045D),
|
||||
"am-ET": WinLcid(0x045E),
|
||||
"tzm-Arab-MA": WinLcid(0x045F),
|
||||
"ks-Arab": WinLcid(0x0460),
|
||||
"ne-NP": WinLcid(0x0461),
|
||||
"fy-NL": WinLcid(0x0462),
|
||||
"ps-AF": WinLcid(0x0463),
|
||||
"fil-PH": WinLcid(0x0464),
|
||||
"dv-MV": WinLcid(0x0465),
|
||||
# "bin-NG": WinLcid(0x0466), # reserved
|
||||
"ff-NG": WinLcid(0x0467),
|
||||
"ff-Latn-NG": WinLcid(0x0467),
|
||||
"ha-Latn-NG": WinLcid(0x0468),
|
||||
# "ibb-NG": WinLcid(0x0469), # reserved
|
||||
"yo-NG": WinLcid(0x046A),
|
||||
"quz-BO": WinLcid(0x046B),
|
||||
"nso-ZA": WinLcid(0x046C),
|
||||
"ba-RU": WinLcid(0x046D),
|
||||
"lb-LU": WinLcid(0x046E),
|
||||
"kl-GL": WinLcid(0x046F),
|
||||
"ig-NG": WinLcid(0x0470),
|
||||
"kr-Latn-NG": WinLcid(0x0471),
|
||||
"om-ET": WinLcid(0x0472),
|
||||
"ti-ET": WinLcid(0x0473),
|
||||
"gn-PY": WinLcid(0x0474),
|
||||
"haw-US": WinLcid(0x0475),
|
||||
"la-VA": WinLcid(0x0476),
|
||||
"so-SO": WinLcid(0x0477),
|
||||
"ii-CN": WinLcid(0x0478),
|
||||
# "pap-029": WinLcid(0x0479), # reserved
|
||||
"arn-CL": WinLcid(0x047A),
|
||||
"moh-CA": WinLcid(0x047C),
|
||||
"br-FR": WinLcid(0x047E),
|
||||
"ug-CN": WinLcid(0x0480),
|
||||
"mi-NZ": WinLcid(0x0481),
|
||||
"oc-FR": WinLcid(0x0482),
|
||||
"co-FR": WinLcid(0x0483),
|
||||
"gsw-FR": WinLcid(0x0484),
|
||||
"sah-RU": WinLcid(0x0485),
|
||||
# "qut-GT": WinLcid(0x0486), # reserved
|
||||
"rw-RW": WinLcid(0x0487),
|
||||
"wo-SN": WinLcid(0x0488),
|
||||
"prs-AF": WinLcid(0x048C),
|
||||
# "plt-MG": WinLcid(0x048D), # reserved
|
||||
# "zh-yue-HK": WinLcid(0x048E), # reserved
|
||||
# "tdd-Tale-CN": WinLcid(0x048F), # reserved
|
||||
# "khb-Talu-CN": WinLcid(0x0490), # reserved
|
||||
"gd-GB": WinLcid(0x0491),
|
||||
"ku-Arab-IQ": WinLcid(0x0492),
|
||||
# "quc-CO": WinLcid(0x0493), # reserved
|
||||
"qps-ploc": WinLcid(0x0501),
|
||||
"qps-ploca": WinLcid(0x05FE),
|
||||
"ar-IQ": WinLcid(0x0801),
|
||||
"ca-ES-valencia": WinLcid(0x0803),
|
||||
"zh-CN": WinLcid(0x0804),
|
||||
"de-CH": WinLcid(0x0807),
|
||||
"en-GB": WinLcid(0x0809),
|
||||
"es-MX": WinLcid(0x080A),
|
||||
"fr-BE": WinLcid(0x080C),
|
||||
"it-CH": WinLcid(0x0810),
|
||||
# "ja-Ploc-JP": WinLcid(0x0811), # reserved
|
||||
"nl-BE": WinLcid(0x0813),
|
||||
"nn-NO": WinLcid(0x0814),
|
||||
"pt-PT": WinLcid(0x0816),
|
||||
"ro-MD": WinLcid(0x0818),
|
||||
"ru-MD": WinLcid(0x0819),
|
||||
"sr-Latn-CS": WinLcid(0x081A),
|
||||
"sv-FI": WinLcid(0x081D),
|
||||
"ur-IN": WinLcid(0x0820),
|
||||
# "az-Cyrl-AZ": WinLcid(0x082C), # reserved
|
||||
"dsb-DE": WinLcid(0x082E),
|
||||
"tn-BW": WinLcid(0x0832),
|
||||
"se-SE": WinLcid(0x083B),
|
||||
"ga-IE": WinLcid(0x083C),
|
||||
"ms-BN": WinLcid(0x083E),
|
||||
# "kk-Latn-KZ": WinLcid(0x083F), # reserved
|
||||
# "uz-Cyrl-UZ": WinLcid(0x0843), # reserved
|
||||
"bn-BD": WinLcid(0x0845),
|
||||
"pa-Arab-PK": WinLcid(0x0846),
|
||||
"ta-LK": WinLcid(0x0849),
|
||||
# "mn-Mong-CN": WinLcid(0x0850), # reserved
|
||||
# "bo-BT": WinLcid(0x0851), # reserved
|
||||
"sd-Arab-PK": WinLcid(0x0859),
|
||||
"iu-Latn-CA": WinLcid(0x085D),
|
||||
"tzm-Latn-DZ": WinLcid(0x085F),
|
||||
"ks-Deva-IN": WinLcid(0x0860),
|
||||
"ne-IN": WinLcid(0x0861),
|
||||
"ff-Latn-SN": WinLcid(0x0867),
|
||||
"quz-EC": WinLcid(0x086B),
|
||||
"ti-ER": WinLcid(0x0873),
|
||||
"qps-plocm": WinLcid(0x09FF),
|
||||
"ar-EG": WinLcid(0x0C01),
|
||||
"zh-HK": WinLcid(0x0C04),
|
||||
"de-AT": WinLcid(0x0C07),
|
||||
"en-AU": WinLcid(0x0C09),
|
||||
"es-ES": WinLcid(0x0C0A),
|
||||
"fr-CA": WinLcid(0x0C0C),
|
||||
"sr-Cyrl-CS": WinLcid(0x0C1A),
|
||||
"se-FI": WinLcid(0x0C3B),
|
||||
"mn-Mong-MN": WinLcid(0x0C50),
|
||||
"dz-BT": WinLcid(0x0C51),
|
||||
# "tmz-MA": WinLcid(0x0C5F), # reserved
|
||||
"quz-PE": WinLcid(0x0C6B),
|
||||
"ar-LY": WinLcid(0x1001),
|
||||
"zh-SG": WinLcid(0x1004),
|
||||
"de-LU": WinLcid(0x1007),
|
||||
"en-CA": WinLcid(0x1009),
|
||||
"es-GT": WinLcid(0x100A),
|
||||
"fr-CH": WinLcid(0x100C),
|
||||
"hr-BA": WinLcid(0x101A),
|
||||
"smj-NO": WinLcid(0x103B),
|
||||
"tzm-Tfng-MA": WinLcid(0x105F),
|
||||
"ar-DZ": WinLcid(0x1401),
|
||||
"zh-MO": WinLcid(0x1404),
|
||||
"de-LI": WinLcid(0x1407),
|
||||
"en-NZ": WinLcid(0x1409),
|
||||
"es-CR": WinLcid(0x140A),
|
||||
"fr-LU": WinLcid(0x140C),
|
||||
"bs-Latn-BA": WinLcid(0x141A),
|
||||
"smj-SE": WinLcid(0x143B),
|
||||
"ar-MA": WinLcid(0x1801),
|
||||
"en-IE": WinLcid(0x1809),
|
||||
"es-PA": WinLcid(0x180A),
|
||||
"fr-MC": WinLcid(0x180C),
|
||||
"sr-Latn-BA": WinLcid(0x181A),
|
||||
"sma-NO": WinLcid(0x183B),
|
||||
"ar-TN": WinLcid(0x1C01),
|
||||
"en-ZA": WinLcid(0x1C09),
|
||||
"es-DO": WinLcid(0x1C0A),
|
||||
"fr-029": WinLcid(0x1C0C),
|
||||
"sr-Cyrl-BA": WinLcid(0x1C1A),
|
||||
"sma-SE": WinLcid(0x1C3B),
|
||||
"ar-OM": WinLcid(0x2001),
|
||||
"en-JM": WinLcid(0x2009),
|
||||
"es-VE": WinLcid(0x200A),
|
||||
"fr-RE": WinLcid(0x200C),
|
||||
"bs-Cyrl-BA": WinLcid(0x201A),
|
||||
"sms-FI": WinLcid(0x203B),
|
||||
"ar-YE": WinLcid(0x2401),
|
||||
# "en-029": WinLcid(0x2409), # reserved
|
||||
"es-CO": WinLcid(0x240A),
|
||||
"fr-CD": WinLcid(0x240C),
|
||||
"sr-Latn-RS": WinLcid(0x241A),
|
||||
"smn-FI": WinLcid(0x243B),
|
||||
"ar-SY": WinLcid(0x2801),
|
||||
"en-BZ": WinLcid(0x2809),
|
||||
"es-PE": WinLcid(0x280A),
|
||||
"fr-SN": WinLcid(0x280C),
|
||||
"sr-Cyrl-RS": WinLcid(0x281A),
|
||||
"ar-JO": WinLcid(0x2C01),
|
||||
"en-TT": WinLcid(0x2C09),
|
||||
"es-AR": WinLcid(0x2C0A),
|
||||
"fr-CM": WinLcid(0x2C0C),
|
||||
"sr-Latn-ME": WinLcid(0x2C1A),
|
||||
"ar-LB": WinLcid(0x3001),
|
||||
"en-ZW": WinLcid(0x3009),
|
||||
"es-EC": WinLcid(0x300A),
|
||||
"fr-CI": WinLcid(0x300C),
|
||||
"sr-Cyrl-ME": WinLcid(0x301A),
|
||||
"ar-KW": WinLcid(0x3401),
|
||||
"en-PH": WinLcid(0x3409),
|
||||
"es-CL": WinLcid(0x340A),
|
||||
"fr-ML": WinLcid(0x340C),
|
||||
"ar-AE": WinLcid(0x3801),
|
||||
# "en-ID": WinLcid(0x3809), # reserved
|
||||
"es-UY": WinLcid(0x380A),
|
||||
"fr-MA": WinLcid(0x380C),
|
||||
"ar-BH": WinLcid(0x3C01),
|
||||
"en-HK": WinLcid(0x3C09),
|
||||
"es-PY": WinLcid(0x3C0A),
|
||||
"fr-HT": WinLcid(0x3C0C),
|
||||
"ar-QA": WinLcid(0x4001),
|
||||
"en-IN": WinLcid(0x4009),
|
||||
"es-BO": WinLcid(0x400A),
|
||||
# "ar-Ploc-SA": WinLcid(0x4401), # reserved
|
||||
"en-MY": WinLcid(0x4409),
|
||||
"es-SV": WinLcid(0x440A),
|
||||
# "ar-145": WinLcid(0x4801), # reserved
|
||||
"en-SG": WinLcid(0x4809),
|
||||
"es-HN": WinLcid(0x480A),
|
||||
"en-AE": WinLcid(0x4C09),
|
||||
"es-NI": WinLcid(0x4C0A),
|
||||
# "en-BH": WinLcid(0x5009), # reserved
|
||||
"es-PR": WinLcid(0x500A),
|
||||
# "en-EG": WinLcid(0x5409), # reserved
|
||||
"es-US": WinLcid(0x540A),
|
||||
# "en-JO": WinLcid(0x5809), # reserved
|
||||
# "es-419": WinLcid(0x580A), # reserved
|
||||
# "en-KW": WinLcid(0x5C09), # reserved
|
||||
"es-CU": WinLcid(0x5C0A),
|
||||
# "en-TR": WinLcid(0x6009), # reserved
|
||||
# "en-YE": WinLcid(0x6409), # reserved
|
||||
"bs-Cyrl": WinLcid(0x641A),
|
||||
"bs-Latn": WinLcid(0x681A),
|
||||
"sr-Cyrl": WinLcid(0x6C1A),
|
||||
"sr-Latn": WinLcid(0x701A),
|
||||
"smn": WinLcid(0x703B),
|
||||
"az-Cyrl": WinLcid(0x742C),
|
||||
"sms": WinLcid(0x743B),
|
||||
"zh": WinLcid(0x7804),
|
||||
"nn": WinLcid(0x7814),
|
||||
"bs": WinLcid(0x781A),
|
||||
"az-Latn": WinLcid(0x782C),
|
||||
"sma": WinLcid(0x783B),
|
||||
# "kk-Cyrl": WinLcid(0x783F), # reserved
|
||||
"uz-Cyrl": WinLcid(0x7843),
|
||||
"mn-Cyrl": WinLcid(0x7850),
|
||||
"iu-Cans": WinLcid(0x785D),
|
||||
"tzm-Tfng": WinLcid(0x785F),
|
||||
"zh-Hant": WinLcid(0x7C04),
|
||||
"nb": WinLcid(0x7C14),
|
||||
"sr": WinLcid(0x7C1A),
|
||||
"tg-Cyrl": WinLcid(0x7C28),
|
||||
"dsb": WinLcid(0x7C2E),
|
||||
"smj": WinLcid(0x7C3B),
|
||||
# "kk-Latn": WinLcid(0x7C3F), # reserved
|
||||
"uz-Latn": WinLcid(0x7C43),
|
||||
"pa-Arab": WinLcid(0x7C46),
|
||||
"mn-Mong": WinLcid(0x7C50),
|
||||
"sd-Arab": WinLcid(0x7C59),
|
||||
"chr-Cher": WinLcid(0x7C5C),
|
||||
"iu-Latn": WinLcid(0x7C5D),
|
||||
"tzm-Latn": WinLcid(0x7C5F),
|
||||
"ff-Latn": WinLcid(0x7C67),
|
||||
"ha-Latn": WinLcid(0x7C68),
|
||||
"ku-Arab": WinLcid(0x7C92),
|
||||
# "fr-015": WinLcid(0xE40C), # reserved
|
||||
}
|
||||
|
||||
|
||||
# Gettext-style script designator words mapped to ISO 15924 script codes.
|
||||
# This is not the full ISO 15924 table - it only contains the words that can
|
||||
# hit entries in _LCID_TAGS above. Extend it as needed.
|
||||
_SCRIPT_WORDS: dict[str, str] = {
|
||||
"latin": "Latn",
|
||||
"cyrillic": "Cyrl",
|
||||
"arabic": "Arab",
|
||||
}
|
||||
|
||||
|
||||
def lookup(lang: PoLang) -> WinLcid:
|
||||
"""
|
||||
Resolve a PO file language to its Windows language identifier.
|
||||
|
||||
:param lang: The PO file language.
|
||||
:return: The Windows language identifier for the language.
|
||||
:raises KeyError: If the language has no transcribed mapping.
|
||||
"""
|
||||
if lang.variant is None:
|
||||
segments = [lang.language]
|
||||
if lang.country is not None:
|
||||
segments.append(lang.country)
|
||||
return _LCID_TAGS["-".join(segments)]
|
||||
|
||||
# YYC MARK: PoLang's variant slot may hold either a script designator or a
|
||||
# genuine variant (Gettext semantics), while MS-LCID language tags place
|
||||
# scripts and variants at different positions with different vocabularies
|
||||
# ('cyrillic' != 'Cyrl'), so the conversion cannot be done mechanically.
|
||||
# Candidate matching is done here as a workaround: the variant position is
|
||||
# tried first, then the script position via _SCRIPT_WORDS (which is not
|
||||
# the full ISO 15924 table, only the words that hit entries above).
|
||||
key = f"{lang.language}-{lang.country}-{lang.variant}"
|
||||
if key in _LCID_TAGS:
|
||||
return _LCID_TAGS[key]
|
||||
script = _SCRIPT_WORDS.get(lang.variant)
|
||||
if script is not None:
|
||||
key = f"{lang.language}-{script}-{lang.country}"
|
||||
if key in _LCID_TAGS:
|
||||
return _LCID_TAGS[key]
|
||||
raise KeyError(str(lang))
|
||||
Reference in New Issue
Block a user