From e505e8e5ed0345c504d7a7baaf2be4c8f72ad9c6 Mon Sep 17 00:00:00 2001 From: Himanshu Kumar <77563702+himanshu748@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:59:33 +0530 Subject: [PATCH] Document locale identifier casing and parsing --- babel/core.py | 27 +++++++++++++++++++++------ docs/locale.rst | 21 +++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/babel/core.py b/babel/core.py index 07b2ad0c7..795bf19c5 100644 --- a/babel/core.py +++ b/babel/core.py @@ -152,9 +152,12 @@ class Locale: >>> locale.display_name 'English (United States)' - A `Locale` object can also be instantiated from a raw locale string: + The constructor preserves the casing of the components. Use lowercase + language codes, uppercase territory and variant codes, and title-case + script codes. A `Locale` object can also be instantiated from a raw locale + string with :meth:`parse`, which normalizes the casing of these codes: - >>> locale = Locale.parse('en-US', sep='-') + >>> locale = Locale.parse('EN-us', sep='-') >>> repr(locale) "Locale('en', territory='US')" @@ -191,10 +194,15 @@ def __init__( >>> 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 + The components are stored as supplied, without case normalization. + Use :meth:`parse` for case-insensitive parsing of locale identifier + strings. + + :param language: the lowercase language code + :param territory: the uppercase territory (country or region) code, + or a numeric region code + :param script: the title-case script code + :param variant: the uppercase variant code :param modifier: a modifier (following the '@' symbol, sometimes called '@variant') :raise `UnknownLocaleError`: if no locale data is available for the requested locale @@ -295,6 +303,13 @@ def parse( >>> l.display_name 'Deutsch (Deutschland)' + For string identifiers, language, territory, script, and variant codes + are case-insensitive and normalized to their usual casing. Modifiers + retain their casing. + + >>> Locale.parse('ZH_hANT_tw') + Locale('zh', territory='TW', script='Hant') + If the `identifier` parameter is not a string, but actually a `Locale` object, that object is returned: diff --git a/docs/locale.rst b/docs/locale.rst index abb36fcf5..013242b34 100644 --- a/docs/locale.rst +++ b/docs/locale.rst @@ -35,6 +35,27 @@ You normally access such locale data through the >>> locale.territories['US'] 'Estados Unidos' +Locale identifiers use lowercase language codes (``en``), uppercase alphabetic +territory codes (``US``), title-case script codes (``Latn``), and uppercase +variant codes (``POSIX``). Numeric territory codes, such as ``419``, are also +supported. The ``Locale`` constructor preserves the casing of its components, +so use this casing when passing them directly. + +To accept locale identifier strings with different casing, use +:meth:`Locale.parse `, which normalizes the language, +territory, script, and variant codes: + +.. code-block:: pycon + + >>> Locale.parse('EN_us') + Locale('en', territory='US') + >>> Locale.parse('ZH_hANT_tw') + Locale('zh', territory='TW', script='Hant') + >>> Locale.parse('ca_es_valencia') + Locale('ca', territory='ES', variant='VALENCIA') + +The optional modifier following ``@`` retains its casing. + In addition to country/territory names, the locale data also provides access to names of languages, scripts, variants, time zones, and more. Some of the data is closely related to number and date formatting.