Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
repos:
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.12.12
rev: 5ba58aca0bd5bc7c0e1c0fc45af2e88d6a2bde83 # frozen: v0.14.10
hooks:
- id: ruff-check
args:
- --fix
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0
hooks:
- id: check-added-large-files
- id: check-docstring-first
Expand Down
22 changes: 11 additions & 11 deletions babel/__init__.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
"""
babel
~~~~~
babel
~~~~~

Integrated collection of utilities that assist in internationalizing and
localizing applications.
Integrated collection of utilities that assist in internationalizing and
localizing applications.

This package is basically composed of two major parts:
This package is basically composed of two major parts:

* tools to build and work with ``gettext`` message catalogs
* a Python interface to the CLDR (Common Locale Data Repository), providing
access to various locale display names, localized number and date
formatting, etc.
* tools to build and work with ``gettext`` message catalogs
* a Python interface to the CLDR (Common Locale Data Repository), providing
access to various locale display names, localized number and date
formatting, etc.

:copyright: (c) 2013-2025 by the Babel Team.
:license: BSD, see LICENSE for more details.
:copyright: (c) 2013-2025 by the Babel Team.
:license: BSD, see LICENSE for more details.
"""

from babel.core import (
Expand Down
110 changes: 69 additions & 41 deletions babel/core.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""
babel.core
~~~~~~~~~~
babel.core
~~~~~~~~~~

Core locale representation and locale data access.
Core locale representation and locale data access.

:copyright: (c) 2013-2025 by the Babel Team.
:license: BSD, see LICENSE for more details.
:copyright: (c) 2013-2025 by the Babel Team.
:license: BSD, see LICENSE for more details.
"""

from __future__ import annotations
Expand Down Expand Up @@ -56,12 +56,14 @@


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.')
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]:
Expand Down Expand Up @@ -119,7 +121,7 @@ def get_global(key: _GLOBAL_KEY) -> Mapping[str, Any]:
'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',
}
} # fmt: skip


class UnknownLocaleError(Exception):
Expand Down Expand Up @@ -216,7 +218,11 @@ def __init__(
raise UnknownLocaleError(identifier)

@classmethod
def default(cls, category: str | None = None, aliases: Mapping[str, str] = LOCALE_ALIASES) -> Locale:
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']:
Expand Down Expand Up @@ -268,8 +274,7 @@ def negotiate(
: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)
identifier = negotiate_locale(preferred, available, sep=sep, aliases=aliases)
if identifier:
return Locale.parse(identifier, sep=sep)
return None
Expand Down Expand Up @@ -346,7 +351,8 @@ def parse(
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
# `parse_locale` would raise a ValueError, so let's do that here
raise ValueError(msg)
raise TypeError(msg)

if not isinstance(identifier, str):
Expand Down Expand Up @@ -420,7 +426,9 @@ def _try_load_reducing(parts):
else:
language2, _, script2, variant2 = parts2
modifier2 = None
locale = _try_load_reducing((language2, territory, script2, variant2, modifier2))
locale = _try_load_reducing(
(language2, territory, script2, variant2, modifier2),
)
if locale is not None:
return locale

Expand All @@ -431,19 +439,18 @@ def __eq__(self, other: object) -> bool:
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
self.language == getattr(other, 'language') # noqa: B009
and self.territory == getattr(other, 'territory') # noqa: B009
and self.script == getattr(other, 'script') # noqa: B009
and self.variant == getattr(other, 'variant') # noqa: B009
and 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))
return hash((self.language, self.territory, self.script, self.variant, self.modifier))

def __repr__(self) -> str:
parameters = ['']
Expand All @@ -454,9 +461,9 @@ def __repr__(self) -> str:
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))
return get_locale_identifier(
(self.language, self.territory, self.script, self.variant, self.modifier),
)

@property
def _data(self) -> localedata.LocaleDataDict:
Expand Down Expand Up @@ -499,7 +506,9 @@ def get_display_name(self, locale: Locale | str | None = None) -> str | None:
retval += f" ({detail_string})"
return retval

display_name = property(get_display_name, doc="""\
display_name = property(
get_display_name,
doc="""\
The localized display name of the locale.

>>> Locale('en').display_name
Expand All @@ -510,7 +519,8 @@ def get_display_name(self, locale: Locale | str | None = None) -> str | None:
'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.
Expand All @@ -527,12 +537,15 @@ def get_language_name(self, locale: Locale | str | None = None) -> str | None:
locale = Locale.parse(locale)
return locale.languages.get(self.language)

language_name = property(get_language_name, doc="""\
language_name = property(
get_language_name,
doc="""\
The localized language name of the locale.

>>> Locale('en', 'US').language_name
'English'
""")
""",
)

def get_territory_name(self, locale: Locale | str | None = None) -> str | None:
"""Return the territory name in the given locale."""
Expand All @@ -541,12 +554,15 @@ def get_territory_name(self, locale: Locale | str | None = None) -> str | None:
locale = Locale.parse(locale)
return locale.territories.get(self.territory or '')

territory_name = property(get_territory_name, doc="""\
territory_name = property(
get_territory_name,
doc="""\
The localized territory name of the locale if available.

>>> Locale('de', 'DE').territory_name
'Deutschland'
""")
""",
)

def get_script_name(self, locale: Locale | str | None = None) -> str | None:
"""Return the script name in the given locale."""
Expand All @@ -555,12 +571,15 @@ def get_script_name(self, locale: Locale | str | None = None) -> str | None:
locale = Locale.parse(locale)
return locale.scripts.get(self.script or '')

script_name = property(get_script_name, doc="""\
script_name = property(
get_script_name,
doc="""\
The localized script name of the locale if available.

>>> Locale('sr', 'ME', script='Latn').script_name
'latinica'
""")
""",
)

@property
def english_name(self) -> str | None:
Expand Down Expand Up @@ -784,8 +803,7 @@ def day_periods(self) -> localedata.LocaleDataDict:

@property
def day_period_rules(self) -> localedata.LocaleDataDict:
"""Day period rules for the locale. Used by `get_period_id`.
"""
"""Day period rules for the locale. Used by `get_period_id`."""
return self._data.get('day_period_rules', localedata.LocaleDataDict({}))

@property
Expand Down Expand Up @@ -1149,7 +1167,12 @@ def default_locale(
return None


def negotiate_locale(preferred: Iterable[str], available: Iterable[str], sep: str = '_', aliases: Mapping[str, str] = LOCALE_ALIASES) -> str | 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'])
Expand Down Expand Up @@ -1215,7 +1238,10 @@ def negotiate_locale(preferred: Iterable[str], available: Iterable[str], sep: st
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]:
) -> (
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)``.

Expand Down Expand Up @@ -1293,8 +1319,10 @@ def parse_locale(
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()
len(parts[0]) == 4
and parts[0][0].isdigit()
or len(parts[0]) >= 5
and parts[0][0].isalpha()
):
variant = parts.pop().upper()

Expand Down
Loading
Loading