Odoo18-Base/odoo/tools/i18n.py

105 lines
3.4 KiB
Python
Raw Permalink Normal View History

2025-01-06 10:57:38 +07:00
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)