Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
core.py1297 linesDownload Raw Back to babel
1"""2    babel.core3    ~~~~~~~~~~4 5    Core locale representation and locale data access.6 7    :copyright: (c) 2013-2024 by the Babel Team.8    :license: BSD, see LICENSE for more details.9"""10 11from __future__ import annotations12 13import os14import pickle15from collections.abc import Iterable, Mapping16from typing import TYPE_CHECKING, Any17 18from babel import localedata19from babel.plural import PluralRule20 21__all__ = ['UnknownLocaleError', 'Locale', 'default_locale', 'negotiate_locale',22           'parse_locale']23 24if TYPE_CHECKING:25    from typing_extensions import Literal, TypeAlias26 27    _GLOBAL_KEY: TypeAlias = Literal[28        "all_currencies",29        "currency_fractions",30        "language_aliases",31        "likely_subtags",32        "meta_zones",33        "parent_exceptions",34        "script_aliases",35        "territory_aliases",36        "territory_currencies",37        "territory_languages",38        "territory_zones",39        "variant_aliases",40        "windows_zone_mapping",41        "zone_aliases",42        "zone_territories",43    ]44 45    _global_data: Mapping[_GLOBAL_KEY, Mapping[str, Any]] | None46 47_global_data = None48_default_plural_rule = PluralRule({})49 50 51def _raise_no_data_error():52    raise RuntimeError('The babel data files are not available. '53                       'This usually happens because you are using '54                       'a source checkout from Babel and you did '55                       'not build the data files.  Just make sure '56                       'to run "python setup.py import_cldr" before '57                       'installing the library.')58 59 60def get_global(key: _GLOBAL_KEY) -> Mapping[str, Any]:61    """Return the dictionary for the given key in the global data.62 63    The global data is stored in the ``babel/global.dat`` file and contains64    information independent of individual locales.65 66    >>> get_global('zone_aliases')['UTC']67    u'Etc/UTC'68    >>> get_global('zone_territories')['Europe/Berlin']69    u'DE'70 71    The keys available are:72 73    - ``all_currencies``74    - ``currency_fractions``75    - ``language_aliases``76    - ``likely_subtags``77    - ``parent_exceptions``78    - ``script_aliases``79    - ``territory_aliases``80    - ``territory_currencies``81    - ``territory_languages``82    - ``territory_zones``83    - ``variant_aliases``84    - ``windows_zone_mapping``85    - ``zone_aliases``86    - ``zone_territories``87 88    .. note:: The internal structure of the data may change between versions.89 90    .. versionadded:: 0.991 92    :param key: the data key93    """94    global _global_data95    if _global_data is None:96        dirname = os.path.join(os.path.dirname(__file__))97        filename = os.path.join(dirname, 'global.dat')98        if not os.path.isfile(filename):99            _raise_no_data_error()100        with open(filename, 'rb') as fileobj:101            _global_data = pickle.load(fileobj)102            assert _global_data is not None103    return _global_data.get(key, {})104 105 106LOCALE_ALIASES = {107    'ar': 'ar_SY', 'bg': 'bg_BG', 'bs': 'bs_BA', 'ca': 'ca_ES', 'cs': 'cs_CZ',108    'da': 'da_DK', 'de': 'de_DE', 'el': 'el_GR', 'en': 'en_US', 'es': 'es_ES',109    'et': 'et_EE', 'fa': 'fa_IR', 'fi': 'fi_FI', 'fr': 'fr_FR', 'gl': 'gl_ES',110    'he': 'he_IL', 'hu': 'hu_HU', 'id': 'id_ID', 'is': 'is_IS', 'it': 'it_IT',111    'ja': 'ja_JP', 'km': 'km_KH', 'ko': 'ko_KR', 'lt': 'lt_LT', 'lv': 'lv_LV',112    'mk': 'mk_MK', 'nl': 'nl_NL', 'nn': 'nn_NO', 'no': 'nb_NO', 'pl': 'pl_PL',113    'pt': 'pt_PT', 'ro': 'ro_RO', 'ru': 'ru_RU', 'sk': 'sk_SK', 'sl': 'sl_SI',114    'sv': 'sv_SE', 'th': 'th_TH', 'tr': 'tr_TR', 'uk': 'uk_UA',115}116 117 118class UnknownLocaleError(Exception):119    """Exception thrown when a locale is requested for which no locale data120    is available.121    """122 123    def __init__(self, identifier: str) -> None:124        """Create the exception.125 126        :param identifier: the identifier string of the unsupported locale127        """128        Exception.__init__(self, f"unknown locale {identifier!r}")129 130        #: The identifier of the locale that could not be found.131        self.identifier = identifier132 133 134class Locale:135    """Representation of a specific locale.136 137    >>> locale = Locale('en', 'US')138    >>> repr(locale)139    "Locale('en', territory='US')"140    >>> locale.display_name141    u'English (United States)'142 143    A `Locale` object can also be instantiated from a raw locale string:144 145    >>> locale = Locale.parse('en-US', sep='-')146    >>> repr(locale)147    "Locale('en', territory='US')"148 149    `Locale` objects provide access to a collection of locale data, such as150    territory and language names, number and date format patterns, and more:151 152    >>> locale.number_symbols['latn']['decimal']153    u'.'154 155    If a locale is requested for which no locale data is available, an156    `UnknownLocaleError` is raised:157 158    >>> Locale.parse('en_XX')159    Traceback (most recent call last):160        ...161    UnknownLocaleError: unknown locale 'en_XX'162 163    For more information see :rfc:`3066`.164    """165 166    def __init__(167        self,168        language: str,169        territory: str | None = None,170        script: str | None = None,171        variant: str | None = None,172        modifier: str | None = None,173    ) -> None:174        """Initialize the locale object from the given identifier components.175 176        >>> locale = Locale('en', 'US')177        >>> locale.language178        'en'179        >>> locale.territory180        'US'181 182        :param language: the language code183        :param territory: the territory (country or region) code184        :param script: the script code185        :param variant: the variant code186        :param modifier: a modifier (following the '@' symbol, sometimes called '@variant')187        :raise `UnknownLocaleError`: if no locale data is available for the188                                     requested locale189        """190        #: the language code191        self.language = language192        #: the territory (country or region) code193        self.territory = territory194        #: the script code195        self.script = script196        #: the variant code197        self.variant = variant198        #: the modifier199        self.modifier = modifier200        self.__data: localedata.LocaleDataDict | None = None201 202        identifier = str(self)203        identifier_without_modifier = identifier.partition('@')[0]204        if not localedata.exists(identifier_without_modifier):205            raise UnknownLocaleError(identifier)206 207    @classmethod208    def default(cls, category: str | None = None, aliases: Mapping[str, str] = LOCALE_ALIASES) -> Locale:209        """Return the system default locale for the specified category.210 211        >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LC_MESSAGES']:212        ...     os.environ[name] = ''213        >>> os.environ['LANG'] = 'fr_FR.UTF-8'214        >>> Locale.default('LC_MESSAGES')215        Locale('fr', territory='FR')216 217        The following fallbacks to the variable are always considered:218 219        - ``LANGUAGE``220        - ``LC_ALL``221        - ``LC_CTYPE``222        - ``LANG``223 224        :param category: one of the ``LC_XXX`` environment variable names225        :param aliases: a dictionary of aliases for locale identifiers226        """227        # XXX: use likely subtag expansion here instead of the228        # aliases dictionary.229        locale_string = default_locale(category, aliases=aliases)230        return cls.parse(locale_string)231 232    @classmethod233    def negotiate(234        cls,235        preferred: Iterable[str],236        available: Iterable[str],237        sep: str = '_',238        aliases: Mapping[str, str] = LOCALE_ALIASES,239    ) -> Locale | None:240        """Find the best match between available and requested locale strings.241 242        >>> Locale.negotiate(['de_DE', 'en_US'], ['de_DE', 'de_AT'])243        Locale('de', territory='DE')244        >>> Locale.negotiate(['de_DE', 'en_US'], ['en', 'de'])245        Locale('de')246        >>> Locale.negotiate(['de_DE', 'de'], ['en_US'])247 248        You can specify the character used in the locale identifiers to separate249        the different components. This separator is applied to both lists. Also,250        case is ignored in the comparison:251 252        >>> Locale.negotiate(['de-DE', 'de'], ['en-us', 'de-de'], sep='-')253        Locale('de', territory='DE')254 255        :param preferred: the list of locale identifiers preferred by the user256        :param available: the list of locale identifiers available257        :param aliases: a dictionary of aliases for locale identifiers258        """259        identifier = negotiate_locale(preferred, available, sep=sep,260                                      aliases=aliases)261        if identifier:262            return Locale.parse(identifier, sep=sep)263        return None264 265    @classmethod266    def parse(267        cls,268        identifier: str | Locale | None,269        sep: str = '_',270        resolve_likely_subtags: bool = True,271    ) -> Locale:272        """Create a `Locale` instance for the given locale identifier.273 274        >>> l = Locale.parse('de-DE', sep='-')275        >>> l.display_name276        u'Deutsch (Deutschland)'277 278        If the `identifier` parameter is not a string, but actually a `Locale`279        object, that object is returned:280 281        >>> Locale.parse(l)282        Locale('de', territory='DE')283 284        If the `identifier` parameter is neither of these, such as `None`285        e.g. because a default locale identifier could not be determined,286        a `TypeError` is raised:287 288        >>> Locale.parse(None)289        Traceback (most recent call last):290            ...291        TypeError: ...292 293        This also can perform resolving of likely subtags which it does294        by default.  This is for instance useful to figure out the most295        likely locale for a territory you can use ``'und'`` as the296        language tag:297 298        >>> Locale.parse('und_AT')299        Locale('de', territory='AT')300 301        Modifiers are optional, and always at the end, separated by "@":302 303        >>> Locale.parse('de_AT@euro')304        Locale('de', territory='AT', modifier='euro')305 306        :param identifier: the locale identifier string307        :param sep: optional component separator308        :param resolve_likely_subtags: if this is specified then a locale will309                                       have its likely subtag resolved if the310                                       locale otherwise does not exist.  For311                                       instance ``zh_TW`` by itself is not a312                                       locale that exists but Babel can313                                       automatically expand it to the full314                                       form of ``zh_hant_TW``.  Note that this315                                       expansion is only taking place if no316                                       locale exists otherwise.  For instance317                                       there is a locale ``en`` that can exist318                                       by itself.319        :raise `ValueError`: if the string does not appear to be a valid locale320                             identifier321        :raise `UnknownLocaleError`: if no locale data is available for the322                                     requested locale323        :raise `TypeError`: if the identifier is not a string or a `Locale`324        """325        if isinstance(identifier, Locale):326            return identifier327        elif not isinstance(identifier, str):328            raise TypeError(f"Unexpected value for identifier: {identifier!r}")329 330        parts = parse_locale(identifier, sep=sep)331        input_id = get_locale_identifier(parts)332 333        def _try_load(parts):334            try:335                return cls(*parts)336            except UnknownLocaleError:337                return None338 339        def _try_load_reducing(parts):340            # Success on first hit, return it.341            locale = _try_load(parts)342            if locale is not None:343                return locale344 345            # Now try without script and variant346            locale = _try_load(parts[:2])347            if locale is not None:348                return locale349 350        locale = _try_load(parts)351        if locale is not None:352            return locale353        if not resolve_likely_subtags:354            raise UnknownLocaleError(input_id)355 356        # From here onwards is some very bad likely subtag resolving.  This357        # whole logic is not entirely correct but good enough (tm) for the358        # time being.  This has been added so that zh_TW does not cause359        # errors for people when they upgrade.  Later we should properly360        # implement ICU like fuzzy locale objects and provide a way to361        # maximize and minimize locale tags.362 363        if len(parts) == 5:364            language, territory, script, variant, modifier = parts365        else:366            language, territory, script, variant = parts367            modifier = None368        language = get_global('language_aliases').get(language, language)369        territory = get_global('territory_aliases').get(territory or '', (territory,))[0]370        script = get_global('script_aliases').get(script or '', script)371        variant = get_global('variant_aliases').get(variant or '', variant)372 373        if territory == 'ZZ':374            territory = None375        if script == 'Zzzz':376            script = None377 378        parts = language, territory, script, variant, modifier379 380        # First match: try the whole identifier381        new_id = get_locale_identifier(parts)382        likely_subtag = get_global('likely_subtags').get(new_id)383        if likely_subtag is not None:384            locale = _try_load_reducing(parse_locale(likely_subtag))385            if locale is not None:386                return locale387 388        # If we did not find anything so far, try again with a389        # simplified identifier that is just the language390        likely_subtag = get_global('likely_subtags').get(language)391        if likely_subtag is not None:392            parts2 = parse_locale(likely_subtag)393            if len(parts2) == 5:394                language2, _, script2, variant2, modifier2 = parts2395            else:396                language2, _, script2, variant2 = parts2397                modifier2 = None398            locale = _try_load_reducing((language2, territory, script2, variant2, modifier2))399            if locale is not None:400                return locale401 402        raise UnknownLocaleError(input_id)403 404    def __eq__(self, other: object) -> bool:405        for key in ('language', 'territory', 'script', 'variant', 'modifier'):406            if not hasattr(other, key):407                return False408        return (409            self.language == getattr(other, 'language') and  # noqa: B009410            self.territory == getattr(other, 'territory') and  # noqa: B009411            self.script == getattr(other, 'script') and  # noqa: B009412            self.variant == getattr(other, 'variant') and  # noqa: B009413            self.modifier == getattr(other, 'modifier')  # noqa: B009414        )415 416    def __ne__(self, other: object) -> bool:417        return not self.__eq__(other)418 419    def __hash__(self) -> int:420        return hash((self.language, self.territory, self.script,421                     self.variant, self.modifier))422 423    def __repr__(self) -> str:424        parameters = ['']425        for key in ('territory', 'script', 'variant', 'modifier'):426            value = getattr(self, key)427            if value is not None:428                parameters.append(f"{key}={value!r}")429        return f"Locale({self.language!r}{', '.join(parameters)})"430 431    def __str__(self) -> str:432        return get_locale_identifier((self.language, self.territory,433                                      self.script, self.variant,434                                      self.modifier))435 436    @property437    def _data(self) -> localedata.LocaleDataDict:438        if self.__data is None:439            self.__data = localedata.LocaleDataDict(localedata.load(str(self)))440        return self.__data441 442    def get_display_name(self, locale: Locale | str | None = None) -> str | None:443        """Return the display name of the locale using the given locale.444 445        The display name will include the language, territory, script, and446        variant, if those are specified.447 448        >>> Locale('zh', 'CN', script='Hans').get_display_name('en')449        u'Chinese (Simplified, China)'450 451        Modifiers are currently passed through verbatim:452 453        >>> Locale('it', 'IT', modifier='euro').get_display_name('en')454        u'Italian (Italy, euro)'455 456        :param locale: the locale to use457        """458        if locale is None:459            locale = self460        locale = Locale.parse(locale)461        retval = locale.languages.get(self.language)462        if retval and (self.territory or self.script or self.variant):463            details = []464            if self.script:465                details.append(locale.scripts.get(self.script))466            if self.territory:467                details.append(locale.territories.get(self.territory))468            if self.variant:469                details.append(locale.variants.get(self.variant))470            if self.modifier:471                details.append(self.modifier)472            detail_string = ', '.join(atom for atom in details if atom)473            if detail_string:474                retval += f" ({detail_string})"475        return retval476 477    display_name = property(get_display_name, doc="""\478        The localized display name of the locale.479 480        >>> Locale('en').display_name481        u'English'482        >>> Locale('en', 'US').display_name483        u'English (United States)'484        >>> Locale('sv').display_name485        u'svenska'486 487        :type: `unicode`488        """)489 490    def get_language_name(self, locale: Locale | str | None = None) -> str | None:491        """Return the language of this locale in the given locale.492 493        >>> Locale('zh', 'CN', script='Hans').get_language_name('de')494        u'Chinesisch'495 496        .. versionadded:: 1.0497 498        :param locale: the locale to use499        """500        if locale is None:501            locale = self502        locale = Locale.parse(locale)503        return locale.languages.get(self.language)504 505    language_name = property(get_language_name, doc="""\506        The localized language name of the locale.507 508        >>> Locale('en', 'US').language_name509        u'English'510    """)511 512    def get_territory_name(self, locale: Locale | str | None = None) -> str | None:513        """Return the territory name in the given locale."""514        if locale is None:515            locale = self516        locale = Locale.parse(locale)517        return locale.territories.get(self.territory or '')518 519    territory_name = property(get_territory_name, doc="""\520        The localized territory name of the locale if available.521 522        >>> Locale('de', 'DE').territory_name523        u'Deutschland'524    """)525 526    def get_script_name(self, locale: Locale | str | None = None) -> str | None:527        """Return the script name in the given locale."""528        if locale is None:529            locale = self530        locale = Locale.parse(locale)531        return locale.scripts.get(self.script or '')532 533    script_name = property(get_script_name, doc="""\534        The localized script name of the locale if available.535 536        >>> Locale('sr', 'ME', script='Latn').script_name537        u'latinica'538    """)539 540    @property541    def english_name(self) -> str | None:542        """The english display name of the locale.543 544        >>> Locale('de').english_name545        u'German'546        >>> Locale('de', 'DE').english_name547        u'German (Germany)'548 549        :type: `unicode`"""550        return self.get_display_name(Locale('en'))551 552    # { General Locale Display Names553 554    @property555    def languages(self) -> localedata.LocaleDataDict:556        """Mapping of language codes to translated language names.557 558        >>> Locale('de', 'DE').languages['ja']559        u'Japanisch'560 561        See `ISO 639 <http://www.loc.gov/standards/iso639-2/>`_ for562        more information.563        """564        return self._data['languages']565 566    @property567    def scripts(self) -> localedata.LocaleDataDict:568        """Mapping of script codes to translated script names.569 570        >>> Locale('en', 'US').scripts['Hira']571        u'Hiragana'572 573        See `ISO 15924 <http://www.evertype.com/standards/iso15924/>`_574        for more information.575        """576        return self._data['scripts']577 578    @property579    def territories(self) -> localedata.LocaleDataDict:580        """Mapping of script codes to translated script names.581 582        >>> Locale('es', 'CO').territories['DE']583        u'Alemania'584 585        See `ISO 3166 <http://www.iso.org/iso/en/prods-services/iso3166ma/>`_586        for more information.587        """588        return self._data['territories']589 590    @property591    def variants(self) -> localedata.LocaleDataDict:592        """Mapping of script codes to translated script names.593 594        >>> Locale('de', 'DE').variants['1901']595        u'Alte deutsche Rechtschreibung'596        """597        return self._data['variants']598 599    # { Number Formatting600 601    @property602    def currencies(self) -> localedata.LocaleDataDict:603        """Mapping of currency codes to translated currency names.  This604        only returns the generic form of the currency name, not the count605        specific one.  If an actual number is requested use the606        :func:`babel.numbers.get_currency_name` function.607 608        >>> Locale('en').currencies['COP']609        u'Colombian Peso'610        >>> Locale('de', 'DE').currencies['COP']611        u'Kolumbianischer Peso'612        """613        return self._data['currency_names']614 615    @property616    def currency_symbols(self) -> localedata.LocaleDataDict:617        """Mapping of currency codes to symbols.618 619        >>> Locale('en', 'US').currency_symbols['USD']620        u'$'621        >>> Locale('es', 'CO').currency_symbols['USD']622        u'US$'623        """624        return self._data['currency_symbols']625 626    @property627    def number_symbols(self) -> localedata.LocaleDataDict:628        """Symbols used in number formatting by number system.629 630        .. note:: The format of the value returned may change between631                  Babel versions.632 633        >>> Locale('fr', 'FR').number_symbols["latn"]['decimal']634        u','635        >>> Locale('fa', 'IR').number_symbols["arabext"]['decimal']636        u'٫'637        >>> Locale('fa', 'IR').number_symbols["latn"]['decimal']638        u'.'639        """640        return self._data['number_symbols']641 642    @property643    def other_numbering_systems(self) -> localedata.LocaleDataDict:644        """645        Mapping of other numbering systems available for the locale.646        See: https://www.unicode.org/reports/tr35/tr35-numbers.html#otherNumberingSystems647 648        >>> Locale('el', 'GR').other_numbering_systems['traditional']649        u'grek'650 651        .. note:: The format of the value returned may change between652                  Babel versions.653        """654        return self._data['numbering_systems']655 656    @property657    def default_numbering_system(self) -> str:658        """The default numbering system used by the locale.659        >>> Locale('el', 'GR').default_numbering_system660        u'latn'661        """662        return self._data['default_numbering_system']663 664    @property665    def decimal_formats(self) -> localedata.LocaleDataDict:666        """Locale patterns for decimal number formatting.667 668        .. note:: The format of the value returned may change between669                  Babel versions.670 671        >>> Locale('en', 'US').decimal_formats[None]672        <NumberPattern u'#,##0.###'>673        """674        return self._data['decimal_formats']675 676    @property677    def compact_decimal_formats(self) -> localedata.LocaleDataDict:678        """Locale patterns for compact decimal number formatting.679 680        .. note:: The format of the value returned may change between681                  Babel versions.682 683        >>> Locale('en', 'US').compact_decimal_formats["short"]["one"]["1000"]684        <NumberPattern u'0K'>685        """686        return self._data['compact_decimal_formats']687 688    @property689    def currency_formats(self) -> localedata.LocaleDataDict:690        """Locale patterns for currency number formatting.691 692        .. note:: The format of the value returned may change between693                  Babel versions.694 695        >>> Locale('en', 'US').currency_formats['standard']696        <NumberPattern u'\\xa4#,##0.00'>697        >>> Locale('en', 'US').currency_formats['accounting']698        <NumberPattern u'\\xa4#,##0.00;(\\xa4#,##0.00)'>699        """700        return self._data['currency_formats']701 702    @property703    def compact_currency_formats(self) -> localedata.LocaleDataDict:704        """Locale patterns for compact currency number formatting.705 706        .. note:: The format of the value returned may change between707                  Babel versions.708 709        >>> Locale('en', 'US').compact_currency_formats["short"]["one"]["1000"]710        <NumberPattern u'¤0K'>711        """712        return self._data['compact_currency_formats']713 714    @property715    def percent_formats(self) -> localedata.LocaleDataDict:716        """Locale patterns for percent number formatting.717 718        .. note:: The format of the value returned may change between719                  Babel versions.720 721        >>> Locale('en', 'US').percent_formats[None]722        <NumberPattern u'#,##0%'>723        """724        return self._data['percent_formats']725 726    @property727    def scientific_formats(self) -> localedata.LocaleDataDict:728        """Locale patterns for scientific number formatting.729 730        .. note:: The format of the value returned may change between731                  Babel versions.732 733        >>> Locale('en', 'US').scientific_formats[None]734        <NumberPattern u'#E0'>735        """736        return self._data['scientific_formats']737 738    # { Calendar Information and Date Formatting739 740    @property741    def periods(self) -> localedata.LocaleDataDict:742        """Locale display names for day periods (AM/PM).743 744        >>> Locale('en', 'US').periods['am']745        u'AM'746        """747        try:748            return self._data['day_periods']['stand-alone']['wide']749        except KeyError:750            return localedata.LocaleDataDict({})  # pragma: no cover751 752    @property753    def day_periods(self) -> localedata.LocaleDataDict:754        """Locale display names for various day periods (not necessarily only AM/PM).755 756        These are not meant to be used without the relevant `day_period_rules`.757        """758        return self._data['day_periods']759 760    @property761    def day_period_rules(self) -> localedata.LocaleDataDict:762        """Day period rules for the locale.  Used by `get_period_id`.763        """764        return self._data.get('day_period_rules', localedata.LocaleDataDict({}))765 766    @property767    def days(self) -> localedata.LocaleDataDict:768        """Locale display names for weekdays.769 770        >>> Locale('de', 'DE').days['format']['wide'][3]771        u'Donnerstag'772        """773        return self._data['days']774 775    @property776    def months(self) -> localedata.LocaleDataDict:777        """Locale display names for months.778 779        >>> Locale('de', 'DE').months['format']['wide'][10]780        u'Oktober'781        """782        return self._data['months']783 784    @property785    def quarters(self) -> localedata.LocaleDataDict:786        """Locale display names for quarters.787 788        >>> Locale('de', 'DE').quarters['format']['wide'][1]789        u'1. Quartal'790        """791        return self._data['quarters']792 793    @property794    def eras(self) -> localedata.LocaleDataDict:795        """Locale display names for eras.796 797        .. note:: The format of the value returned may change between798                  Babel versions.799 800        >>> Locale('en', 'US').eras['wide'][1]801        u'Anno Domini'802        >>> Locale('en', 'US').eras['abbreviated'][0]803        u'BC'804        """805        return self._data['eras']806 807    @property808    def time_zones(self) -> localedata.LocaleDataDict:809        """Locale display names for time zones.810 811        .. note:: The format of the value returned may change between812                  Babel versions.813 814        >>> Locale('en', 'US').time_zones['Europe/London']['long']['daylight']815        u'British Summer Time'816        >>> Locale('en', 'US').time_zones['America/St_Johns']['city']817        u'St. John\u2019s'818        """819        return self._data['time_zones']820 821    @property822    def meta_zones(self) -> localedata.LocaleDataDict:823        """Locale display names for meta time zones.824 825        Meta time zones are basically groups of different Olson time zones that826        have the same GMT offset and daylight savings time.827 828        .. note:: The format of the value returned may change between829                  Babel versions.830 831        >>> Locale('en', 'US').meta_zones['Europe_Central']['long']['daylight']832        u'Central European Summer Time'833 834        .. versionadded:: 0.9835        """836        return self._data['meta_zones']837 838    @property839    def zone_formats(self) -> localedata.LocaleDataDict:840        """Patterns related to the formatting of time zones.841 842        .. note:: The format of the value returned may change between843                  Babel versions.844 845        >>> Locale('en', 'US').zone_formats['fallback']846        u'%(1)s (%(0)s)'847        >>> Locale('pt', 'BR').zone_formats['region']848        u'Hor\\xe1rio %s'849 850        .. versionadded:: 0.9851        """852        return self._data['zone_formats']853 854    @property855    def first_week_day(self) -> int:856        """The first day of a week, with 0 being Monday.857 858        >>> Locale('de', 'DE').first_week_day859        0860        >>> Locale('en', 'US').first_week_day861        6862        """863        return self._data['week_data']['first_day']864 865    @property866    def weekend_start(self) -> int:867        """The day the weekend starts, with 0 being Monday.868 869        >>> Locale('de', 'DE').weekend_start870        5871        """872        return self._data['week_data']['weekend_start']873 874    @property875    def weekend_end(self) -> int:876        """The day the weekend ends, with 0 being Monday.877 878        >>> Locale('de', 'DE').weekend_end879        6880        """881        return self._data['week_data']['weekend_end']882 883    @property884    def min_week_days(self) -> int:885        """The minimum number of days in a week so that the week is counted as886        the first week of a year or month.887 888        >>> Locale('de', 'DE').min_week_days889        4890        """891        return self._data['week_data']['min_days']892 893    @property894    def date_formats(self) -> localedata.LocaleDataDict:895        """Locale patterns for date formatting.896 897        .. note:: The format of the value returned may change between898                  Babel versions.899 900        >>> Locale('en', 'US').date_formats['short']901        <DateTimePattern u'M/d/yy'>902        >>> Locale('fr', 'FR').date_formats['long']903        <DateTimePattern u'd MMMM y'>904        """905        return self._data['date_formats']906 907    @property908    def time_formats(self) -> localedata.LocaleDataDict:909        """Locale patterns for time formatting.910 911        .. note:: The format of the value returned may change between912                  Babel versions.913 914        >>> Locale('en', 'US').time_formats['short']915        <DateTimePattern u'h:mm\u202fa'>916        >>> Locale('fr', 'FR').time_formats['long']917        <DateTimePattern u'HH:mm:ss z'>918        """919        return self._data['time_formats']920 921    @property922    def datetime_formats(self) -> localedata.LocaleDataDict:923        """Locale patterns for datetime formatting.924 925        .. note:: The format of the value returned may change between926                  Babel versions.927 928        >>> Locale('en').datetime_formats['full']929        u'{1}, {0}'930        >>> Locale('th').datetime_formats['medium']931        u'{1} {0}'932        """933        return self._data['datetime_formats']934 935    @property936    def datetime_skeletons(self) -> localedata.LocaleDataDict:937        """Locale patterns for formatting parts of a datetime.938 939        >>> Locale('en').datetime_skeletons['MEd']940        <DateTimePattern u'E, M/d'>941        >>> Locale('fr').datetime_skeletons['MEd']942        <DateTimePattern u'E dd/MM'>943        >>> Locale('fr').datetime_skeletons['H']944        <DateTimePattern u"HH 'h'">945        """946        return self._data['datetime_skeletons']947 948    @property949    def interval_formats(self) -> localedata.LocaleDataDict:950        """Locale patterns for interval formatting.951 952        .. note:: The format of the value returned may change between953                  Babel versions.954 955        How to format date intervals in Finnish when the day is the956        smallest changing component:957 958        >>> Locale('fi_FI').interval_formats['MEd']['d']959        [u'E d.\u2009\u2013\u2009', u'E d.M.']960 961        .. seealso::962 963           The primary API to use this data is :py:func:`babel.dates.format_interval`.964 965 966        :rtype: dict[str, dict[str, list[str]]]967        """968        return self._data['interval_formats']969 970    @property971    def plural_form(self) -> PluralRule:972        """Plural rules for the locale.973 974        >>> Locale('en').plural_form(1)975        'one'976        >>> Locale('en').plural_form(0)977        'other'978        >>> Locale('fr').plural_form(0)979        'one'980        >>> Locale('ru').plural_form(100)981        'many'982        """983        return self._data.get('plural_form', _default_plural_rule)984 985    @property986    def list_patterns(self) -> localedata.LocaleDataDict:987        """Patterns for generating lists988 989        .. note:: The format of the value returned may change between990                  Babel versions.991 992        >>> Locale('en').list_patterns['standard']['start']993        u'{0}, {1}'994        >>> Locale('en').list_patterns['standard']['end']995        u'{0}, and {1}'996        >>> Locale('en_GB').list_patterns['standard']['end']997        u'{0} and {1}'998        """999        return self._data['list_patterns']1000 1001    @property1002    def ordinal_form(self) -> PluralRule:1003        """Plural rules for the locale.1004 1005        >>> Locale('en').ordinal_form(1)1006        'one'1007        >>> Locale('en').ordinal_form(2)1008        'two'1009        >>> Locale('en').ordinal_form(3)1010        'few'1011        >>> Locale('fr').ordinal_form(2)1012        'other'1013        >>> Locale('ru').ordinal_form(100)1014        'other'1015        """1016        return self._data.get('ordinal_form', _default_plural_rule)1017 1018    @property1019    def measurement_systems(self) -> localedata.LocaleDataDict:1020        """Localized names for various measurement systems.1021 1022        >>> Locale('fr', 'FR').measurement_systems['US']1023        u'am\\xe9ricain'1024        >>> Locale('en', 'US').measurement_systems['US']1025        u'US'1026 1027        """1028        return self._data['measurement_systems']1029 1030    @property1031    def character_order(self) -> str:1032        """The text direction for the language.1033 1034        >>> Locale('de', 'DE').character_order1035        'left-to-right'1036        >>> Locale('ar', 'SA').character_order1037        'right-to-left'1038        """1039        return self._data['character_order']1040 1041    @property1042    def text_direction(self) -> str:1043        """The text direction for the language in CSS short-hand form.1044 1045        >>> Locale('de', 'DE').text_direction1046        'ltr'1047        >>> Locale('ar', 'SA').text_direction1048        'rtl'1049        """1050        return ''.join(word[0] for word in self.character_order.split('-'))1051 1052    @property1053    def unit_display_names(self) -> localedata.LocaleDataDict:1054        """Display names for units of measurement.1055 1056        .. seealso::1057 1058           You may want to use :py:func:`babel.units.get_unit_name` instead.1059 1060        .. note:: The format of the value returned may change between1061                  Babel versions.1062 1063        """1064        return self._data['unit_display_names']1065 1066 1067def default_locale(category: str | None = None, aliases: Mapping[str, str] = LOCALE_ALIASES) -> str | None:1068    """Returns the system default locale for a given category, based on1069    environment variables.1070 1071    >>> for name in ['LANGUAGE', 'LC_ALL', 'LC_CTYPE']:1072    ...     os.environ[name] = ''1073    >>> os.environ['LANG'] = 'fr_FR.UTF-8'1074    >>> default_locale('LC_MESSAGES')1075    'fr_FR'1076 1077    The "C" or "POSIX" pseudo-locales are treated as aliases for the1078    "en_US_POSIX" locale:1079 1080    >>> os.environ['LC_MESSAGES'] = 'POSIX'1081    >>> default_locale('LC_MESSAGES')1082    'en_US_POSIX'1083 1084    The following fallbacks to the variable are always considered:1085 1086    - ``LANGUAGE``1087    - ``LC_ALL``1088    - ``LC_CTYPE``1089    - ``LANG``1090 1091    :param category: one of the ``LC_XXX`` environment variable names1092    :param aliases: a dictionary of aliases for locale identifiers1093    """1094    varnames = (category, 'LANGUAGE', 'LC_ALL', 'LC_CTYPE', 'LANG')1095    for name in filter(None, varnames):1096        locale = os.getenv(name)1097        if locale:1098            if name == 'LANGUAGE' and ':' in locale:1099                # the LANGUAGE variable may contain a colon-separated list of1100                # language codes; we just pick the language on the list1101                locale = locale.split(':')[0]1102            if locale.split('.')[0] in ('C', 'POSIX'):1103                locale = 'en_US_POSIX'1104            elif aliases and locale in aliases:1105                locale = aliases[locale]1106            try:1107                return get_locale_identifier(parse_locale(locale))1108            except ValueError:1109                pass1110    return None1111 1112 1113def negotiate_locale(preferred: Iterable[str], available: Iterable[str], sep: str = '_', aliases: Mapping[str, str] = LOCALE_ALIASES) -> str | None:1114    """Find the best match between available and requested locale strings.1115 1116    >>> negotiate_locale(['de_DE', 'en_US'], ['de_DE', 'de_AT'])1117    'de_DE'1118    >>> negotiate_locale(['de_DE', 'en_US'], ['en', 'de'])1119    'de'1120 1121    Case is ignored by the algorithm, the result uses the case of the preferred1122    locale identifier:1123 1124    >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at'])1125    'de_DE'1126 1127    >>> negotiate_locale(['de_DE', 'en_US'], ['de_de', 'de_at'])1128    'de_DE'1129 1130    By default, some web browsers unfortunately do not include the territory1131    in the locale identifier for many locales, and some don't even allow the1132    user to easily add the territory. So while you may prefer using qualified1133    locale identifiers in your web-application, they would not normally match1134    the language-only locale sent by such browsers. To workaround that, this1135    function uses a default mapping of commonly used language-only locale1136    identifiers to identifiers including the territory:1137 1138    >>> negotiate_locale(['ja', 'en_US'], ['ja_JP', 'en_US'])1139    'ja_JP'1140 1141    Some browsers even use an incorrect or outdated language code, such as "no"1142    for Norwegian, where the correct locale identifier would actually be "nb_NO"1143    (Bokmål) or "nn_NO" (Nynorsk). The aliases are intended to take care of1144    such cases, too:1145 1146    >>> negotiate_locale(['no', 'sv'], ['nb_NO', 'sv_SE'])1147    'nb_NO'1148 1149    You can override this default mapping by passing a different `aliases`1150    dictionary to this function, or you can bypass the behavior althogher by1151    setting the `aliases` parameter to `None`.1152 1153    :param preferred: the list of locale strings preferred by the user1154    :param available: the list of locale strings available1155    :param sep: character that separates the different parts of the locale1156                strings1157    :param aliases: a dictionary of aliases for locale identifiers1158    """1159    available = [a.lower() for a in available if a]1160    for locale in preferred:1161        ll = locale.lower()1162        if ll in available:1163            return locale1164        if aliases:1165            alias = aliases.get(ll)1166            if alias:1167                alias = alias.replace('_', sep)1168                if alias.lower() in available:1169                    return alias1170        parts = locale.split(sep)1171        if len(parts) > 1 and parts[0].lower() in available:1172            return parts[0]1173    return None1174 1175 1176def parse_locale(1177    identifier: str,1178    sep: str = '_',1179) -> tuple[str, str | None, str | None, str | None] | tuple[str, str | None, str | None, str | None, str | None]:1180    """Parse a locale identifier into a tuple of the form ``(language,1181    territory, script, variant, modifier)``.1182 1183    >>> parse_locale('zh_CN')1184    ('zh', 'CN', None, None)1185    >>> parse_locale('zh_Hans_CN')1186    ('zh', 'CN', 'Hans', None)1187    >>> parse_locale('ca_es_valencia')1188    ('ca', 'ES', None, 'VALENCIA')1189    >>> parse_locale('en_150')1190    ('en', '150', None, None)1191    >>> parse_locale('en_us_posix')1192    ('en', 'US', None, 'POSIX')1193    >>> parse_locale('it_IT@euro')1194    ('it', 'IT', None, None, 'euro')1195    >>> parse_locale('it_IT@custom')1196    ('it', 'IT', None, None, 'custom')1197    >>> parse_locale('it_IT@')1198    ('it', 'IT', None, None)1199 1200    The default component separator is "_", but a different separator can be

Showing the first 1,200 of 1297 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai