Update upstream source from tag 'upstream/4.4.0'
Update to upstream version '4.4.0'
with Debian dir 103707c6999ada5e09e3dc7b0d470dbc4a2c8247
Sylvestre Ledru
1 year, 7 months ago
0 | version: 2 | |
1 | updates: | |
2 | - package-ecosystem: github-actions | |
3 | directory: "/" | |
4 | schedule: | |
5 | interval: monthly | |
6 | time: "03:00" | |
7 | open-pull-requests-limit: 10 | |
8 | labels: | |
9 | - "changelog: skip" | |
10 | - "dependencies" | |
11 | - package-ecosystem: pip | |
12 | directory: "/" | |
13 | schedule: | |
14 | interval: monthly | |
15 | time: "03:00" | |
16 | open-pull-requests-limit: 10 | |
17 | labels: | |
18 | - "changelog: skip" | |
19 | - "dependencies" |
0 | { | |
1 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", | |
2 | "extends": ["config:base"], | |
3 | "labels": ["changelog: skip", "dependencies"], | |
4 | "packageRules": [ | |
5 | { | |
6 | "groupName": "github-actions", | |
7 | "matchManagers": ["github-actions"], | |
8 | "separateMajorMinor": "false" | |
9 | } | |
10 | ], | |
11 | "schedule": ["on the first day of the month"] | |
12 | } |
9 | 9 | - uses: actions/checkout@v3 |
10 | 10 | |
11 | 11 | - name: Set up Python |
12 | uses: actions/setup-python@v3 | |
12 | uses: actions/setup-python@v4 | |
13 | 13 | with: |
14 | 14 | python-version: "3.x" |
15 | 15 | cache: pip |
7 | 7 | |
8 | 8 | steps: |
9 | 9 | - uses: actions/checkout@v3 |
10 | - uses: actions/setup-python@v3 | |
11 | - uses: pre-commit/action@v2.0.3 | |
10 | - uses: actions/setup-python@v4 | |
11 | with: | |
12 | python-version: "3.x" | |
13 | - uses: pre-commit/action@v3.0.0 |
8 | 8 | runs-on: ubuntu-latest |
9 | 9 | |
10 | 10 | steps: |
11 | - uses: mheap/github-action-required-labels@v1 | |
11 | - uses: mheap/github-action-required-labels@v2 | |
12 | 12 | with: |
13 | 13 | mode: minimum |
14 | 14 | count: 1 |
17 | 17 | - uses: actions/checkout@v3 |
18 | 18 | |
19 | 19 | - name: Set up Python ${{ matrix.python-version }} |
20 | uses: actions/setup-python@v3 | |
20 | uses: actions/setup-python@v4 | |
21 | 21 | with: |
22 | 22 | python-version: ${{ matrix.python-version }} |
23 | 23 | cache: pip |
0 | 0 | repos: |
1 | 1 | - repo: https://github.com/asottile/pyupgrade |
2 | rev: v2.32.0 | |
2 | rev: v2.37.3 | |
3 | 3 | hooks: |
4 | 4 | - id: pyupgrade |
5 | 5 | args: [--py37-plus] |
6 | 6 | |
7 | 7 | - repo: https://github.com/psf/black |
8 | rev: 22.3.0 | |
8 | rev: 22.6.0 | |
9 | 9 | hooks: |
10 | 10 | - id: black |
11 | 11 | args: [--target-version=py37] |
30 | 30 | files: \.py$ |
31 | 31 | |
32 | 32 | - repo: https://github.com/PyCQA/flake8 |
33 | rev: 4.0.1 | |
33 | rev: 5.0.4 | |
34 | 34 | hooks: |
35 | 35 | - id: flake8 |
36 | 36 | additional_dependencies: [flake8-2020, flake8-implicit-str-concat] |
41 | 41 | - id: python-check-blanket-noqa |
42 | 42 | |
43 | 43 | - repo: https://github.com/pre-commit/pre-commit-hooks |
44 | rev: v4.2.0 | |
44 | rev: v4.3.0 | |
45 | 45 | hooks: |
46 | - id: check-json | |
46 | 47 | - id: check-merge-conflict |
47 | 48 | - id: check-toml |
48 | 49 | - id: check-yaml |
56 | 57 | files: "src/" |
57 | 58 | |
58 | 59 | - repo: https://github.com/pre-commit/mirrors-mypy |
59 | rev: v0.942 | |
60 | rev: v0.971 | |
60 | 61 | hooks: |
61 | 62 | - id: mypy |
62 | 63 | additional_dependencies: [pytest, types-freezegun, types-setuptools] |
63 | 64 | args: [--strict] |
64 | 65 | |
65 | 66 | - repo: https://github.com/asottile/setup-cfg-fmt |
66 | rev: v1.20.1 | |
67 | rev: v2.0.0 | |
67 | 68 | hooks: |
68 | 69 | - id: setup-cfg-fmt |
69 | args: [--max-py-version=3.11] | |
70 | args: [--max-py-version=3.11, --include-version-classifiers] | |
70 | 71 | |
71 | 72 | - repo: https://github.com/tox-dev/pyproject-fmt |
72 | rev: 0.3.3 | |
73 | rev: 0.3.5 | |
73 | 74 | hooks: |
74 | 75 | - id: pyproject-fmt |
75 | 76 |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: humanize |
2 | Version: 4.2.3 | |
2 | Version: 4.4.0 | |
3 | 3 | Summary: Python humanize utilities |
4 | 4 | Home-page: https://github.com/python-humanize/humanize |
5 | 5 | Author: Jason Moiron |
58 | 58 | - Finnish |
59 | 59 | - French |
60 | 60 | - German |
61 | - Greek | |
61 | 62 | - Indonesian |
62 | 63 | - Italian |
63 | 64 | - Japanese |
80 | 81 | |
81 | 82 | <!-- usage-start --> |
82 | 83 | |
84 | ## Installation | |
85 | ||
86 | ### From PyPI | |
87 | ||
88 | ```bash | |
89 | python3 -m pip install --upgrade humanize | |
90 | ``` | |
91 | ||
92 | ### From source | |
93 | ||
94 | ```bash | |
95 | git clone https://github.com/python-humanize/humanize | |
96 | cd humanize | |
97 | python3 -m pip install -e . | |
98 | ``` | |
99 | ||
83 | 100 | ## Usage |
84 | 101 | |
85 | 102 | ### Integer humanization |
242 | 259 | |
243 | 260 | How to add new phrases to existing locale files: |
244 | 261 | |
245 | ```console | |
246 | $ xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -l python src/humanize/*.py # extract new phrases | |
247 | $ msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files | |
262 | ```sh | |
263 | xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -l python src/humanize/*.py # extract new phrases | |
264 | msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files | |
248 | 265 | ``` |
249 | 266 | |
250 | 267 | How to add a new locale: |
251 | 268 | |
252 | ```console | |
253 | $ msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name> | |
269 | ```sh | |
270 | msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name> | |
254 | 271 | ``` |
255 | 272 | |
256 | 273 | Where `<locale name>` is a locale abbreviation, eg. `en_GB`, `pt_BR` or just `ru`, `fr` |
22 | 22 | - Finnish |
23 | 23 | - French |
24 | 24 | - German |
25 | - Greek | |
25 | 26 | - Indonesian |
26 | 27 | - Italian |
27 | 28 | - Japanese |
44 | 45 | |
45 | 46 | <!-- usage-start --> |
46 | 47 | |
48 | ## Installation | |
49 | ||
50 | ### From PyPI | |
51 | ||
52 | ```bash | |
53 | python3 -m pip install --upgrade humanize | |
54 | ``` | |
55 | ||
56 | ### From source | |
57 | ||
58 | ```bash | |
59 | git clone https://github.com/python-humanize/humanize | |
60 | cd humanize | |
61 | python3 -m pip install -e . | |
62 | ``` | |
63 | ||
47 | 64 | ## Usage |
48 | 65 | |
49 | 66 | ### Integer humanization |
206 | 223 | |
207 | 224 | How to add new phrases to existing locale files: |
208 | 225 | |
209 | ```console | |
210 | $ xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -l python src/humanize/*.py # extract new phrases | |
211 | $ msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files | |
226 | ```sh | |
227 | xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -l python src/humanize/*.py # extract new phrases | |
228 | msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files | |
212 | 229 | ``` |
213 | 230 | |
214 | 231 | How to add a new locale: |
215 | 232 | |
216 | ```console | |
217 | $ msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name> | |
233 | ```sh | |
234 | msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name> | |
218 | 235 | ``` |
219 | 236 | |
220 | 237 | Where `<locale name>` is a locale abbreviation, eg. `en_GB`, `pt_BR` or just `ru`, `fr` |
21 | 21 | pip install -U pip build keyring twine |
22 | 22 | rm -rf build dist |
23 | 23 | python -m build |
24 | twine check --strict dist/* && twine upload --repository-url https://test.pypi.org/legacy/ dist/* | |
24 | twine check --strict dist/* && twine upload --repository testpypi dist/* | |
25 | 25 | ``` |
26 | 26 | |
27 | 27 | - [ ] (Optional) Check **test** installation: |
44 | 44 | pip install -U pip build keyring twine |
45 | 45 | rm -rf build dist |
46 | 46 | python -m build |
47 | twine check --strict dist/* && twine upload -r pypi dist/* | |
47 | twine check --strict dist/* && twine upload --repository pypi dist/* | |
48 | 48 | ``` |
49 | 49 | |
50 | 50 | * [ ] Check installation: |
0 | mkdocs>=1.1 | |
0 | mkdocs==1.3.1 | |
1 | 1 | mkdocs-material |
2 | mkdocstrings[python]>=0.18 | |
2 | mkdocstrings[python]==0.19.0 | |
3 | 3 | mkdocs-include-markdown-plugin |
4 | 4 | pygments |
5 | pymdown-extensions>=9.2 | |
5 | pymdown-extensions==9.5 |
0 | 0 | """Main package for humanize.""" |
1 | 1 | |
2 | 2 | from humanize.filesize import naturalsize |
3 | from humanize.i18n import activate, deactivate, thousands_separator | |
3 | from humanize.i18n import activate, deactivate, decimal_separator, thousands_separator | |
4 | 4 | from humanize.number import ( |
5 | 5 | apnumber, |
6 | 6 | clamp, |
35 | 35 | "apnumber", |
36 | 36 | "clamp", |
37 | 37 | "deactivate", |
38 | "decimal_separator", | |
38 | 39 | "fractional", |
39 | 40 | "intcomma", |
40 | 41 | "intword", |
59 | 59 | |
60 | 60 | if abs_bytes == 1 and not gnu: |
61 | 61 | return "%d Byte" % bytes_ |
62 | elif abs_bytes < base and not gnu: | |
62 | ||
63 | if abs_bytes < base and not gnu: | |
63 | 64 | return "%d Bytes" % bytes_ |
64 | elif abs_bytes < base and gnu: | |
65 | ||
66 | if abs_bytes < base and gnu: | |
65 | 67 | return "%dB" % bytes_ |
66 | 68 | |
67 | 69 | for i, s in enumerate(suffix): |
68 | 70 | unit = base ** (i + 2) |
71 | ||
69 | 72 | if abs_bytes < unit and not gnu: |
70 | 73 | return (format + " %s") % ((base * bytes_ / unit), s) |
71 | elif abs_bytes < unit and gnu: | |
74 | ||
75 | if abs_bytes < unit and gnu: | |
72 | 76 | return (format + "%s") % ((base * bytes_ / unit), s) |
77 | ||
73 | 78 | if gnu: |
74 | 79 | return (format + "%s") % ((base * bytes_ / unit), s) |
75 | 80 | return (format + " %s") % ((base * bytes_ / unit), s) |
4 | 4 | import os.path |
5 | 5 | from threading import local |
6 | 6 | |
7 | __all__ = ["activate", "deactivate", "thousands_separator"] | |
7 | __all__ = ["activate", "deactivate", "decimal_separator", "thousands_separator"] | |
8 | 8 | |
9 | 9 | _TRANSLATIONS: dict[str | None, gettext_module.NullTranslations] = { |
10 | 10 | None: gettext_module.NullTranslations() |
14 | 14 | |
15 | 15 | # Mapping of locale to thousands separator |
16 | 16 | _THOUSANDS_SEPARATOR = { |
17 | "de_DE": ".", | |
17 | 18 | "fr_FR": " ", |
19 | } | |
20 | ||
21 | # Mapping of locale to decimal separator | |
22 | _DECIMAL_SEPARATOR = { | |
23 | "de_DE": ",", | |
18 | 24 | } |
19 | 25 | |
20 | 26 | |
171 | 177 | except (AttributeError, KeyError): |
172 | 178 | sep = "," |
173 | 179 | return sep |
180 | ||
181 | ||
182 | def decimal_separator() -> str: | |
183 | """Return the decimal separator for a locale, default to dot. | |
184 | ||
185 | Returns: | |
186 | str: Decimal separator. | |
187 | """ | |
188 | try: | |
189 | sep = _DECIMAL_SEPARATOR[_CURRENT.locale] | |
190 | except (AttributeError, KeyError): | |
191 | sep = "." | |
192 | return sep |
Binary diff not shown
0 | # Greek translations for PACKAGE package. | |
1 | # Copyright (C) 2022 THE PACKAGE'S COPYRIGHT HOLDER | |
2 | # This file is distributed under the same license as the PACKAGE package. | |
3 | # Isaak Tsalicoglou <isaak@waseigo.com>, 2022. | |
4 | # | |
5 | msgid "" | |
6 | msgstr "" | |
7 | "Project-Id-Version: humanize\n" | |
8 | "Report-Msgid-Bugs-To: \n" | |
9 | "POT-Creation-Date: 2022-08-05 01:06+0300\n" | |
10 | "PO-Revision-Date: 2022-08-05 01:09+0300\n" | |
11 | "Last-Translator: Isaak Tsalicoglou <isaak@waseigo.com>\n" | |
12 | "Language-Team: Greek <team@lists.gnome.gr>\n" | |
13 | "Language: el\n" | |
14 | "MIME-Version: 1.0\n" | |
15 | "Content-Type: text/plain; charset=utf-8\n" | |
16 | "Content-Transfer-Encoding: 8bit\n" | |
17 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" | |
18 | "Generated-By: Isaak Tsalicoglou\n" | |
19 | "X-Generator: Mousepad 0.5.9\n" | |
20 | ||
21 | #: src/humanize/number.py:71 | |
22 | msgctxt "0 (male)" | |
23 | msgid "ος" | |
24 | msgstr "." | |
25 | ||
26 | #: src/humanize/number.py:72 | |
27 | msgctxt "1 (male)" | |
28 | msgid "ος" | |
29 | msgstr "." | |
30 | ||
31 | #: src/humanize/number.py:73 | |
32 | msgctxt "2 (male)" | |
33 | msgid "ος" | |
34 | msgstr "." | |
35 | ||
36 | #: src/humanize/number.py:74 | |
37 | msgctxt "3 (male)" | |
38 | msgid "ος" | |
39 | msgstr "." | |
40 | ||
41 | #: src/humanize/number.py:75 | |
42 | msgctxt "4 (male)" | |
43 | msgid "ος" | |
44 | msgstr "." | |
45 | ||
46 | #: src/humanize/number.py:76 | |
47 | msgctxt "5 (male)" | |
48 | msgid "ος" | |
49 | msgstr "." | |
50 | ||
51 | #: src/humanize/number.py:77 | |
52 | msgctxt "6 (male)" | |
53 | msgid "ος" | |
54 | msgstr "." | |
55 | ||
56 | #: src/humanize/number.py:78 | |
57 | msgctxt "7 (male)" | |
58 | msgid "ος" | |
59 | msgstr "." | |
60 | ||
61 | #: src/humanize/number.py:79 | |
62 | msgctxt "8 (male)" | |
63 | msgid "ος" | |
64 | msgstr "." | |
65 | ||
66 | #: src/humanize/number.py:80 | |
67 | msgctxt "9 (male)" | |
68 | msgid "ος" | |
69 | msgstr "." | |
70 | ||
71 | #: src/humanize/number.py:84 | |
72 | msgctxt "0 (female)" | |
73 | msgid "η" | |
74 | msgstr "." | |
75 | ||
76 | #: src/humanize/number.py:85 | |
77 | msgctxt "1 (female)" | |
78 | msgid "η" | |
79 | msgstr "." | |
80 | ||
81 | #: src/humanize/number.py:86 | |
82 | msgctxt "2 (female)" | |
83 | msgid "η" | |
84 | msgstr "." | |
85 | ||
86 | #: src/humanize/number.py:87 | |
87 | msgctxt "3 (female)" | |
88 | msgid "η" | |
89 | msgstr "." | |
90 | ||
91 | #: src/humanize/number.py:88 | |
92 | msgctxt "4 (female)" | |
93 | msgid "η" | |
94 | msgstr "." | |
95 | ||
96 | #: src/humanize/number.py:89 | |
97 | msgctxt "5 (female)" | |
98 | msgid "η" | |
99 | msgstr "." | |
100 | ||
101 | #: src/humanize/number.py:90 | |
102 | msgctxt "6 (female)" | |
103 | msgid "η" | |
104 | msgstr "." | |
105 | ||
106 | #: src/humanize/number.py:91 | |
107 | msgctxt "7 (female)" | |
108 | msgid "η" | |
109 | msgstr "." | |
110 | ||
111 | #: src/humanize/number.py:92 | |
112 | msgctxt "8 (female)" | |
113 | msgid "η" | |
114 | msgstr "." | |
115 | ||
116 | #: src/humanize/number.py:93 | |
117 | msgctxt "9 (female)" | |
118 | msgid "η" | |
119 | msgstr "." | |
120 | ||
121 | #: src/humanize/number.py:140 | |
122 | msgid "thousand" | |
123 | msgid_plural "thousand" | |
124 | msgstr[0] "χιλιάδα" | |
125 | msgstr[1] "χιλιάδες" | |
126 | ||
127 | #: src/humanize/number.py:141 | |
128 | msgid "million" | |
129 | msgid_plural "million" | |
130 | msgstr[0] "εκατομμύριο" | |
131 | msgstr[1] "εκατομμύρια" | |
132 | ||
133 | #: src/humanize/number.py:142 | |
134 | msgid "billion" | |
135 | msgid_plural "billion" | |
136 | msgstr[0] "δισεκατομμύριο" | |
137 | msgstr[1] "δισεκατομμύρια" | |
138 | ||
139 | #: src/humanize/number.py:143 | |
140 | msgid "trillion" | |
141 | msgid_plural "trillion" | |
142 | msgstr[0] "τρισεκατομμύριο" | |
143 | msgstr[1] "τρισεκατομμύρια" | |
144 | ||
145 | #: src/humanize/number.py:144 | |
146 | msgid "quadrillion" | |
147 | msgid_plural "quadrillion" | |
148 | msgstr[0] "τετράκις εκατομμύριο" | |
149 | msgstr[1] "τετράκις εκατομμύρια" | |
150 | ||
151 | #: src/humanize/number.py:145 | |
152 | msgid "quintillion" | |
153 | msgid_plural "quintillion" | |
154 | msgstr[0] "πεντάκις εκατομμύριο" | |
155 | msgstr[1] "πεντάκις εκατομμύρια" | |
156 | ||
157 | #: src/humanize/number.py:146 | |
158 | msgid "sextillion" | |
159 | msgid_plural "sextillion" | |
160 | msgstr[0] "εξάκις εκατομμύριο" | |
161 | msgstr[1] "εξάκις εκατομμύρια" | |
162 | ||
163 | #: src/humanize/number.py:147 | |
164 | msgid "septillion" | |
165 | msgid_plural "septillion" | |
166 | msgstr[0] "επτάκις εκατομμύριο" | |
167 | msgstr[1] "επτάκις εκατομμύρια" | |
168 | ||
169 | #: src/humanize/number.py:148 | |
170 | msgid "octillion" | |
171 | msgid_plural "octillion" | |
172 | msgstr[0] "οκτάκις εκατομμύριο" | |
173 | msgstr[1] "οκτάκις εκατομμύρια" | |
174 | ||
175 | #: src/humanize/number.py:149 | |
176 | msgid "nonillion" | |
177 | msgid_plural "nonillion" | |
178 | msgstr[0] "εννεάκις εκατομμύριο" | |
179 | msgstr[1] "εννεάκις εκατομμύρια" | |
180 | ||
181 | #: src/humanize/number.py:150 | |
182 | msgid "decillion" | |
183 | msgid_plural "decillion" | |
184 | msgstr[0] "δεκάκις εκατομμύριο" | |
185 | msgstr[1] "δεκάκις εκατομμύρια" | |
186 | ||
187 | #: src/humanize/number.py:151 | |
188 | msgid "googol" | |
189 | msgid_plural "googol" | |
190 | msgstr[0] "δέκα τριακονταδυάκις εκατομμύριο" | |
191 | msgstr[1] "δέκα τριακονταδυάκις εκατομμύρια" | |
192 | ||
193 | #: src/humanize/number.py:246 | |
194 | msgid "zero" | |
195 | msgstr "μηδέν" | |
196 | ||
197 | #: src/humanize/number.py:275 | |
198 | msgid "one" | |
199 | msgstr "ένα" | |
200 | ||
201 | #: src/humanize/number.py:276 | |
202 | msgid "two" | |
203 | msgstr "δύο" | |
204 | ||
205 | #: src/humanize/number.py:277 | |
206 | msgid "three" | |
207 | msgstr "τρία" | |
208 | ||
209 | #: src/humanize/number.py:278 | |
210 | msgid "four" | |
211 | msgstr "τέσσερα" | |
212 | ||
213 | #: src/humanize/number.py:279 | |
214 | msgid "five" | |
215 | msgstr "πέντε" | |
216 | ||
217 | #: src/humanize/number.py:280 | |
218 | msgid "six" | |
219 | msgstr "έξι" | |
220 | ||
221 | #: src/humanize/number.py:281 | |
222 | msgid "seven" | |
223 | msgstr "επτά" | |
224 | ||
225 | #: src/humanize/number.py:254 | |
226 | msgid "eight" | |
227 | msgstr "οκτώ" | |
228 | ||
229 | #: src/humanize/number.py:255 | |
230 | msgid "nine" | |
231 | msgstr "εννέα" | |
232 | ||
233 | #: src/humanize/time.py:133 | |
234 | #, fuzzy, python-format | |
235 | msgid "%d microsecond" | |
236 | msgid_plural "%d microseconds" | |
237 | msgstr[0] "%d εκατομμυριοστό του δευτερολέπτου" | |
238 | msgstr[1] "%d εκατομμυριοστά του δευτερολέπτου" | |
239 | ||
240 | #: src/humanize/time.py:142 | |
241 | #, fuzzy, python-format | |
242 | msgid "%d millisecond" | |
243 | msgid_plural "%d milliseconds" | |
244 | msgstr[0] "%d χιλιοστό του δευτερολέπτου" | |
245 | msgstr[1] "%d χιλιοστά του δευτερολέπτου" | |
246 | ||
247 | #: src/humanize/time.py:145 src/humanize/time.py:220 | |
248 | msgid "a moment" | |
249 | msgstr "μια στιγμή" | |
250 | ||
251 | #: src/humanize/time.py:147 | |
252 | msgid "a second" | |
253 | msgstr "ένα δευτερόλεπτο" | |
254 | ||
255 | #: src/humanize/time.py:149 | |
256 | #, python-format | |
257 | msgid "%d second" | |
258 | msgid_plural "%d seconds" | |
259 | msgstr[0] "%d δευτερόλεπτο" | |
260 | msgstr[1] "%d δευτερόλεπτα" | |
261 | ||
262 | #: src/humanize/time.py:151 | |
263 | msgid "a minute" | |
264 | msgstr "ένα λεπτό" | |
265 | ||
266 | #: src/humanize/time.py:154 | |
267 | #, python-format | |
268 | msgid "%d minute" | |
269 | msgid_plural "%d minutes" | |
270 | msgstr[0] "%d λεπτό" | |
271 | msgstr[1] "%d λεπτά" | |
272 | ||
273 | #: src/humanize/time.py:156 | |
274 | msgid "an hour" | |
275 | msgstr "μία ώρα" | |
276 | ||
277 | #: src/humanize/time.py:159 | |
278 | #, python-format | |
279 | msgid "%d hour" | |
280 | msgid_plural "%d hours" | |
281 | msgstr[0] "%d ώρα" | |
282 | msgstr[1] "%d ώρες" | |
283 | ||
284 | #: src/humanize/time.py:162 | |
285 | msgid "a day" | |
286 | msgstr "μία ημέρα" | |
287 | ||
288 | #: src/humanize/time.py:164 src/humanize/time.py:167 | |
289 | #, python-format | |
290 | msgid "%d day" | |
291 | msgid_plural "%d days" | |
292 | msgstr[0] "%d ημέρα" | |
293 | msgstr[1] "%d ημέρες" | |
294 | ||
295 | #: src/humanize/time.py:169 | |
296 | msgid "a month" | |
297 | msgstr "ένα μήνα" | |
298 | ||
299 | #: src/humanize/time.py:171 | |
300 | #, python-format | |
301 | msgid "%d month" | |
302 | msgid_plural "%d months" | |
303 | msgstr[0] "%d μήνα" | |
304 | msgstr[1] "%d μήνες" | |
305 | ||
306 | #: src/humanize/time.py:174 | |
307 | msgid "a year" | |
308 | msgstr "ένα έτος" | |
309 | ||
310 | #: src/humanize/time.py:176 src/humanize/time.py:185 | |
311 | #, python-format | |
312 | msgid "1 year, %d day" | |
313 | msgid_plural "1 year, %d days" | |
314 | msgstr[0] "ένα έτος και %d ημέρα" | |
315 | msgstr[1] "ένα έτος και %d ημέρες" | |
316 | ||
317 | #: src/humanize/time.py:179 | |
318 | msgid "1 year, 1 month" | |
319 | msgstr "ένα έτος και ένα μήνα" | |
320 | ||
321 | #: src/humanize/time.py:182 | |
322 | #, python-format | |
323 | msgid "1 year, %d month" | |
324 | msgid_plural "1 year, %d months" | |
325 | msgstr[0] "ένα έτος και %d μήνα" | |
326 | msgstr[1] "ένα έτος και %d μήνες" | |
327 | ||
328 | #: src/humanize/time.py:187 | |
329 | #, python-format | |
330 | msgid "%d year" | |
331 | msgid_plural "%d years" | |
332 | msgstr[0] "%d έτος" | |
333 | msgstr[1] "%d έτη" | |
334 | ||
335 | #: src/humanize/time.py:217 | |
336 | #, python-format | |
337 | msgid "%s from now" | |
338 | msgstr "σε %s από τώρα" | |
339 | ||
340 | #: src/humanize/time.py:242 | |
341 | #, python-format | |
342 | msgid "%s ago" | |
343 | msgstr "πριν από %s" | |
344 | ||
345 | #: src/humanize/time.py:246 | |
346 | msgid "now" | |
347 | msgstr "τώρα" | |
348 | ||
349 | #: src/humanize/time.py:269 | |
350 | msgid "today" | |
351 | msgstr "σήμερα" | |
352 | ||
353 | #: src/humanize/time.py:271 | |
354 | msgid "tomorrow" | |
355 | msgstr "αύριο" | |
356 | ||
357 | #: src/humanize/time.py:273 | |
358 | msgid "yesterday" | |
359 | msgstr "χθες" | |
360 | ||
361 | #: src/humanize/time.py:581 | |
362 | #, python-format | |
363 | msgid "%s and %s" | |
364 | msgstr "%s και %s" |
Binary diff not shown
2 | 2 | # This file is distributed under the same license as the PACKAGE package. |
3 | 3 | # Bartosz Bubak <bartosz.bubak@gmail.com>, 2020. |
4 | 4 | # Added missing strings by Krystian Postek <krystian postek eu>, 2020. |
5 | # Replace short scale with long scale by Maciej J. Mikulski (mjmikulski), 2022. | |
5 | 6 | # |
6 | 7 | msgid "" |
7 | 8 | msgstr "" |
121 | 122 | #: src/humanize/number.py:140 |
122 | 123 | msgid "thousand" |
123 | 124 | msgid_plural "thousand" |
124 | msgstr[0] "" | |
125 | msgstr[1] "" | |
126 | msgstr[2] "" | |
125 | msgstr[0] "tysiąc" | |
126 | msgstr[1] "tysiąc" | |
127 | msgstr[2] "tysięcy" | |
127 | 128 | |
128 | 129 | #: src/humanize/number.py:141 |
129 | 130 | msgid "million" |
130 | 131 | msgid_plural "million" |
131 | 132 | msgstr[0] "milion" |
132 | msgstr[1] "milion" | |
133 | msgstr[2] "milion" | |
133 | msgstr[1] "miliony" | |
134 | msgstr[2] "milionów" | |
134 | 135 | |
135 | 136 | #: src/humanize/number.py:142 |
136 | 137 | msgid "billion" |
137 | 138 | msgid_plural "billion" |
138 | msgstr[0] "bilion" | |
139 | msgstr[1] "bilion" | |
140 | msgstr[2] "bilion" | |
139 | msgstr[0] "miliard" | |
140 | msgstr[1] "miliardy" | |
141 | msgstr[2] "miliardów" | |
141 | 142 | |
142 | 143 | #: src/humanize/number.py:143 |
143 | 144 | msgid "trillion" |
144 | 145 | msgid_plural "trillion" |
145 | msgstr[0] "trylion" | |
146 | msgstr[1] "trylion" | |
147 | msgstr[2] "trylion" | |
146 | msgstr[0] "bilion" | |
147 | msgstr[1] "biliony" | |
148 | msgstr[2] "bilionów" | |
148 | 149 | |
149 | 150 | #: src/humanize/number.py:144 |
150 | 151 | msgid "quadrillion" |
151 | 152 | msgid_plural "quadrillion" |
152 | msgstr[0] "kwadrylion" | |
153 | msgstr[1] "kwadrylion" | |
154 | msgstr[2] "kwadrylion" | |
153 | msgstr[0] "biliard" | |
154 | msgstr[1] "biliardy" | |
155 | msgstr[2] "biliardów" | |
155 | 156 | |
156 | 157 | #: src/humanize/number.py:145 |
157 | 158 | msgid "quintillion" |
158 | 159 | msgid_plural "quintillion" |
159 | msgstr[0] "kwintylion" | |
160 | msgstr[1] "kwintylion" | |
161 | msgstr[2] "kwintylion" | |
160 | msgstr[0] "trylion" | |
161 | msgstr[1] "tryliony" | |
162 | msgstr[2] "trylionów" | |
162 | 163 | |
163 | 164 | #: src/humanize/number.py:146 |
164 | 165 | msgid "sextillion" |
165 | 166 | msgid_plural "sextillion" |
166 | msgstr[0] "sekstylion" | |
167 | msgstr[1] "sekstylion" | |
168 | msgstr[2] "sekstylion" | |
167 | msgstr[0] "tryliard" | |
168 | msgstr[1] "tryliard" | |
169 | msgstr[2] "tryliard" | |
169 | 170 | |
170 | 171 | #: src/humanize/number.py:147 |
171 | 172 | msgid "septillion" |
172 | 173 | msgid_plural "septillion" |
173 | msgstr[0] "septylion" | |
174 | msgstr[1] "septylion" | |
175 | msgstr[2] "septylion" | |
174 | msgstr[0] "kwadrylion" | |
175 | msgstr[1] "kwadryliony" | |
176 | msgstr[2] "kwadrylionów" | |
176 | 177 | |
177 | 178 | #: src/humanize/number.py:148 |
178 | 179 | msgid "octillion" |
179 | 180 | msgid_plural "octillion" |
180 | msgstr[0] "oktylion" | |
181 | msgstr[1] "oktylion" | |
182 | msgstr[2] "oktylion" | |
181 | msgstr[0] "kwadryliard" | |
182 | msgstr[1] "kwadryliardy" | |
183 | msgstr[2] "kwadryliardów" | |
183 | 184 | |
184 | 185 | #: src/humanize/number.py:149 |
185 | 186 | msgid "nonillion" |
186 | 187 | msgid_plural "nonillion" |
187 | msgstr[0] "nonilion" | |
188 | msgstr[1] "nonilion" | |
189 | msgstr[2] "nonilion" | |
188 | msgstr[0] "kwintylion" | |
189 | msgstr[1] "kwintyliony" | |
190 | msgstr[2] "kwintylionów" | |
190 | 191 | |
191 | 192 | #: src/humanize/number.py:150 |
192 | 193 | msgid "decillion" |
193 | 194 | msgid_plural "decillion" |
194 | msgstr[0] "decylion" | |
195 | msgstr[1] "decylion" | |
196 | msgstr[2] "decylion" | |
195 | msgstr[0] "kwintyliard" | |
196 | msgstr[1] "kwintyliardy" | |
197 | msgstr[2] "kwintyliardów" | |
197 | 198 | |
198 | 199 | #: src/humanize/number.py:151 |
199 | 200 | msgid "googol" |
200 | 201 | msgid_plural "googol" |
201 | 202 | msgstr[0] "googol" |
202 | msgstr[1] "googol" | |
203 | msgstr[2] "googol" | |
203 | msgstr[1] "googole" | |
204 | msgstr[2] "googoli" | |
204 | 205 | |
205 | 206 | #: src/humanize/number.py:246 |
206 | 207 | msgid "zero" |
351 | 352 | msgid "%d year" |
352 | 353 | msgid_plural "%d years" |
353 | 354 | msgstr[0] "%d rok" |
354 | msgstr[1] "%d lat" | |
355 | msgstr[2] "%d lata" | |
355 | msgstr[1] "%d lata" | |
356 | msgstr[2] "%d lat" | |
356 | 357 | |
357 | 358 | #: src/humanize/time.py:217 |
358 | 359 | #, python-format |
12 | 12 | from .i18n import _ngettext |
13 | 13 | from .i18n import _ngettext_noop as NS_ |
14 | 14 | from .i18n import _pgettext as P_ |
15 | from .i18n import thousands_separator | |
15 | from .i18n import decimal_separator, thousands_separator | |
16 | 16 | |
17 | 17 | if TYPE_CHECKING: |
18 | 18 | if sys.version_info >= (3, 10): |
116 | 116 | '1,234.55' |
117 | 117 | >>> intcomma(14308.40, 1) |
118 | 118 | '14,308.4' |
119 | >>> intcomma("14308.40", 1) | |
120 | '14,308.4' | |
119 | 121 | >>> intcomma(None) |
120 | 122 | 'None' |
121 | 123 | |
127 | 129 | Returns: |
128 | 130 | str: String containing commas every three digits. |
129 | 131 | """ |
130 | sep = thousands_separator() | |
132 | thousands_sep = thousands_separator() | |
133 | decimal_sep = decimal_separator() | |
131 | 134 | try: |
132 | 135 | if isinstance(value, str): |
133 | float(value.replace(sep, "")) | |
136 | value = value.replace(thousands_sep, "").replace(decimal_sep, ".") | |
137 | if "." in value: | |
138 | value = float(value) | |
139 | else: | |
140 | value = int(value) | |
134 | 141 | else: |
135 | 142 | float(value) |
136 | 143 | except (TypeError, ValueError): |
140 | 147 | orig = "{0:.{1}f}".format(value, ndigits) |
141 | 148 | else: |
142 | 149 | orig = str(value) |
143 | ||
144 | new = re.sub(r"^(-?\d+)(\d{3})", rf"\g<1>{sep}\g<2>", orig) | |
145 | if orig == new: | |
146 | return new | |
147 | else: | |
148 | return intcomma(new) | |
150 | orig = orig.replace(".", decimal_sep) | |
151 | while True: | |
152 | new = re.sub(r"^(-?\d+)(\d{3})", rf"\g<1>{thousands_sep}\g<2>", orig) | |
153 | if orig == new: | |
154 | return new | |
155 | orig = new | |
149 | 156 | |
150 | 157 | |
151 | 158 | powers = [10**x for x in (3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 100)] |
204 | 211 | except (TypeError, ValueError): |
205 | 212 | return str(value) |
206 | 213 | |
214 | if value < 0: | |
215 | value *= -1 | |
216 | negative_prefix = "-" | |
217 | else: | |
218 | negative_prefix = "" | |
219 | ||
207 | 220 | if value < powers[0]: |
208 | return str(value) | |
209 | for ordinal, power in enumerate(powers[1:], 1): | |
221 | return negative_prefix + str(value) | |
222 | ||
223 | for ordinal_, power in enumerate(powers[1:], 1): | |
210 | 224 | if value < power: |
211 | chopped = value / float(powers[ordinal - 1]) | |
225 | chopped = value / float(powers[ordinal_ - 1]) | |
212 | 226 | if float(format % chopped) == float(10**3): |
213 | chopped = value / float(powers[ordinal]) | |
214 | singular, plural = human_powers[ordinal] | |
227 | chopped = value / float(powers[ordinal_]) | |
228 | singular, plural = human_powers[ordinal_] | |
215 | 229 | return ( |
216 | " ".join([format, _ngettext(singular, plural, math.ceil(chopped))]) | |
230 | negative_prefix | |
231 | + " ".join( | |
232 | [format, _ngettext(singular, plural, math.ceil(chopped))] | |
233 | ) | |
217 | 234 | ) % chopped |
218 | else: | |
219 | singular, plural = human_powers[ordinal - 1] | |
220 | return ( | |
221 | " ".join([format, _ngettext(singular, plural, math.ceil(chopped))]) | |
222 | ) % chopped | |
223 | return str(value) | |
235 | ||
236 | singular, plural = human_powers[ordinal_ - 1] | |
237 | return ( | |
238 | negative_prefix | |
239 | + " ".join([format, _ngettext(singular, plural, math.ceil(chopped))]) | |
240 | ) % chopped | |
241 | ||
242 | return negative_prefix + str(value) | |
224 | 243 | |
225 | 244 | |
226 | 245 | def apnumber(value: NumberOrString) -> str: |
320 | 339 | # this means that an integer was passed in |
321 | 340 | # (or variants of that integer like 1.0000) |
322 | 341 | return f"{whole_number:.0f}" |
323 | elif not whole_number: | |
342 | ||
343 | if not whole_number: | |
324 | 344 | return f"{numerator:.0f}/{denominator:.0f}" |
325 | else: | |
326 | return f"{whole_number:.0f} {numerator:.0f}/{denominator:.0f}" | |
345 | ||
346 | return f"{whole_number:.0f} {numerator:.0f}/{denominator:.0f}" | |
327 | 347 | |
328 | 348 | |
329 | 349 | def scientific(value: NumberOrString, precision: int = 2) -> str: |
450 | 470 | |
451 | 471 | if isinstance(format, str): |
452 | 472 | return token + format.format(value) |
453 | elif callable(format): | |
473 | ||
474 | if callable(format): | |
454 | 475 | return token + format(value) |
455 | else: | |
456 | raise ValueError( | |
457 | "Invalid format. Must be either a valid formatting string, or a function " | |
458 | "that accepts value and returns a string." | |
459 | ) | |
476 | ||
477 | raise ValueError( | |
478 | "Invalid format. Must be either a valid formatting string, or a function " | |
479 | "that accepts value and returns a string." | |
480 | ) | |
460 | 481 | |
461 | 482 | |
462 | 483 | def metric(value: float, unit: str = "", precision: int = 3) -> str: |
494 | 515 | Returns: |
495 | 516 | str: |
496 | 517 | """ |
497 | exponent = int(math.floor(math.log10(abs(value)))) | |
518 | exponent = int(math.floor(math.log10(abs(value)))) if value != 0 else 0 | |
498 | 519 | |
499 | 520 | if exponent >= 27 or exponent < -24: |
500 | 521 | return scientific(value, precision - 1) + unit |
501 | 522 | |
502 | 523 | value /= 10 ** (exponent // 3 * 3) |
503 | 524 | if exponent >= 3: |
504 | ordinal = "kMGTPEZY"[exponent // 3 - 1] | |
525 | ordinal_ = "kMGTPEZY"[exponent // 3 - 1] | |
505 | 526 | elif exponent < 0: |
506 | ordinal = "mμnpfazy"[(-exponent - 1) // 3] | |
507 | else: | |
508 | ordinal = "" | |
527 | ordinal_ = "mμnpfazy"[(-exponent - 1) // 3] | |
528 | else: | |
529 | ordinal_ = "" | |
509 | 530 | value_ = format(value, ".%if" % (precision - (exponent % 3) - 1)) |
510 | if not (unit or ordinal) or unit in ("°", "′", "″"): | |
531 | if not (unit or ordinal_) or unit in ("°", "′", "″"): | |
511 | 532 | space = "" |
512 | 533 | else: |
513 | 534 | space = " " |
514 | 535 | |
515 | return f"{value_}{space}{ordinal}{unit}" | |
536 | return f"{value_}{space}{ordinal_}{unit}" |
150 | 150 | _ngettext("%d microsecond", "%d microseconds", delta.microseconds) |
151 | 151 | % delta.microseconds |
152 | 152 | ) |
153 | elif min_unit == Unit.MILLISECONDS or ( | |
153 | ||
154 | if min_unit == Unit.MILLISECONDS or ( | |
154 | 155 | min_unit == Unit.MICROSECONDS and 1000 <= delta.microseconds < 1_000_000 |
155 | 156 | ): |
156 | 157 | milliseconds = delta.microseconds / 1000 |
159 | 160 | % milliseconds |
160 | 161 | ) |
161 | 162 | return _("a moment") |
162 | elif seconds == 1: | |
163 | ||
164 | if seconds == 1: | |
163 | 165 | return _("a second") |
164 | elif seconds < 60: | |
166 | ||
167 | if seconds < 60: | |
165 | 168 | return _ngettext("%d second", "%d seconds", seconds) % seconds |
166 | elif 60 <= seconds < 120: | |
169 | ||
170 | if 60 <= seconds < 120: | |
167 | 171 | return _("a minute") |
168 | elif 120 <= seconds < 3600: | |
172 | ||
173 | if 120 <= seconds < 3600: | |
169 | 174 | minutes = seconds // 60 |
170 | 175 | return _ngettext("%d minute", "%d minutes", minutes) % minutes |
171 | elif 3600 <= seconds < 3600 * 2: | |
176 | ||
177 | if 3600 <= seconds < 3600 * 2: | |
172 | 178 | return _("an hour") |
173 | elif 3600 < seconds: | |
179 | ||
180 | if 3600 < seconds: | |
174 | 181 | hours = seconds // 3600 |
175 | 182 | return _ngettext("%d hour", "%d hours", hours) % hours |
183 | ||
176 | 184 | elif years == 0: |
177 | 185 | if days == 1: |
178 | 186 | return _("a day") |
187 | ||
179 | 188 | if not use_months: |
180 | 189 | return _ngettext("%d day", "%d days", days) % days |
181 | else: | |
182 | if not num_months: | |
183 | return _ngettext("%d day", "%d days", days) % days | |
184 | elif num_months == 1: | |
185 | return _("a month") | |
186 | else: | |
187 | return _ngettext("%d month", "%d months", num_months) % num_months | |
190 | ||
191 | if not num_months: | |
192 | return _ngettext("%d day", "%d days", days) % days | |
193 | ||
194 | if num_months == 1: | |
195 | return _("a month") | |
196 | ||
197 | return _ngettext("%d month", "%d months", num_months) % num_months | |
198 | ||
188 | 199 | elif years == 1: |
189 | 200 | if not num_months and not days: |
190 | 201 | return _("a year") |
191 | elif not num_months: | |
202 | ||
203 | if not num_months: | |
192 | 204 | return _ngettext("1 year, %d day", "1 year, %d days", days) % days |
193 | elif use_months: | |
205 | ||
206 | if use_months: | |
194 | 207 | if num_months == 1: |
195 | 208 | return _("1 year, 1 month") |
196 | else: | |
197 | return ( | |
198 | _ngettext("1 year, %d month", "1 year, %d months", num_months) | |
199 | % num_months | |
200 | ) | |
201 | else: | |
202 | return _ngettext("1 year, %d day", "1 year, %d days", days) % days | |
209 | ||
210 | return ( | |
211 | _ngettext("1 year, %d month", "1 year, %d months", num_months) | |
212 | % num_months | |
213 | ) | |
214 | ||
215 | return _ngettext("1 year, %d day", "1 year, %d days", days) % days | |
203 | 216 | |
204 | 217 | return _ngettext("%d year", "%d years", years).replace("%d", "%s") % intcomma(years) |
205 | 218 | |
264 | 277 | # Date arguments out of range |
265 | 278 | return str(value) |
266 | 279 | delta = value - dt.date.today() |
280 | ||
267 | 281 | if delta.days == 0: |
268 | 282 | return _("today") |
269 | elif delta.days == 1: | |
283 | ||
284 | if delta.days == 1: | |
270 | 285 | return _("tomorrow") |
271 | elif delta.days == -1: | |
286 | ||
287 | if delta.days == -1: | |
272 | 288 | return _("yesterday") |
289 | ||
273 | 290 | return value.strftime(format) |
274 | 291 | |
275 | 292 | |
322 | 339 | """ |
323 | 340 | if unit == minimum_unit: |
324 | 341 | return value / divisor, 0 |
325 | elif unit in suppress: | |
342 | ||
343 | if unit in suppress: | |
326 | 344 | return 0, value |
327 | else: | |
328 | return divmod(value, divisor) | |
345 | ||
346 | return divmod(value, divisor) | |
329 | 347 | |
330 | 348 | |
331 | 349 | def _carry( |
360 | 378 | """ |
361 | 379 | if unit == min_unit: |
362 | 380 | return value1 + value2 / ratio, 0 |
363 | elif unit in suppress: | |
381 | ||
382 | if unit in suppress: | |
364 | 383 | return 0, value2 + value1 * ratio |
365 | else: | |
366 | return value1, value2 | |
384 | ||
385 | return value1, value2 | |
367 | 386 | |
368 | 387 | |
369 | 388 | def _suitable_minimum_unit(min_unit: Unit, suppress: typing.Iterable[Unit]) -> Unit: |
375 | 394 | >>> _suitable_minimum_unit(Unit.HOURS, []).name |
376 | 395 | 'HOURS' |
377 | 396 | |
378 | But if suppressed, find a unit greather than the original one that is not | |
397 | But if suppressed, find a unit greater than the original one that is not | |
379 | 398 | suppressed: |
380 | 399 | |
381 | 400 | >>> _suitable_minimum_unit(Unit.HOURS, [Unit.HOURS]).name |
404 | 423 | ['MICROSECONDS', 'MILLISECONDS', 'DAYS'] |
405 | 424 | """ |
406 | 425 | suppress = set(suppress) |
407 | for u in Unit: | |
408 | if u == min_unit: | |
426 | for unit in Unit: | |
427 | if unit == min_unit: | |
409 | 428 | break |
410 | suppress.add(u) | |
429 | suppress.add(unit) | |
411 | 430 | |
412 | 431 | return suppress |
413 | 432 | |
414 | 433 | |
415 | 434 | def precisedelta( |
416 | value: dt.timedelta | int, | |
435 | value: dt.timedelta | int | None, | |
417 | 436 | minimum_unit: str = "seconds", |
418 | 437 | suppress: typing.Iterable[str] = (), |
419 | 438 | format: str = "%0.2f", |
0 | 0 | Metadata-Version: 2.1 |
1 | 1 | Name: humanize |
2 | Version: 4.2.3 | |
2 | Version: 4.4.0 | |
3 | 3 | Summary: Python humanize utilities |
4 | 4 | Home-page: https://github.com/python-humanize/humanize |
5 | 5 | Author: Jason Moiron |
58 | 58 | - Finnish |
59 | 59 | - French |
60 | 60 | - German |
61 | - Greek | |
61 | 62 | - Indonesian |
62 | 63 | - Italian |
63 | 64 | - Japanese |
80 | 81 | |
81 | 82 | <!-- usage-start --> |
82 | 83 | |
84 | ## Installation | |
85 | ||
86 | ### From PyPI | |
87 | ||
88 | ```bash | |
89 | python3 -m pip install --upgrade humanize | |
90 | ``` | |
91 | ||
92 | ### From source | |
93 | ||
94 | ```bash | |
95 | git clone https://github.com/python-humanize/humanize | |
96 | cd humanize | |
97 | python3 -m pip install -e . | |
98 | ``` | |
99 | ||
83 | 100 | ## Usage |
84 | 101 | |
85 | 102 | ### Integer humanization |
242 | 259 | |
243 | 260 | How to add new phrases to existing locale files: |
244 | 261 | |
245 | ```console | |
246 | $ xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -l python src/humanize/*.py # extract new phrases | |
247 | $ msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files | |
262 | ```sh | |
263 | xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -l python src/humanize/*.py # extract new phrases | |
264 | msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files | |
248 | 265 | ``` |
249 | 266 | |
250 | 267 | How to add a new locale: |
251 | 268 | |
252 | ```console | |
253 | $ msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name> | |
269 | ```sh | |
270 | msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name> | |
254 | 271 | ``` |
255 | 272 | |
256 | 273 | Where `<locale name>` is a locale abbreviation, eg. `en_GB`, `pt_BR` or just `ru`, `fr` |
10 | 10 | setup.py |
11 | 11 | tox.ini |
12 | 12 | .github/CONTRIBUTING.md |
13 | .github/FUNDING.md | |
13 | .github/FUNDING.yml | |
14 | 14 | .github/ISSUE_TEMPLATE.md |
15 | 15 | .github/PULL_REQUEST_TEMPLATE.md |
16 | 16 | .github/SECURITY.md |
17 | .github/dependabot.yml | |
18 | 17 | .github/labels.yml |
19 | 18 | .github/release-drafter.yml |
19 | .github/renovate.json | |
20 | 20 | .github/workflows/docs.yml |
21 | 21 | .github/workflows/labels.yml |
22 | 22 | .github/workflows/lint.yml |
54 | 54 | src/humanize/locale/da_DK/LC_MESSAGES/humanize.po |
55 | 55 | src/humanize/locale/de_DE/LC_MESSAGES/humanize.mo |
56 | 56 | src/humanize/locale/de_DE/LC_MESSAGES/humanize.po |
57 | src/humanize/locale/el_GR/LC_MESSAGES/humanize.mo | |
58 | src/humanize/locale/el_GR/LC_MESSAGES/humanize.po | |
57 | 59 | src/humanize/locale/es_ES/LC_MESSAGES/humanize.mo |
58 | 60 | src/humanize/locale/es_ES/LC_MESSAGES/humanize.po |
59 | 61 | src/humanize/locale/fa_IR/LC_MESSAGES/humanize.mo |
41 | 41 | assert humanize.intcomma(number) == "10,000,000" |
42 | 42 | |
43 | 43 | try: |
44 | humanize.i18n.activate("de_DE") | |
45 | assert humanize.intcomma(number) == "10.000.000" | |
46 | assert humanize.intcomma(1_234_567.8901) == "1.234.567,8901" | |
47 | assert humanize.intcomma(1_234_567.89) == "1.234.567,89" | |
48 | assert humanize.intcomma("1234567,89") == "1.234.567,89" | |
49 | assert humanize.intcomma("1.234.567,89") == "1.234.567,89" | |
50 | assert humanize.intcomma("1.234.567,8") == "1.234.567,8" | |
51 | ||
44 | 52 | humanize.i18n.activate("fr_FR") |
45 | 53 | assert humanize.intcomma(number) == "10 000 000" |
46 | 54 | |
155 | 163 | def test_default_locale_path_undefined__file__() -> None: |
156 | 164 | i18n = importlib.import_module("humanize.i18n") |
157 | 165 | del i18n.__file__ |
158 | i18n._get_default_locale_path() is None | |
166 | assert i18n._get_default_locale_path() is None | |
159 | 167 | |
160 | 168 | |
161 | 169 | class TestActivate: |
45 | 45 | (["10311"], "10,311"), |
46 | 46 | (["1000000"], "1,000,000"), |
47 | 47 | (["1234567.1234567"], "1,234,567.1234567"), |
48 | (["1234567.1234567", 0], "1,234,567"), | |
49 | (["1234567.1234567", 1], "1,234,567.1"), | |
50 | (["1234567.1234567", 10], "1,234,567.1234567000"), | |
51 | (["1234567", 1], "1,234,567.0"), | |
48 | 52 | ([None], "None"), |
49 | 53 | ([14308.40], "14,308.4"), |
50 | 54 | ([14308.40, None], "14,308.4"), |
74 | 78 | @pytest.mark.parametrize( |
75 | 79 | "test_args, expected", |
76 | 80 | [ |
81 | (["0"], "0"), | |
77 | 82 | (["100"], "100"), |
83 | (["-100"], "-100"), | |
78 | 84 | (["1000"], "1.0 thousand"), |
79 | 85 | (["12400"], "12.4 thousand"), |
80 | 86 | (["12490"], "12.5 thousand"), |
81 | 87 | (["1000000"], "1.0 million"), |
88 | (["-1000000"], "-1.0 million"), | |
82 | 89 | (["1200000"], "1.2 million"), |
83 | 90 | (["1290000"], "1.3 million"), |
84 | 91 | (["999999999"], "1.0 billion"), |
85 | 92 | (["1000000000"], "1.0 billion"), |
93 | (["-1000000000"], "-1.0 billion"), | |
86 | 94 | (["2000000000"], "2.0 billion"), |
87 | 95 | (["999999999999"], "1.0 trillion"), |
88 | 96 | (["1000000000000"], "1.0 trillion"), |
89 | 97 | (["6000000000000"], "6.0 trillion"), |
98 | (["-6000000000000"], "-6.0 trillion"), | |
90 | 99 | (["999999999999999"], "1.0 quadrillion"), |
91 | 100 | (["1000000000000000"], "1.0 quadrillion"), |
92 | 101 | (["1300000000000000"], "1.3 quadrillion"), |
102 | (["-1300000000000000"], "-1.3 quadrillion"), | |
93 | 103 | (["3500000000000000000000"], "3.5 sextillion"), |
94 | 104 | (["8100000000000000000000000000000000"], "8.1 decillion"), |
105 | (["-8100000000000000000000000000000000"], "-8.1 decillion"), | |
95 | 106 | ([None], "None"), |
96 | 107 | (["1230000", "%0.2f"], "1.23 million"), |
97 | 108 | ([10**101], "1" + "0" * 101), |
186 | 197 | @pytest.mark.parametrize( |
187 | 198 | "test_args, expected", |
188 | 199 | [ |
200 | ([0], "0.00"), | |
189 | 201 | ([1, "Hz"], "1.00 Hz"), |
190 | 202 | ([1.0, "W"], "1.00 W"), |
191 | 203 | ([3, "C"], "3.00 C"), |
628 | 628 | |
629 | 629 | |
630 | 630 | def test_precisedelta_bogus_call() -> None: |
631 | assert humanize.precisedelta(None) == "None" | |
632 | ||
631 | 633 | with pytest.raises(ValueError): |
632 | 634 | humanize.precisedelta(1, minimum_unit="years", suppress=["years"]) |
633 | 635 | |
639 | 641 | years, minutes = time.Unit["YEARS"], time.Unit["MINUTES"] |
640 | 642 | assert minutes < years |
641 | 643 | assert years > minutes |
642 | assert minutes == minutes | |
643 | 644 | |
644 | 645 | with pytest.raises(TypeError): |
645 | 646 | _ = years < "foo" |