cosmo-intl 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cosmo_intl-0.1.0/.github/workflows/test.yml +27 -0
- cosmo_intl-0.1.0/.gitignore +6 -0
- cosmo_intl-0.1.0/PKG-INFO +109 -0
- cosmo_intl-0.1.0/README.md +85 -0
- cosmo_intl-0.1.0/example.py +28 -0
- cosmo_intl-0.1.0/pyproject.toml +60 -0
- cosmo_intl-0.1.0/src/cosmo/__init__.py +15 -0
- cosmo_intl-0.1.0/src/cosmo/bundle.py +18 -0
- cosmo_intl-0.1.0/src/cosmo/cosmo.py +1231 -0
- cosmo_intl-0.1.0/src/cosmo/errors.py +19 -0
- cosmo_intl-0.1.0/tests/test_cosmo.py +441 -0
- cosmo_intl-0.1.0/uv.lock +211 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
fail-fast: false
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.9", "3.11", "3.13"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
|
|
18
|
+
# PyICU is a C extension; it needs the system ICU headers + a compiler.
|
|
19
|
+
- name: Install ICU
|
|
20
|
+
run: sudo apt-get update && sudo apt-get install -y libicu-dev pkg-config
|
|
21
|
+
|
|
22
|
+
- uses: astral-sh/setup-uv@v5
|
|
23
|
+
with:
|
|
24
|
+
enable-cache: true
|
|
25
|
+
|
|
26
|
+
- name: Run tests
|
|
27
|
+
run: uv run --extra test --python ${{ matrix.python-version }} pytest -q
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cosmo-intl
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Ergonomic internationalization (i18n) and localization (l10n) for Python — format numbers, currency, dates, times, units, lists and ICU plurals for any locale, powered by ICU and Unicode CLDR via PyICU. No bundled locale data.
|
|
5
|
+
Project-URL: Homepage, https://github.com/cosmo-intl/cosmo-python
|
|
6
|
+
Project-URL: Repository, https://github.com/cosmo-intl/cosmo-python
|
|
7
|
+
Project-URL: PHP port, https://github.com/cosmo-intl/cosmo-php
|
|
8
|
+
Author-email: Miloun <cosmo-python@miloun.com>
|
|
9
|
+
License: MIT
|
|
10
|
+
Keywords: cldr,currency,date,datetime,i18n,icu,internationalisation,internationalization,intl,l10n,locale,localisation,localization,money,pluralization,pyicu,timezone,translation,unicode
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Topic :: Software Development :: Internationalization
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Classifier: Topic :: Software Development :: Localization
|
|
19
|
+
Requires-Python: >=3.9
|
|
20
|
+
Requires-Dist: pyicu>=2.10
|
|
21
|
+
Provides-Extra: test
|
|
22
|
+
Requires-Dist: pytest>=7; extra == 'test'
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
|
|
25
|
+
# Cosmo
|
|
26
|
+
|
|
27
|
+
Ergonomic application localisation for Python, powered by [ICU](https://icu.unicode.org/).
|
|
28
|
+
|
|
29
|
+
Cosmo is a thin, ergonomic layer over **ICU**, reached through
|
|
30
|
+
[PyICU](https://gitlab.pyicu.org/main/pyicu). Give it a locale (and optionally a
|
|
31
|
+
time zone) and it formats numbers, money, dates, units, lists and messages exactly
|
|
32
|
+
the way your users expect. There is **no bundled locale data** — every result comes
|
|
33
|
+
straight from ICU and [CLDR](https://cldr.unicode.org/), covering all languages,
|
|
34
|
+
scripts, calendars and time zones.
|
|
35
|
+
|
|
36
|
+
Cosmo is implemented consistently across four languages — the same concepts, method
|
|
37
|
+
names and behaviour, each built directly on its platform's ICU:
|
|
38
|
+
[JavaScript](https://github.com/cosmo-intl/cosmo-js) ([docs](https://cosmo.miloun.com/?lang=js)) ·
|
|
39
|
+
**Python** ·
|
|
40
|
+
[Java](https://github.com/cosmo-intl/cosmo-java) ([docs](https://cosmo.miloun.com/?lang=java)) ·
|
|
41
|
+
[PHP](https://github.com/salarmehr/cosmopolitan) ([docs](https://cosmo.miloun.com/?lang=php)).
|
|
42
|
+
|
|
43
|
+
📖 **Full documentation, API reference and live playground:** https://cosmo.miloun.com/?lang=python
|
|
44
|
+
|
|
45
|
+
## Requirements
|
|
46
|
+
|
|
47
|
+
- Python 3.9+
|
|
48
|
+
- System ICU development libraries for PyICU (e.g. `libicu-dev` + `pkg-config`)
|
|
49
|
+
|
|
50
|
+
## Install
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pip install cosmo-intl # pulls in PyICU; the import package is `cosmo`
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Quick start
|
|
57
|
+
|
|
58
|
+
```python
|
|
59
|
+
from cosmo import Cosmo
|
|
60
|
+
|
|
61
|
+
Cosmo("es_ES").money(11000.4, "EUR") # "11.000,40 €"
|
|
62
|
+
Cosmo("en").percentage(0.2) # "20%"
|
|
63
|
+
Cosmo("en_AU").money(1234.5) # "$1,234.50" (currency inferred)
|
|
64
|
+
Cosmo("en").spellout(42) # "forty-two"
|
|
65
|
+
Cosmo("fa").language("en") # "انگلیسی"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
All methods are `snake_case`. Underscore locales (`en_AU`) and [BCP-47](https://www.rfc-editor.org/info/bcp47)
|
|
69
|
+
[Unicode extensions](https://unicode.org/reports/tr35/#u_Extension)
|
|
70
|
+
(`fa-IR-u-nu-latn-ca-buddhist`) are both accepted.
|
|
71
|
+
|
|
72
|
+
## What you get
|
|
73
|
+
|
|
74
|
+
- **Locale display names** — languages, regions, scripts, calendars and currencies, plus emoji flags and writing direction.
|
|
75
|
+
- **Numbers & money** — decimals, percentages, currencies (inferred from the region), units, compact notation, scientific, ranges, plus spelled-out and ordinal text.
|
|
76
|
+
- **Dates & times** — locale formats in any calendar (Gregorian, Persian, Buddhist…), custom ICU patterns, durations, date ranges, and relative times.
|
|
77
|
+
- **Text** — locale-aware sort and search, word/sentence/grapheme segmentation, case mapping and quotation marks.
|
|
78
|
+
- **Messages** — [ICU MessageFormat](https://unicode-org.github.io/icu/userguide/format_parse/messages/) (`plural`, `selectordinal`, `select`).
|
|
79
|
+
- **Parsing & transforms** — the inverse formatters for numbers, money and dates, transliteration, UTS #39 spoof checks, locale negotiation and contact-list index buckets.
|
|
80
|
+
- **Raw ICU access** — resource-bundle lookups for data the high-level methods don't cover.
|
|
81
|
+
|
|
82
|
+
See the [full API reference](https://cosmo.miloun.com/api-reference/?lang=python) for every method,
|
|
83
|
+
the [platform notes](https://cosmo.miloun.com/platform-notes/) for PyICU's binding
|
|
84
|
+
limits, and [resources](https://cosmo.miloun.com/resources/) for ICU/CLDR references.
|
|
85
|
+
|
|
86
|
+
## Development
|
|
87
|
+
|
|
88
|
+
The dev environment is managed with [uv](https://docs.astral.sh/uv/), which
|
|
89
|
+
provisions a matching Python automatically. You still need the system ICU
|
|
90
|
+
libraries (e.g. `libicu-dev` + `pkg-config`) for PyICU to build and link.
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
uv run --extra test pytest # run the test suite
|
|
94
|
+
uv build # build the wheel + sdist into dist/
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
`uv.lock` pins the dev/test toolchain for reproducible local runs and CI. It does
|
|
98
|
+
**not** affect anyone who `pip install cosmo-intl` — they resolve from the
|
|
99
|
+
dependency ranges in `pyproject.toml`.
|
|
100
|
+
|
|
101
|
+
## Errors
|
|
102
|
+
|
|
103
|
+
Recoverable problems raise `CosmoError`, with `InvalidArgumentError` and
|
|
104
|
+
`UnsupportedError` subclasses — an invalid currency in strict mode, an unsupported
|
|
105
|
+
unit, an unknown symbol name, an unformattable date, and the like.
|
|
106
|
+
|
|
107
|
+
## License
|
|
108
|
+
|
|
109
|
+
MIT © Aiden Adrian
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Cosmo
|
|
2
|
+
|
|
3
|
+
Ergonomic application localisation for Python, powered by [ICU](https://icu.unicode.org/).
|
|
4
|
+
|
|
5
|
+
Cosmo is a thin, ergonomic layer over **ICU**, reached through
|
|
6
|
+
[PyICU](https://gitlab.pyicu.org/main/pyicu). Give it a locale (and optionally a
|
|
7
|
+
time zone) and it formats numbers, money, dates, units, lists and messages exactly
|
|
8
|
+
the way your users expect. There is **no bundled locale data** — every result comes
|
|
9
|
+
straight from ICU and [CLDR](https://cldr.unicode.org/), covering all languages,
|
|
10
|
+
scripts, calendars and time zones.
|
|
11
|
+
|
|
12
|
+
Cosmo is implemented consistently across four languages — the same concepts, method
|
|
13
|
+
names and behaviour, each built directly on its platform's ICU:
|
|
14
|
+
[JavaScript](https://github.com/cosmo-intl/cosmo-js) ([docs](https://cosmo.miloun.com/?lang=js)) ·
|
|
15
|
+
**Python** ·
|
|
16
|
+
[Java](https://github.com/cosmo-intl/cosmo-java) ([docs](https://cosmo.miloun.com/?lang=java)) ·
|
|
17
|
+
[PHP](https://github.com/salarmehr/cosmopolitan) ([docs](https://cosmo.miloun.com/?lang=php)).
|
|
18
|
+
|
|
19
|
+
📖 **Full documentation, API reference and live playground:** https://cosmo.miloun.com/?lang=python
|
|
20
|
+
|
|
21
|
+
## Requirements
|
|
22
|
+
|
|
23
|
+
- Python 3.9+
|
|
24
|
+
- System ICU development libraries for PyICU (e.g. `libicu-dev` + `pkg-config`)
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install cosmo-intl # pulls in PyICU; the import package is `cosmo`
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Quick start
|
|
33
|
+
|
|
34
|
+
```python
|
|
35
|
+
from cosmo import Cosmo
|
|
36
|
+
|
|
37
|
+
Cosmo("es_ES").money(11000.4, "EUR") # "11.000,40 €"
|
|
38
|
+
Cosmo("en").percentage(0.2) # "20%"
|
|
39
|
+
Cosmo("en_AU").money(1234.5) # "$1,234.50" (currency inferred)
|
|
40
|
+
Cosmo("en").spellout(42) # "forty-two"
|
|
41
|
+
Cosmo("fa").language("en") # "انگلیسی"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
All methods are `snake_case`. Underscore locales (`en_AU`) and [BCP-47](https://www.rfc-editor.org/info/bcp47)
|
|
45
|
+
[Unicode extensions](https://unicode.org/reports/tr35/#u_Extension)
|
|
46
|
+
(`fa-IR-u-nu-latn-ca-buddhist`) are both accepted.
|
|
47
|
+
|
|
48
|
+
## What you get
|
|
49
|
+
|
|
50
|
+
- **Locale display names** — languages, regions, scripts, calendars and currencies, plus emoji flags and writing direction.
|
|
51
|
+
- **Numbers & money** — decimals, percentages, currencies (inferred from the region), units, compact notation, scientific, ranges, plus spelled-out and ordinal text.
|
|
52
|
+
- **Dates & times** — locale formats in any calendar (Gregorian, Persian, Buddhist…), custom ICU patterns, durations, date ranges, and relative times.
|
|
53
|
+
- **Text** — locale-aware sort and search, word/sentence/grapheme segmentation, case mapping and quotation marks.
|
|
54
|
+
- **Messages** — [ICU MessageFormat](https://unicode-org.github.io/icu/userguide/format_parse/messages/) (`plural`, `selectordinal`, `select`).
|
|
55
|
+
- **Parsing & transforms** — the inverse formatters for numbers, money and dates, transliteration, UTS #39 spoof checks, locale negotiation and contact-list index buckets.
|
|
56
|
+
- **Raw ICU access** — resource-bundle lookups for data the high-level methods don't cover.
|
|
57
|
+
|
|
58
|
+
See the [full API reference](https://cosmo.miloun.com/api-reference/?lang=python) for every method,
|
|
59
|
+
the [platform notes](https://cosmo.miloun.com/platform-notes/) for PyICU's binding
|
|
60
|
+
limits, and [resources](https://cosmo.miloun.com/resources/) for ICU/CLDR references.
|
|
61
|
+
|
|
62
|
+
## Development
|
|
63
|
+
|
|
64
|
+
The dev environment is managed with [uv](https://docs.astral.sh/uv/), which
|
|
65
|
+
provisions a matching Python automatically. You still need the system ICU
|
|
66
|
+
libraries (e.g. `libicu-dev` + `pkg-config`) for PyICU to build and link.
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
uv run --extra test pytest # run the test suite
|
|
70
|
+
uv build # build the wheel + sdist into dist/
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
`uv.lock` pins the dev/test toolchain for reproducible local runs and CI. It does
|
|
74
|
+
**not** affect anyone who `pip install cosmo-intl` — they resolve from the
|
|
75
|
+
dependency ranges in `pyproject.toml`.
|
|
76
|
+
|
|
77
|
+
## Errors
|
|
78
|
+
|
|
79
|
+
Recoverable problems raise `CosmoError`, with `InvalidArgumentError` and
|
|
80
|
+
`UnsupportedError` subclasses — an invalid currency in strict mode, an unsupported
|
|
81
|
+
unit, an unknown symbol name, an unformattable date, and the like.
|
|
82
|
+
|
|
83
|
+
## License
|
|
84
|
+
|
|
85
|
+
MIT © Aiden Adrian
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Runnable tour of cosmo. `python example.py`"""
|
|
2
|
+
|
|
3
|
+
import datetime
|
|
4
|
+
|
|
5
|
+
from cosmo import Cosmo
|
|
6
|
+
|
|
7
|
+
when = datetime.datetime(2020, 2, 2, 9, 30, tzinfo=datetime.timezone.utc)
|
|
8
|
+
|
|
9
|
+
for tag in ("en_AU", "fa_IR", "de_DE"):
|
|
10
|
+
c = Cosmo(tag, {"timeZone": "UTC"})
|
|
11
|
+
print(f"\n=== {tag} ===")
|
|
12
|
+
print("language(en): ", c.language("en"))
|
|
13
|
+
print("country/flag: ", c.country(), c.flag())
|
|
14
|
+
print("number: ", c.number(1234567.89))
|
|
15
|
+
print("money: ", c.money(1234.5))
|
|
16
|
+
print("percentage: ", c.percentage(0.1234))
|
|
17
|
+
print("compact: ", c.compact(1_200_000, "long"))
|
|
18
|
+
print("spellout/ord: ", c.spellout(42), "/", c.ordinal(21))
|
|
19
|
+
print("moment: ", c.moment(when, "full", "short"))
|
|
20
|
+
print("month[0]: ", c.month_names()[0])
|
|
21
|
+
print("relative: ", c.relative_duration(-3, "day"))
|
|
22
|
+
print("join: ", c.join(["apples", "pears", "figs"]))
|
|
23
|
+
print("quote: ", c.quote("hi"))
|
|
24
|
+
print("plural(2): ", c.plural_category(2))
|
|
25
|
+
print(
|
|
26
|
+
"message: ",
|
|
27
|
+
c.message("{0, plural, one {# file} other {# files}}", [3]),
|
|
28
|
+
)
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
# PyPI distribution name; the bare `cosmo` is taken on PyPI, so we publish as
|
|
7
|
+
# `cosmo-intl` (matches the GitHub org) while the import package stays `cosmo`.
|
|
8
|
+
name = "cosmo-intl"
|
|
9
|
+
version = "0.1.0"
|
|
10
|
+
description = "Ergonomic internationalization (i18n) and localization (l10n) for Python — format numbers, currency, dates, times, units, lists and ICU plurals for any locale, powered by ICU and Unicode CLDR via PyICU. No bundled locale data."
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
requires-python = ">=3.9"
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
authors = [{ name = "Miloun", email = "cosmo-python@miloun.com" }]
|
|
15
|
+
keywords = [
|
|
16
|
+
"i18n",
|
|
17
|
+
"l10n",
|
|
18
|
+
"internationalization",
|
|
19
|
+
"internationalisation",
|
|
20
|
+
"localization",
|
|
21
|
+
"localisation",
|
|
22
|
+
"intl",
|
|
23
|
+
"icu",
|
|
24
|
+
"cldr",
|
|
25
|
+
"unicode",
|
|
26
|
+
"locale",
|
|
27
|
+
"translation",
|
|
28
|
+
"currency",
|
|
29
|
+
"money",
|
|
30
|
+
"date",
|
|
31
|
+
"datetime",
|
|
32
|
+
"timezone",
|
|
33
|
+
"pluralization",
|
|
34
|
+
"pyicu",
|
|
35
|
+
]
|
|
36
|
+
classifiers = [
|
|
37
|
+
"Programming Language :: Python :: 3",
|
|
38
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
39
|
+
"Topic :: Software Development :: Localization",
|
|
40
|
+
"Topic :: Software Development :: Internationalization",
|
|
41
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
42
|
+
"Intended Audience :: Developers",
|
|
43
|
+
"License :: OSI Approved :: MIT License",
|
|
44
|
+
"Operating System :: OS Independent",
|
|
45
|
+
]
|
|
46
|
+
dependencies = ["PyICU>=2.10"]
|
|
47
|
+
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
test = ["pytest>=7"]
|
|
50
|
+
|
|
51
|
+
[project.urls]
|
|
52
|
+
Homepage = "https://github.com/cosmo-intl/cosmo-python"
|
|
53
|
+
Repository = "https://github.com/cosmo-intl/cosmo-python"
|
|
54
|
+
"PHP port" = "https://github.com/cosmo-intl/cosmo-php"
|
|
55
|
+
|
|
56
|
+
[tool.hatch.build.targets.wheel]
|
|
57
|
+
packages = ["src/cosmo"]
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""Cosmo — application localisation for Python, backed entirely by ICU."""
|
|
2
|
+
|
|
3
|
+
from .bundle import Bundle
|
|
4
|
+
from .cosmo import Cosmo, Moment
|
|
5
|
+
from .errors import CosmoError, InvalidArgumentError, UnsupportedError
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"Cosmo",
|
|
9
|
+
"Bundle",
|
|
10
|
+
"CosmoError",
|
|
11
|
+
"InvalidArgumentError",
|
|
12
|
+
"UnsupportedError",
|
|
13
|
+
"Moment",
|
|
14
|
+
]
|
|
15
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Names of the ICU resource bundles reachable through :meth:`Cosmo.get`.
|
|
2
|
+
|
|
3
|
+
These mirror the constants in the PHP port's ``Bundle`` class. They are the
|
|
4
|
+
package identifiers PyICU's :class:`icu.ResourceBundle` understands.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Bundle:
|
|
9
|
+
"""ICU resource-bundle package names."""
|
|
10
|
+
|
|
11
|
+
#: Break-iterator rule source data.
|
|
12
|
+
BRKITR = "ICUDATA-brkitr"
|
|
13
|
+
#: Currency symbols and display names.
|
|
14
|
+
CURRENCY = "ICUDATA-curr"
|
|
15
|
+
#: The per-locale bundle (delimiters, layout, …).
|
|
16
|
+
LOCALE = "ICUDATA"
|
|
17
|
+
#: Language / script / calendar display names.
|
|
18
|
+
LANGUAGE = "ICUDATA-lang"
|