Odoo18-Base/odoo/tools/i18n.py
2025-01-06 10:57:38 +07:00

105 lines
3.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import re
from typing import TYPE_CHECKING, Literal, Optional, Sequence
from babel import lists
from odoo.tools.misc import babel_locale_parse, get_lang
if TYPE_CHECKING:
import odoo.api
XPG_LOCALE_RE = re.compile(
r"""^
([a-z]+) # language
(_[A-Z\d]+)? # maybe _territory
# no support for .codeset (we don't use that in Odoo)
(@.+)? # maybe @modifier
$""",
re.VERBOSE,
)
def format_list(
env: odoo.api.Environment,
lst: Sequence[str],
style: Literal["standard", "standard-short", "or", "or-short", "unit", "unit-short", "unit-narrow"] = "standard",
lang_code: Optional[str] = None,
) -> str:
"""
Format the items in `lst` as a list in a locale-dependent manner with the chosen style.
The available styles are defined by babel according to the Unicode TR35-49 spec:
* standard:
A typical 'and' list for arbitrary placeholders.
e.g. "January, February, and March"
* standard-short:
A short version of an 'and' list, suitable for use with short or abbreviated placeholder values.
e.g. "Jan., Feb., and Mar."
* or:
A typical 'or' list for arbitrary placeholders.
e.g. "January, February, or March"
* or-short:
A short version of an 'or' list.
e.g. "Jan., Feb., or Mar."
* unit:
A list suitable for wide units.
e.g. "3 feet, 7 inches"
* unit-short:
A list suitable for short units
e.g. "3 ft, 7 in"
* unit-narrow:
A list suitable for narrow units, where space on the screen is very limited.
e.g. "3 7″"
See https://www.unicode.org/reports/tr35/tr35-49/tr35-general.html#ListPatterns for more details.
:param env: the current environment.
:param lst: the sequence of items to format into a list.
:param style: the style to format the list with.
:param lang_code: the locale (i.e. en_US).
:return: the formatted list.
"""
locale = babel_locale_parse(lang_code or get_lang(env).code)
# Some styles could be unavailable for the chosen locale
if style not in locale.list_patterns:
style = "standard"
return lists.format_list(lst, style, locale)
def py_to_js_locale(locale: str) -> str:
"""
Converts a locale from Python to JavaScript format.
Most of the time the conversion is simply to replace _ with -.
Example: fr_BE → fr-BE
Exception: Serbian can be written in both Latin and Cyrillic scripts
interchangeably, therefore its locale includes a special modifier
to indicate which script to use.
Example: sr@latin → sr-Latn
BCP 47 (JS):
language[-extlang][-script][-region][-variant][-extension][-privateuse]
https://www.ietf.org/rfc/rfc5646.txt
XPG syntax (Python):
language[_territory][.codeset][@modifier]
https://www.gnu.org/software/libc/manual/html_node/Locale-Names.html
:param locale: The locale formatted for use on the Python-side.
:return: The locale formatted for use on the JavaScript-side.
"""
match_ = XPG_LOCALE_RE.match(locale)
if not match_:
return locale
language, territory, modifier = match_.groups()
subtags = [language]
if modifier == "@Cyrl":
subtags.append("Cyrl")
elif modifier == "@latin":
subtags.append("Latn")
if territory:
subtags.append(territory.removeprefix("_"))
return "-".join(subtags)