Download rtme/lib/python3.10/site-packages/babel/core.py from ckadirt/backup_rtme: direct link, hf CLI and curl.
- Browser
- Download file 45.4 kB
-
https://huggingface.co/ckadirt/backup_rtme/resolve/main/rtme/lib/python3.10/site-packages/babel/core.py
- Command line
-
hf download hf://ckadirt/backup_rtme/rtme/lib/python3.10/site-packages/babel/core.py
-
curl -L -o core.py https://huggingface.co/ckadirt/backup_rtme/resolve/main/rtme/lib/python3.10/site-packages/babel/core.py
45.4 kB
| """ | |
| babel.core | |
| ~~~~~~~~~~ | |
| Core locale representation and locale data access. | |
| :copyright: (c) 2013-2025 by the Babel Team. | |
| :license: BSD, see LICENSE for more details. | |
| """ | |
| from __future__ import annotations | |
| import os | |
| import pickle | |
| from collections.abc import Iterable, Mapping | |
| from typing import TYPE_CHECKING, Any, Literal | |
| from babel import localedata | |
| from babel.plural import PluralRule | |
| __all__ = [ | |
| 'Locale', | |
| 'UnknownLocaleError', | |
| 'default_locale', | |
| 'get_global', | |
| 'get_locale_identifier', | |
| 'negotiate_locale', | |
| 'parse_locale', | |
| ] | |
| if TYPE_CHECKING: | |
| from typing_extensions import TypeAlias | |
| _GLOBAL_KEY: TypeAlias = Literal[ | |
| "all_currencies", | |
| "currency_fractions", | |
| "language_aliases", | |
| "likely_subtags", | |
| "meta_zones", | |
| "parent_exceptions", | |
| "script_aliases", | |
| "territory_aliases", | |
| "territory_currencies", | |
| "territory_languages", | |
| "territory_zones", | |
| "variant_aliases", | |
| "windows_zone_mapping", | |
| "zone_aliases", | |
| "zone_territories", | |
| ] | |
| _global_data: Mapping[_GLOBAL_KEY, Mapping[str, Any]] | None | |
| _global_data = None | |
| _default_plural_rule = PluralRule({}) | |
| def _raise_no_data_error(): | |
| raise RuntimeError('The babel data files are not available. ' | |
| 'This usually happens because you are using ' | |
| 'a source checkout from Babel and you did ' | |
| 'not build the data files. Just make sure ' | |
| 'to run "python setup.py import_cldr" before ' | |
| 'installing the library.') | |
| def get_global(key: _GLOBAL_KEY) -> Mapping[str, Any]: | |
| """Return the dictionary for the given key in the global data. | |
| The global data is stored in the ``babel/global.dat`` file and contains | |
| information independent of individual locales. | |
| >>> get_global('zone_aliases')['UTC'] | |
| u'Etc/UTC' | |
| >>> get_global('zone_territories')['Europe/Berlin'] | |
| u'DE' | |
| The keys available are: | |
| - ``all_currencies`` | |
| - ``currency_fractions`` | |
| - ``language_aliases`` | |
| - ``likely_subtags`` | |
| - ``parent_exceptions`` | |
| - ``script_aliases`` | |
| - ``territory_aliases`` | |
| - ``territory_currencies`` | |
| - ``territory_languages`` | |
| - ``territory_zones`` | |
| - ``variant_aliases`` | |
| - ``windows_zone_mapping`` | |
| - ``zone_aliases`` | |
| - ``zone_territories`` | |
| .. note:: The internal structure of the data may change between versions. | |
| .. versionadded:: 0.9 | |
| :param key: the data key | |
| """ | |
| global _global_data | |
| if _global_data is None: | |
| dirname = os.path.join(os.path.dirname(__file__)) | |
| filename = os.path.join(dirname, 'global.dat') | |
| if not os.path.isfile(filename): | |
| _raise_no_data_error() | |
| with open(filename, 'rb') as fileobj: | |
| _global_data = pickle.load(fileobj) | |
| assert _global_data is not None | |
| return _global_data.get(key, {}) | |
| LOCALE_ALIASES = { | |
| 'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ', | |
| 'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES', | |
| 'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES', | |
| 'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT', | |
| 'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV', | |
| 'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL', | |
| 'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI', | |
| 'sv': 'sv_SE', 'th': 'th_TH', 'tr': 'tr_TR', 'uk': 'uk_UA', | |
| } | |
| class UnknownLocaleError(Exception): | |
| """Exception thrown when a locale is requested for which no locale data | |
| is available. | |
| """ | |
| def __init__(self, identifier: str) -> None: | |
| """Create the exception. | |
| :param identifier: the identifier string of the unsupported locale | |
| """ | |
| Exception.__init__(self, f"unknown locale {identifier!r}") | |
| #: The identifier of the locale that could not be found. | |
| self.identifier = identifier | |
| class Locale: | |
| """Representation of a specific locale. | |
| >>> locale = Locale('en', 'US') | |
| >>> repr(locale) | |
| "Locale('en', territory='US')" | |
| >>> locale.display_name | |
| u'English (United States)' | |
| A `Locale` object can also be instantiated from a raw locale string: | |
| >>> locale = Locale.parse('en-US', sep='-') | |
| >>> repr(locale) | |
| "Locale('en', territory='US')" | |
| `Locale` objects provide access to a collection of locale data, such as | |
| territory and language names, number and date format patterns, and more: | |
| >>> locale.number_symbols['latn']['decimal'] | |
| u'.' | |
| If a locale is requested for which no locale data is available, an | |
| `UnknownLocaleError` is raised: | |
| >>> Locale.parse('en_XX') | |
| Traceback (most recent call last): | |
| ... | |
| UnknownLocaleError: unknown locale 'en_XX' | |
| For more information see :rfc:`3066`. | |
| """ | |
| def __init__( | |
| self, | |
| language: str, | |
| territory: str | None = None, | |
| script: str | None = None, | |
| variant: str | None = None, | |
| modifier: str | None = None, | |
| ) -> None: | |
| """Initialize the locale object from the given identifier components. | |
| >>> locale = Locale('en', 'US') | |
| >>> locale.language | |
| 'en' | |
| >>> locale.territory | |
| 'US' | |
| :param language: the language code | |
| :param territory: the territory (country or region) code | |
| :param script: the script code | |
| :param variant: the variant code | |
| :param modifier: a modifier (following the '@' symbol, sometimes called '@variant') | |
| :raise `UnknownLocaleError`: if no locale data is available for the | |
| requested locale | |
| """ | |
| #: the language code | |
| self.language = language | |
| #: the territory (country or region) code | |
| self.territory = territory | |
| #: the script code | |
| self.script = script | |
| #: the variant code | |
| self.variant = variant | |
| #: the modifier | |
| self.modifier = modifier | |
| self.__data: localedata.LocaleDataDict | None = None | |
| identifier = str(self) | |
| identifier_without_modifier = identifier.partition('@')[0] | |
| if localedata.exists(identifier): | |
| self.__data_identifier = identifier | |
| elif localedata.exists(identifier_without_modifier): | |
| self.__data_identifier = identifier_without_modifier | |
| else: | |
| raise UnknownLocaleError(identifier) | |
| def default(cls, category: str | None = None, aliases: Mapping[str, str] = LOCALE_ALIASES) -> Locale: | |
| """Return the system default locale for the specified category. | |
| >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']: | |
| ... os.environ[name] = '' | |
| >>> os.environ['LANG'] = 'fr_FR.UTF-8' | |
| >>> Locale.default('LC_MESSAGES') | |
| Locale('fr', territory='FR') | |
| The following fallbacks to the variable are always considered: | |
| - ``LANGUAGE`` | |
| - ``LC_ALL`` | |
| - ``LC_CTYPE`` | |
| - ``LANG`` | |
| :param category: one of the ``LC_XXX`` environment variable names | |
| :param aliases: a dictionary of aliases for locale identifiers | |
| """ | |
| # XXX: use likely subtag expansion here instead of the | |
| # aliases dictionary. | |
| locale_string = default_locale(category, aliases=aliases) | |
| return cls.parse(locale_string) | |
| def negotiate( | |
| cls, | |
| preferred: Iterable[str], | |
| available: Iterable[str], | |
| sep: str = '_', | |
| aliases: Mapping[str, str] = LOCALE_ALIASES, | |
| ) -> Locale | None: | |
| """Find the best match between available and requested locale strings. | |
| >>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT']) | |
| Locale('de', territory='DE') | |
| >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de']) | |
| Locale('de') | |
| >>> Locale.negotiate(['de_DE', 'de'], ['en_US']) | |
| You can specify the character used in the locale identifiers to separate | |
| the different components. This separator is applied to both lists. Also, | |
| case is ignored in the comparison: | |
| >>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-') | |
| Locale('de', territory='DE') | |
| :param preferred: the list of locale identifiers preferred by the user | |
| :param available: the list of locale identifiers available | |
| :param aliases: a dictionary of aliases for locale identifiers | |
| :param sep: separator for parsing; e.g. Windows tends to use '-' instead of '_'. | |
| """ | |
| identifier = negotiate_locale(preferred, available, sep=sep, | |
| aliases=aliases) | |
| if identifier: | |
| return Locale.parse(identifier, sep=sep) | |
| return None | |
| def parse( | |
| cls, | |
| identifier: Locale | str | None, | |
| sep: str = '_', | |
| resolve_likely_subtags: bool = True, | |
| ) -> Locale: | |
| """Create a `Locale` instance for the given locale identifier. | |
| >>> l = Locale.parse('de-DE', sep='-') | |
| >>> l.display_name | |
| u'Deutsch (Deutschland)' | |
| If the `identifier` parameter is not a string, but actually a `Locale` | |
| object, that object is returned: | |
| >>> Locale.parse(l) | |
| Locale('de', territory='DE') | |
| If the `identifier` parameter is neither of these, such as `None` | |
| or an empty string, e.g. because a default locale identifier | |
| could not be determined, a `TypeError` is raised: | |
| >>> Locale.parse(None) | |
| Traceback (most recent call last): | |
| ... | |
| TypeError: ... | |
| This also can perform resolving of likely subtags which it does | |
| by default. This is for instance useful to figure out the most | |
| likely locale for a territory you can use ``'und'`` as the | |
| language tag: | |
| >>> Locale.parse('und_AT') | |
| Locale('de', territory='AT') | |
| Modifiers are optional, and always at the end, separated by "@": | |
| >>> Locale.parse('de_AT@euro') | |
| Locale('de', territory='AT', modifier='euro') | |
| :param identifier: the locale identifier string | |
| :param sep: optional component separator | |
| :param resolve_likely_subtags: if this is specified then a locale will | |
| have its likely subtag resolved if the | |
| locale otherwise does not exist. For | |
| instance ``zh_TW`` by itself is not a | |
| locale that exists but Babel can | |
| automatically expand it to the full | |
| form of ``zh_hant_TW``. Note that this | |
| expansion is only taking place if no | |
| locale exists otherwise. For instance | |
| there is a locale ``en`` that can exist | |
| by itself. | |
| :raise `ValueError`: if the string does not appear to be a valid locale | |
| identifier | |
| :raise `UnknownLocaleError`: if no locale data is available for the | |
| requested locale | |
| :raise `TypeError`: if the identifier is not a string or a `Locale` | |
| :raise `ValueError`: if the identifier is not a valid string | |
| """ | |
| if isinstance(identifier, Locale): | |
| return identifier | |
| if not identifier: | |
| msg = ( | |
| f"Empty locale identifier value: {identifier!r}\n\n" | |
| f"If you didn't explicitly pass an empty value to a Babel function, " | |
| f"this could be caused by there being no suitable locale environment " | |
| f"variables for the API you tried to use.", | |
| ) | |
| if isinstance(identifier, str): | |
| raise ValueError(msg) # `parse_locale` would raise a ValueError, so let's do that here | |
| raise TypeError(msg) | |
| if not isinstance(identifier, str): | |
| raise TypeError(f"Unexpected value for identifier: {identifier!r}") | |
| parts = parse_locale(identifier, sep=sep) | |
| input_id = get_locale_identifier(parts) | |
| def _try_load(parts): | |
| try: | |
| return cls(*parts) | |
| except UnknownLocaleError: | |
| return None | |
| def _try_load_reducing(parts): | |
| # Success on first hit, return it. | |
| locale = _try_load(parts) | |
| if locale is not None: | |
| return locale | |
| # Now try without script and variant | |
| locale = _try_load(parts[:2]) | |
| if locale is not None: | |
| return locale | |
| locale = _try_load(parts) | |
| if locale is not None: | |
| return locale | |
| if not resolve_likely_subtags: | |
| raise UnknownLocaleError(input_id) | |
| # From here onwards is some very bad likely subtag resolving. This | |
| # whole logic is not entirely correct but good enough (tm) for the | |
| # time being. This has been added so that zh_TW does not cause | |
| # errors for people when they upgrade. Later we should properly | |
| # implement ICU like fuzzy locale objects and provide a way to | |
| # maximize and minimize locale tags. | |
| if len(parts) == 5: | |
| language, territory, script, variant, modifier = parts | |
| else: | |
| language, territory, script, variant = parts | |
| modifier = None | |
| language = get_global('language_aliases').get(language, language) | |
| territory = get_global('territory_aliases').get(territory or '', (territory,))[0] | |
| script = get_global('script_aliases').get(script or '', script) | |
| variant = get_global('variant_aliases').get(variant or '', variant) | |
| if territory == 'ZZ': | |
| territory = None | |
| if script == 'Zzzz': | |
| script = None | |
| parts = language, territory, script, variant, modifier | |
| # First match: try the whole identifier | |
| new_id = get_locale_identifier(parts) | |
| likely_subtag = get_global('likely_subtags').get(new_id) | |
| if likely_subtag is not None: | |
| locale = _try_load_reducing(parse_locale(likely_subtag)) | |
| if locale is not None: | |
| return locale | |
| # If we did not find anything so far, try again with a | |
| # simplified identifier that is just the language | |
| likely_subtag = get_global('likely_subtags').get(language) | |
| if likely_subtag is not None: | |
| parts2 = parse_locale(likely_subtag) | |
| if len(parts2) == 5: | |
| language2, _, script2, variant2, modifier2 = parts2 | |
| else: | |
| language2, _, script2, variant2 = parts2 | |
| modifier2 = None | |
| locale = _try_load_reducing((language2, territory, script2, variant2, modifier2)) | |
| if locale is not None: | |
| return locale | |
| raise UnknownLocaleError(input_id) | |
| def __eq__(self, other: object) -> bool: | |
| for key in ('language', 'territory', 'script', 'variant', 'modifier'): | |
| if not hasattr(other, key): | |
| return False | |
| return ( | |
| self.language == getattr(other, 'language') and # noqa: B009 | |
| self.territory == getattr(other, 'territory') and # noqa: B009 | |
| self.script == getattr(other, 'script') and # noqa: B009 | |
| self.variant == getattr(other, 'variant') and # noqa: B009 | |
| self.modifier == getattr(other, 'modifier') # noqa: B009 | |
| ) | |
| def __ne__(self, other: object) -> bool: | |
| return not self.__eq__(other) | |
| def __hash__(self) -> int: | |
| return hash((self.language, self.territory, self.script, | |
| self.variant, self.modifier)) | |
| def __repr__(self) -> str: | |
| parameters = [''] | |
| for key in ('territory', 'script', 'variant', 'modifier'): | |
| value = getattr(self, key) | |
| if value is not None: | |
| parameters.append(f"{key}={value!r}") | |
| return f"Locale({self.language!r}{', '.join(parameters)})" | |
| def __str__(self) -> str: | |
| return get_locale_identifier((self.language, self.territory, | |
| self.script, self.variant, | |
| self.modifier)) | |
| def _data(self) -> localedata.LocaleDataDict: | |
| if self.__data is None: | |
| self.__data = localedata.LocaleDataDict(localedata.load(self.__data_identifier)) | |
| return self.__data | |
| def get_display_name(self, locale: Locale | str | None = None) -> str | None: | |
| """Return the display name of the locale using the given locale. | |
| The display name will include the language, territory, script, and | |
| variant, if those are specified. | |
| >>> Locale('zh', 'CN', script='Hans').get_display_name('en') | |
| u'Chinese (Simplified, China)' | |
| Modifiers are currently passed through verbatim: | |
| >>> Locale('it', 'IT', modifier='euro').get_display_name('en') | |
| u'Italian (Italy, euro)' | |
| :param locale: the locale to use | |
| """ | |
| if locale is None: | |
| locale = self | |
| locale = Locale.parse(locale) | |
| retval = locale.languages.get(self.language) | |
| if retval and (self.territory or self.script or self.variant): | |
| details = [] | |
| if self.script: | |
| details.append(locale.scripts.get(self.script)) | |
| if self.territory: | |
| details.append(locale.territories.get(self.territory)) | |
| if self.variant: | |
| details.append(locale.variants.get(self.variant)) | |
| if self.modifier: | |
| details.append(self.modifier) | |
| detail_string = ', '.join(atom for atom in details if atom) | |
| if detail_string: | |
| retval += f" ({detail_string})" | |
| return retval | |
| display_name = property(get_display_name, doc="""\ | |
| The localized display name of the locale. | |
| >>> Locale('en').display_name | |
| u'English' | |
| >>> Locale('en', 'US').display_name | |
| u'English (United States)' | |
| >>> Locale('sv').display_name | |
| u'svenska' | |
| :type: `unicode` | |
| """) | |
| def get_language_name(self, locale: Locale | str | None = None) -> str | None: | |
| """Return the language of this locale in the given locale. | |
| >>> Locale('zh', 'CN', script='Hans').get_language_name('de') | |
| u'Chinesisch' | |
| .. versionadded:: 1.0 | |
| :param locale: the locale to use | |
| """ | |
| if locale is None: | |
| locale = self | |
| locale = Locale.parse(locale) | |
| return locale.languages.get(self.language) | |
| language_name = property(get_language_name, doc="""\ | |
| The localized language name of the locale. | |
| >>> Locale('en', 'US').language_name | |
| u'English' | |
| """) | |
| def get_territory_name(self, locale: Locale | str | None = None) -> str | None: | |
| """Return the territory name in the given locale.""" | |
| if locale is None: | |
| locale = self | |
| locale = Locale.parse(locale) | |
| return locale.territories.get(self.territory or '') | |
| territory_name = property(get_territory_name, doc="""\ | |
| The localized territory name of the locale if available. | |
| >>> Locale('de', 'DE').territory_name | |
| u'Deutschland' | |
| """) | |
| def get_script_name(self, locale: Locale | str | None = None) -> str | None: | |
| """Return the script name in the given locale.""" | |
| if locale is None: | |
| locale = self | |
| locale = Locale.parse(locale) | |
| return locale.scripts.get(self.script or '') | |
| script_name = property(get_script_name, doc="""\ | |
| The localized script name of the locale if available. | |
| >>> Locale('sr', 'ME', script='Latn').script_name | |
| u'latinica' | |
| """) | |
| def english_name(self) -> str | None: | |
| """The english display name of the locale. | |
| >>> Locale('de').english_name | |
| u'German' | |
| >>> Locale('de', 'DE').english_name | |
| u'German (Germany)' | |
| :type: `unicode`""" | |
| return self.get_display_name(Locale('en')) | |
| # { General Locale Display Names | |
| def languages(self) -> localedata.LocaleDataDict: | |
| """Mapping of language codes to translated language names. | |
| >>> Locale('de', 'DE').languages['ja'] | |
| u'Japanisch' | |
| See `ISO 639 <https://www.loc.gov/standards/iso639-2/>`_ for | |
| more information. | |
| """ | |
| return self._data['languages'] | |
| def scripts(self) -> localedata.LocaleDataDict: | |
| """Mapping of script codes to translated script names. | |
| >>> Locale('en', 'US').scripts['Hira'] | |
| u'Hiragana' | |
| See `ISO 15924 <https://www.unicode.org/iso15924/>`_ | |
| for more information. | |
| """ | |
| return self._data['scripts'] | |
| def territories(self) -> localedata.LocaleDataDict: | |
| """Mapping of script codes to translated script names. | |
| >>> Locale('es', 'CO').territories['DE'] | |
| u'Alemania' | |
| See `ISO 3166 <https://en.wikipedia.org/wiki/ISO_3166>`_ | |
| for more information. | |
| """ | |
| return self._data['territories'] | |
| def variants(self) -> localedata.LocaleDataDict: | |
| """Mapping of script codes to translated script names. | |
| >>> Locale('de', 'DE').variants['1901'] | |
| u'Alte deutsche Rechtschreibung' | |
| """ | |
| return self._data['variants'] | |
| # { Number Formatting | |
| def currencies(self) -> localedata.LocaleDataDict: | |
| """Mapping of currency codes to translated currency names. This | |
| only returns the generic form of the currency name, not the count | |
| specific one. If an actual number is requested use the | |
| :func:`babel.numbers.get_currency_name` function. | |
| >>> Locale('en').currencies['COP'] | |
| u'Colombian Peso' | |
| >>> Locale('de', 'DE').currencies['COP'] | |
| u'Kolumbianischer Peso' | |
| """ | |
| return self._data['currency_names'] | |
| def currency_symbols(self) -> localedata.LocaleDataDict: | |
| """Mapping of currency codes to symbols. | |
| >>> Locale('en', 'US').currency_symbols['USD'] | |
| u'$' | |
| >>> Locale('es', 'CO').currency_symbols['USD'] | |
| u'US$' | |
| """ | |
| return self._data['currency_symbols'] | |
| def number_symbols(self) -> localedata.LocaleDataDict: | |
| """Symbols used in number formatting by number system. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('fr', 'FR').number_symbols["latn"]['decimal'] | |
| u',' | |
| >>> Locale('fa', 'IR').number_symbols["arabext"]['decimal'] | |
| u'٫' | |
| >>> Locale('fa', 'IR').number_symbols["latn"]['decimal'] | |
| u'.' | |
| """ | |
| return self._data['number_symbols'] | |
| def other_numbering_systems(self) -> localedata.LocaleDataDict: | |
| """ | |
| Mapping of other numbering systems available for the locale. | |
| See: https://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems | |
| >>> Locale('el', 'GR').other_numbering_systems['traditional'] | |
| u'grek' | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| """ | |
| return self._data['numbering_systems'] | |
| def default_numbering_system(self) -> str: | |
| """The default numbering system used by the locale. | |
| >>> Locale('el', 'GR').default_numbering_system | |
| u'latn' | |
| """ | |
| return self._data['default_numbering_system'] | |
| def decimal_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for decimal number formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').decimal_formats[None] | |
| <NumberPattern u'#,##0.###'> | |
| """ | |
| return self._data['decimal_formats'] | |
| def compact_decimal_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for compact decimal number formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').compact_decimal_formats["short"]["one"]["1000"] | |
| <NumberPattern u'0K'> | |
| """ | |
| return self._data['compact_decimal_formats'] | |
| def currency_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for currency number formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').currency_formats['standard'] | |
| <NumberPattern u'\\xa4#,##0.00'> | |
| >>> Locale('en', 'US').currency_formats['accounting'] | |
| <NumberPattern u'\\xa4#,##0.00;(\\xa4#,##0.00)'> | |
| """ | |
| return self._data['currency_formats'] | |
| def compact_currency_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for compact currency number formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').compact_currency_formats["short"]["one"]["1000"] | |
| <NumberPattern u'¤0K'> | |
| """ | |
| return self._data['compact_currency_formats'] | |
| def percent_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for percent number formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').percent_formats[None] | |
| <NumberPattern u'#,##0%'> | |
| """ | |
| return self._data['percent_formats'] | |
| def scientific_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for scientific number formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').scientific_formats[None] | |
| <NumberPattern u'#E0'> | |
| """ | |
| return self._data['scientific_formats'] | |
| # { Calendar Information and Date Formatting | |
| def periods(self) -> localedata.LocaleDataDict: | |
| """Locale display names for day periods (AM/PM). | |
| >>> Locale('en', 'US').periods['am'] | |
| u'AM' | |
| """ | |
| try: | |
| return self._data['day_periods']['stand-alone']['wide'] | |
| except KeyError: | |
| return localedata.LocaleDataDict({}) # pragma: no cover | |
| def day_periods(self) -> localedata.LocaleDataDict: | |
| """Locale display names for various day periods (not necessarily only AM/PM). | |
| These are not meant to be used without the relevant `day_period_rules`. | |
| """ | |
| return self._data['day_periods'] | |
| def day_period_rules(self) -> localedata.LocaleDataDict: | |
| """Day period rules for the locale. Used by `get_period_id`. | |
| """ | |
| return self._data.get('day_period_rules', localedata.LocaleDataDict({})) | |
| def days(self) -> localedata.LocaleDataDict: | |
| """Locale display names for weekdays. | |
| >>> Locale('de', 'DE').days['format']['wide'][3] | |
| u'Donnerstag' | |
| """ | |
| return self._data['days'] | |
| def months(self) -> localedata.LocaleDataDict: | |
| """Locale display names for months. | |
| >>> Locale('de', 'DE').months['format']['wide'][10] | |
| u'Oktober' | |
| """ | |
| return self._data['months'] | |
| def quarters(self) -> localedata.LocaleDataDict: | |
| """Locale display names for quarters. | |
| >>> Locale('de', 'DE').quarters['format']['wide'][1] | |
| u'1. Quartal' | |
| """ | |
| return self._data['quarters'] | |
| def eras(self) -> localedata.LocaleDataDict: | |
| """Locale display names for eras. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').eras['wide'][1] | |
| u'Anno Domini' | |
| >>> Locale('en', 'US').eras['abbreviated'][0] | |
| u'BC' | |
| """ | |
| return self._data['eras'] | |
| def time_zones(self) -> localedata.LocaleDataDict: | |
| """Locale display names for time zones. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight'] | |
| u'British Summer Time' | |
| >>> Locale('en', 'US').time_zones['America/St_Johns']['city'] | |
| u'St. John\u2019s' | |
| """ | |
| return self._data['time_zones'] | |
| def meta_zones(self) -> localedata.LocaleDataDict: | |
| """Locale display names for meta time zones. | |
| Meta time zones are basically groups of different Olson time zones that | |
| have the same GMT offset and daylight savings time. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight'] | |
| u'Central European Summer Time' | |
| .. versionadded:: 0.9 | |
| """ | |
| return self._data['meta_zones'] | |
| def zone_formats(self) -> localedata.LocaleDataDict: | |
| """Patterns related to the formatting of time zones. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').zone_formats['fallback'] | |
| u'%(1)s (%(0)s)' | |
| >>> Locale('pt', 'BR').zone_formats['region'] | |
| u'Hor\\xe1rio %s' | |
| .. versionadded:: 0.9 | |
| """ | |
| return self._data['zone_formats'] | |
| def first_week_day(self) -> int: | |
| """The first day of a week, with 0 being Monday. | |
| >>> Locale('de', 'DE').first_week_day | |
| 0 | |
| >>> Locale('en', 'US').first_week_day | |
| 6 | |
| """ | |
| return self._data['week_data']['first_day'] | |
| def weekend_start(self) -> int: | |
| """The day the weekend starts, with 0 being Monday. | |
| >>> Locale('de', 'DE').weekend_start | |
| 5 | |
| """ | |
| return self._data['week_data']['weekend_start'] | |
| def weekend_end(self) -> int: | |
| """The day the weekend ends, with 0 being Monday. | |
| >>> Locale('de', 'DE').weekend_end | |
| 6 | |
| """ | |
| return self._data['week_data']['weekend_end'] | |
| def min_week_days(self) -> int: | |
| """The minimum number of days in a week so that the week is counted as | |
| the first week of a year or month. | |
| >>> Locale('de', 'DE').min_week_days | |
| 4 | |
| """ | |
| return self._data['week_data']['min_days'] | |
| def date_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for date formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').date_formats['short'] | |
| <DateTimePattern u'M/d/yy'> | |
| >>> Locale('fr', 'FR').date_formats['long'] | |
| <DateTimePattern u'd MMMM y'> | |
| """ | |
| return self._data['date_formats'] | |
| def time_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for time formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en', 'US').time_formats['short'] | |
| <DateTimePattern u'h:mm\u202fa'> | |
| >>> Locale('fr', 'FR').time_formats['long'] | |
| <DateTimePattern u'HH:mm:ss z'> | |
| """ | |
| return self._data['time_formats'] | |
| def datetime_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for datetime formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en').datetime_formats['full'] | |
| u'{1}, {0}' | |
| >>> Locale('th').datetime_formats['medium'] | |
| u'{1} {0}' | |
| """ | |
| return self._data['datetime_formats'] | |
| def datetime_skeletons(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for formatting parts of a datetime. | |
| >>> Locale('en').datetime_skeletons['MEd'] | |
| <DateTimePattern u'E, M/d'> | |
| >>> Locale('fr').datetime_skeletons['MEd'] | |
| <DateTimePattern u'E dd/MM'> | |
| >>> Locale('fr').datetime_skeletons['H'] | |
| <DateTimePattern u"HH 'h'"> | |
| """ | |
| return self._data['datetime_skeletons'] | |
| def interval_formats(self) -> localedata.LocaleDataDict: | |
| """Locale patterns for interval formatting. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| How to format date intervals in Finnish when the day is the | |
| smallest changing component: | |
| >>> Locale('fi_FI').interval_formats['MEd']['d'] | |
| [u'E d.\u2009\u2013\u2009', u'E d.M.'] | |
| .. seealso:: | |
| The primary API to use this data is :py:func:`babel.dates.format_interval`. | |
| :rtype: dict[str, dict[str, list[str]]] | |
| """ | |
| return self._data['interval_formats'] | |
| def plural_form(self) -> PluralRule: | |
| """Plural rules for the locale. | |
| >>> Locale('en').plural_form(1) | |
| 'one' | |
| >>> Locale('en').plural_form(0) | |
| 'other' | |
| >>> Locale('fr').plural_form(0) | |
| 'one' | |
| >>> Locale('ru').plural_form(100) | |
| 'many' | |
| """ | |
| return self._data.get('plural_form', _default_plural_rule) | |
| def list_patterns(self) -> localedata.LocaleDataDict: | |
| """Patterns for generating lists | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| >>> Locale('en').list_patterns['standard']['start'] | |
| u'{0}, {1}' | |
| >>> Locale('en').list_patterns['standard']['end'] | |
| u'{0}, and {1}' | |
| >>> Locale('en_GB').list_patterns['standard']['end'] | |
| u'{0} and {1}' | |
| """ | |
| return self._data['list_patterns'] | |
| def ordinal_form(self) -> PluralRule: | |
| """Plural rules for the locale. | |
| >>> Locale('en').ordinal_form(1) | |
| 'one' | |
| >>> Locale('en').ordinal_form(2) | |
| 'two' | |
| >>> Locale('en').ordinal_form(3) | |
| 'few' | |
| >>> Locale('fr').ordinal_form(2) | |
| 'other' | |
| >>> Locale('ru').ordinal_form(100) | |
| 'other' | |
| """ | |
| return self._data.get('ordinal_form', _default_plural_rule) | |
| def measurement_systems(self) -> localedata.LocaleDataDict: | |
| """Localized names for various measurement systems. | |
| >>> Locale('fr', 'FR').measurement_systems['US'] | |
| u'am\\xe9ricain' | |
| >>> Locale('en', 'US').measurement_systems['US'] | |
| u'US' | |
| """ | |
| return self._data['measurement_systems'] | |
| def character_order(self) -> str: | |
| """The text direction for the language. | |
| >>> Locale('de', 'DE').character_order | |
| 'left-to-right' | |
| >>> Locale('ar', 'SA').character_order | |
| 'right-to-left' | |
| """ | |
| return self._data['character_order'] | |
| def text_direction(self) -> str: | |
| """The text direction for the language in CSS short-hand form. | |
| >>> Locale('de', 'DE').text_direction | |
| 'ltr' | |
| >>> Locale('ar', 'SA').text_direction | |
| 'rtl' | |
| """ | |
| return ''.join(word[0] for word in self.character_order.split('-')) | |
| def unit_display_names(self) -> localedata.LocaleDataDict: | |
| """Display names for units of measurement. | |
| .. seealso:: | |
| You may want to use :py:func:`babel.units.get_unit_name` instead. | |
| .. note:: The format of the value returned may change between | |
| Babel versions. | |
| """ | |
| return self._data['unit_display_names'] | |
| def default_locale( | |
| category: str | tuple[str, ...] | list[str] | None = None, | |
| aliases: Mapping[str, str] = LOCALE_ALIASES, | |
| ) -> str | None: | |
| """Returns the system default locale for a given category, based on | |
| environment variables. | |
| >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']: | |
| ... os.environ[name] = '' | |
| >>> os.environ['LANG'] = 'fr_FR.UTF-8' | |
| >>> default_locale('LC_MESSAGES') | |
| 'fr_FR' | |
| The "C" or "POSIX" pseudo-locales are treated as aliases for the | |
| "en_US_POSIX" locale: | |
| >>> os.environ['LC_MESSAGES'] = 'POSIX' | |
| >>> default_locale('LC_MESSAGES') | |
| 'en_US_POSIX' | |
| The following fallbacks to the variable are always considered: | |
| - ``LANGUAGE`` | |
| - ``LC_ALL`` | |
| - ``LC_CTYPE`` | |
| - ``LANG`` | |
| :param category: one or more of the ``LC_XXX`` environment variable names | |
| :param aliases: a dictionary of aliases for locale identifiers | |
| """ | |
| varnames = ('LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG') | |
| if category: | |
| if isinstance(category, str): | |
| varnames = (category, *varnames) | |
| elif isinstance(category, (list, tuple)): | |
| varnames = (*category, *varnames) | |
| else: | |
| raise TypeError(f"Invalid type for category: {category!r}") | |
| for name in varnames: | |
| if not name: | |
| continue | |
| locale = os.getenv(name) | |
| if locale: | |
| if name == 'LANGUAGE' and ':' in locale: | |
| # the LANGUAGE variable may contain a colon-separated list of | |
| # language codes; we just pick the language on the list | |
| locale = locale.split(':')[0] | |
| if locale.split('.')[0] in ('C', 'POSIX'): | |
| locale = 'en_US_POSIX' | |
| elif aliases and locale in aliases: | |
| locale = aliases[locale] | |
| try: | |
| return get_locale_identifier(parse_locale(locale)) | |
| except ValueError: | |
| pass | |
| return None | |
| def negotiate_locale(preferred: Iterable[str], available: Iterable[str], sep: str = '_', aliases: Mapping[str, str] = LOCALE_ALIASES) -> str | None: | |
| """Find the best match between available and requested locale strings. | |
| >>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT']) | |
| 'de_DE' | |
| >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de']) | |
| 'de' | |
| Case is ignored by the algorithm, the result uses the case of the preferred | |
| locale identifier: | |
| >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) | |
| 'de_DE' | |
| >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at']) | |
| 'de_DE' | |
| By default, some web browsers unfortunately do not include the territory | |
| in the locale identifier for many locales, and some don't even allow the | |
| user to easily add the territory. So while you may prefer using qualified | |
| locale identifiers in your web-application, they would not normally match | |
| the language-only locale sent by such browsers. To workaround that, this | |
| function uses a default mapping of commonly used language-only locale | |
| identifiers to identifiers including the territory: | |
| >>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US']) | |
| 'ja_JP' | |
| Some browsers even use an incorrect or outdated language code, such as "no" | |
| for Norwegian, where the correct locale identifier would actually be "nb_NO" | |
| (Bokmål) or "nn_NO" (Nynorsk). The aliases are intended to take care of | |
| such cases, too: | |
| >>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE']) | |
| 'nb_NO' | |
| You can override this default mapping by passing a different `aliases` | |
| dictionary to this function, or you can bypass the behavior althogher by | |
| setting the `aliases` parameter to `None`. | |
| :param preferred: the list of locale strings preferred by the user | |
| :param available: the list of locale strings available | |
| :param sep: character that separates the different parts of the locale | |
| strings | |
| :param aliases: a dictionary of aliases for locale identifiers | |
| """ | |
| available = [a.lower() for a in available if a] | |
| for locale in preferred: | |
| ll = locale.lower() | |
| if ll in available: | |
| return locale | |
| if aliases: | |
| alias = aliases.get(ll) | |
| if alias: | |
| alias = alias.replace('_', sep) | |
| if alias.lower() in available: | |
| return alias | |
| parts = locale.split(sep) | |
| if len(parts) > 1 and parts[0].lower() in available: | |
| return parts[0] | |
| return None | |
| def parse_locale( | |
| identifier: str, | |
| sep: str = '_', | |
| ) -> tuple[str, str | None, str | None, str | None] | tuple[str, str | None, str | None, str | None, str | None]: | |
| """Parse a locale identifier into a tuple of the form ``(language, | |
| territory, script, variant, modifier)``. | |
| >>> parse_locale('zh_CN') | |
| ('zh', 'CN', None, None) | |
| >>> parse_locale('zh_Hans_CN') | |
| ('zh', 'CN', 'Hans', None) | |
| >>> parse_locale('ca_es_valencia') | |
| ('ca', 'ES', None, 'VALENCIA') | |
| >>> parse_locale('en_150') | |
| ('en', '150', None, None) | |
| >>> parse_locale('en_us_posix') | |
| ('en', 'US', None, 'POSIX') | |
| >>> parse_locale('it_IT@euro') | |
| ('it', 'IT', None, None, 'euro') | |
| >>> parse_locale('it_IT@custom') | |
| ('it', 'IT', None, None, 'custom') | |
| >>> parse_locale('it_IT@') | |
| ('it', 'IT', None, None) | |
| The default component separator is "_", but a different separator can be | |
| specified using the `sep` parameter. | |
| The optional modifier is always separated with "@" and at the end: | |
| >>> parse_locale('zh-CN', sep='-') | |
| ('zh', 'CN', None, None) | |
| >>> parse_locale('zh-CN@custom', sep='-') | |
| ('zh', 'CN', None, None, 'custom') | |
| If the identifier cannot be parsed into a locale, a `ValueError` exception | |
| is raised: | |
| >>> parse_locale('not_a_LOCALE_String') | |
| Traceback (most recent call last): | |
| ... | |
| ValueError: 'not_a_LOCALE_String' is not a valid locale identifier | |
| Encoding information is removed from the identifier, while modifiers are | |
| kept: | |
| >>> parse_locale('en_US.UTF-8') | |
| ('en', 'US', None, None) | |
| >>> parse_locale('de_DE.iso885915@euro') | |
| ('de', 'DE', None, None, 'euro') | |
| See :rfc:`4646` for more information. | |
| :param identifier: the locale identifier string | |
| :param sep: character that separates the different components of the locale | |
| identifier | |
| :raise `ValueError`: if the string does not appear to be a valid locale | |
| identifier | |
| """ | |
| if not identifier: | |
| raise ValueError("empty locale identifier") | |
| identifier, _, modifier = identifier.partition('@') | |
| if '.' in identifier: | |
| # this is probably the charset/encoding, which we don't care about | |
| identifier = identifier.split('.', 1)[0] | |
| parts = identifier.split(sep) | |
| lang = parts.pop(0).lower() | |
| if not lang.isalpha(): | |
| raise ValueError(f"expected only letters, got {lang!r}") | |
| script = territory = variant = None | |
| if parts and len(parts[0]) == 4 and parts[0].isalpha(): | |
| script = parts.pop(0).title() | |
| if parts: | |
| if len(parts[0]) == 2 and parts[0].isalpha(): | |
| territory = parts.pop(0).upper() | |
| elif len(parts[0]) == 3 and parts[0].isdigit(): | |
| territory = parts.pop(0) | |
| if parts and ( | |
| len(parts[0]) == 4 and parts[0][0].isdigit() or | |
| len(parts[0]) >= 5 and parts[0][0].isalpha() | |
| ): | |
| variant = parts.pop().upper() | |
| if parts: | |
| raise ValueError(f"{identifier!r} is not a valid locale identifier") | |
| # TODO(3.0): always return a 5-tuple | |
| if modifier: | |
| return lang, territory, script, variant, modifier | |
| else: | |
| return lang, territory, script, variant | |
| def get_locale_identifier( | |
| tup: tuple[str] | |
| | tuple[str, str | None] | |
| | tuple[str, str | None, str | None] | |
| | tuple[str, str | None, str | None, str | None] | |
| | tuple[str, str | None, str | None, str | None, str | None], | |
| sep: str = "_", | |
| ) -> str: | |
| """The reverse of :func:`parse_locale`. It creates a locale identifier out | |
| of a ``(language, territory, script, variant, modifier)`` tuple. Items can be set to | |
| ``None`` and trailing ``None``\\s can also be left out of the tuple. | |
| >>> get_locale_identifier(('de', 'DE', None, '1999', 'custom')) | |
| 'de_DE_1999@custom' | |
| >>> get_locale_identifier(('fi', None, None, None, 'custom')) | |
| 'fi@custom' | |
| .. versionadded:: 1.0 | |
| :param tup: the tuple as returned by :func:`parse_locale`. | |
| :param sep: the separator for the identifier. | |
| """ | |
| tup = tuple(tup[:5]) # type: ignore # length should be no more than 5 | |
| lang, territory, script, variant, modifier = tup + (None,) * (5 - len(tup)) | |
| ret = sep.join(filter(None, (lang, script, territory, variant))) | |
| return f'{ret}@{modifier}' if modifier else ret | |