Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate translation binaries during release #232

Merged
merged 3 commits into from
Feb 11, 2025

Conversation

hugovk
Copy link
Member

@hugovk hugovk commented Feb 11, 2025

Fixes #231.

@hugovk hugovk added the changelog: Fixed For any bug fixes label Feb 11, 2025
Copy link

codecov bot commented Feb 11, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.47%. Comparing base (724263d) to head (5c79e2f).
Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #232   +/-   ##
=======================================
  Coverage   99.47%   99.47%           
=======================================
  Files          11       11           
  Lines         760      760           
=======================================
  Hits          756      756           
  Misses          4        4           
Flag Coverage Δ
macos-latest 97.89% <ø> (ø)
ubuntu-latest 97.89% <ø> (ø)
windows-latest 96.44% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@hugovk
Copy link
Member Author

hugovk commented Feb 11, 2025

Before: no .mo files

Package Contents

SDist contents
[2025-02-01T22:08:54Z]  humanize-4.11.1.dev29
├── [2025-02-01T22:08:37Z]  .coveragerc
├── [2025-02-01T22:08:54Z]  .github
│   ├── [2025-02-01T22:08:37Z]  CONTRIBUTING.md
│   ├── [2025-02-01T22:08:37Z]  FUNDING.yml
│   ├── [2025-02-01T22:08:37Z]  ISSUE_TEMPLATE.md
│   ├── [2025-02-01T22:08:37Z]  PULL_REQUEST_TEMPLATE.md
│   ├── [2025-02-01T22:08:37Z]  SECURITY.md
│   ├── [2025-02-01T22:08:37Z]  labels.yml
│   ├── [2025-02-01T22:08:37Z]  release-drafter.yml
│   ├── [2025-02-01T22:08:37Z]  renovate.json
│   └── [2025-02-01T22:08:54Z]  workflows
│       ├── [2025-02-01T22:08:37Z]  docs.yml
│       ├── [2025-02-01T22:08:37Z]  labels.yml
│       ├── [2025-02-01T22:08:37Z]  lint.yml
│       ├── [2025-02-01T22:08:37Z]  release-drafter.yml
│       ├── [2025-02-01T22:08:37Z]  release.yml
│       ├── [2025-02-01T22:08:37Z]  require-pr-label.yml
│       └── [2025-02-01T22:08:37Z]  test.yml
├── [2025-02-01T22:08:37Z]  .gitignore
├── [2025-02-01T22:08:37Z]  .pre-commit-config.yaml
├── [2025-02-01T22:08:37Z]  .readthedocs.yml
├── [2025-02-01T22:08:37Z]  LICENCE
├── [2025-02-01T22:08:37Z]  PKG-INFO
├── [2025-02-01T22:08:37Z]  README.md
├── [2025-02-01T22:08:37Z]  RELEASING.md
├── [2025-02-01T22:08:54Z]  docs
│   ├── [2025-02-01T22:08:54Z]  css
│   │   └── [2025-02-01T22:08:37Z]  code_select.css
│   ├── [2025-02-01T22:08:37Z]  filesize.md
│   ├── [2025-02-01T22:08:37Z]  i18n.md
│   ├── [2025-02-01T22:08:37Z]  index.md
│   ├── [2025-02-01T22:08:37Z]  lists.md
│   ├── [2025-02-01T22:08:37Z]  number.md
│   ├── [2025-02-01T22:08:37Z]  requirements.txt
│   └── [2025-02-01T22:08:37Z]  time.md
├── [2025-02-01T22:08:37Z]  mkdocs.yml
├── [2025-02-01T22:08:37Z]  pyproject.toml
├── [2025-02-01T22:08:54Z]  scripts
│   ├── [2025-02-01T22:08:37Z]  generate-translation-binaries.sh
│   └── [2025-02-01T22:08:37Z]  update-translations.sh
├── [2025-02-01T22:08:54Z]  src
│   └── [2025-02-01T22:08:54Z]  humanize
│       ├── [2025-02-01T22:08:37Z]  __init__.py
│       ├── [2025-02-01T22:08:37Z]  _version.py
│       ├── [2025-02-01T22:08:37Z]  filesize.py
│       ├── [2025-02-01T22:08:37Z]  i18n.py
│       ├── [2025-02-01T22:08:37Z]  lists.py
│       ├── [2025-02-01T22:08:54Z]  locale
│       │   ├── [2025-02-01T22:08:54Z]  ar
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  bn_BD
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  ca_ES
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  da_DK
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  de_DE
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  el_GR
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  eo
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  es_ES
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  eu
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  fa_IR
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  fi_FI
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  fr_FR
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  he_IL
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  hu_HU
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  id_ID
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  it_IT
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  ja_JP
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  ko_KR
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  nb
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  nl_NL
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  pl_PL
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  pt_BR
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  pt_PT
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  ru_RU
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  sk_SK
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  sl_SI
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  sv_SE
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  tlh
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  tr_TR
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  uk_UA
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  vi_VN
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   ├── [2025-02-01T22:08:54Z]  zh_CN
│       │   │   └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │   │       └── [2025-02-01T22:08:37Z]  humanize.po
│       │   └── [2025-02-01T22:08:54Z]  zh_HK
│       │       └── [2025-02-01T22:08:54Z]  LC_MESSAGES
│       │           └── [2025-02-01T22:08:37Z]  humanize.po
│       ├── [2025-02-01T22:08:37Z]  number.py
│       ├── [2025-02-01T22:08:37Z]  py.typed
│       └── [2025-02-01T22:08:37Z]  time.py
├── [2025-02-01T22:08:54Z]  tests
│   ├── [2025-02-01T22:08:37Z]  __init__.py
│   ├── [2025-02-01T22:08:37Z]  test_filesize.py
│   ├── [2025-02-01T22:08:37Z]  test_i18n.py
│   ├── [2025-02-01T22:08:37Z]  test_lists.py
│   ├── [2025-02-01T22:08:37Z]  test_number.py
│   └── [2025-02-01T22:08:37Z]  test_time.py
└── [2025-02-01T22:08:37Z]  tox.ini

76 directories, 83 files
Wheel contents
humanize-4.11.1.dev29
├── humanize
│   ├── __init__.py
│   ├── _version.py
│   ├── filesize.py
│   ├── i18n.py
│   ├── lists.py
│   ├── locale
│   │   ├── ar
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── bn_BD
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── ca_ES
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── da_DK
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── de_DE
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── el_GR
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── eo
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── es_ES
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── eu
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── fa_IR
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── fi_FI
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── fr_FR
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── he_IL
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── hu_HU
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── id_ID
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── it_IT
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── ja_JP
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── ko_KR
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── nb
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── nl_NL
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── pl_PL
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── pt_BR
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── pt_PT
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── ru_RU
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── sk_SK
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── sl_SI
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── sv_SE
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── tlh
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── tr_TR
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── uk_UA
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── vi_VN
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   ├── zh_CN
│   │   │   └── LC_MESSAGES
│   │   │       └── humanize.po
│   │   └── zh_HK
│   │       └── LC_MESSAGES
│   │           └── humanize.po
│   ├── number.py
│   ├── py.typed
│   └── time.py
└── humanize-4.11.1.dev29.dist-info
    ├── METADATA
    ├── RECORD
    ├── WHEEL
    └── licenses
        └── LICENCE

71 directories, 45 files
Metadata
Metadata-Version: 2.4
Name: humanize
Version: 4.11.1.dev29
Summary: Python humanize utilities
Project-URL: Documentation, https://humanize.readthedocs.io/
Project-URL: Funding, https://tidelift.com/subscription/pkg/pypi-humanize?utm_source=pypi-humanize&utm_medium=pypi
Project-URL: Homepage, https://github.com/python-humanize/humanize
Project-URL: Issue tracker, https://github.com/python-humanize/humanize/issues
Project-URL: Release notes, https://github.com/python-humanize/humanize/releases
Project-URL: Source, https://github.com/python-humanize/humanize
Author-email: Jason Moiron <jmoiron@jmoiron.net>
Maintainer: Hugo van Kemenade
License: MIT
License-File: LICENCE
Keywords: humanize time size
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Text Processing
Classifier: Topic :: Text Processing :: General
Requires-Python: >=3.9
Provides-Extra: tests
Requires-Dist: freezegun; extra == 'tests'
Requires-Dist: pytest; extra == 'tests'
Requires-Dist: pytest-cov; extra == 'tests'
Description-Content-Type: text/markdown

# humanize

[![PyPI version](https://img.shields.io/pypi/v/humanize.svg?logo=pypi&logoColor=FFE873)](https://pypi.org/project/humanize/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/humanize.svg?logo=python&logoColor=FFE873)](https://pypi.org/project/humanize/)
[![Documentation Status](https://readthedocs.org/projects/python-humanize/badge/?version=latest)](https://humanize.readthedocs.io/en/latest/?badge=latest)
[![PyPI downloads](https://img.shields.io/pypi/dm/humanize.svg)](https://pypistats.org/packages/humanize)
[![GitHub Actions status](https://github.com/python-humanize/humanize/workflows/Test/badge.svg)](https://github.com/python-humanize/humanize/actions)
[![codecov](https://codecov.io/gh/python-humanize/humanize/branch/main/graph/badge.svg)](https://codecov.io/gh/python-humanize/humanize)
[![MIT License](https://img.shields.io/github/license/python-humanize/humanize.svg)](LICENCE)
[![Tidelift](https://tidelift.com/badges/package/pypi/humanize)](https://tidelift.com/subscription/pkg/pypi-humanize?utm_source=pypi-humanize&utm_medium=badge)

This modest package contains various common humanization utilities, like turning a
number into a fuzzy human-readable duration ("3 minutes ago") or into a human-readable
size or throughput. It is localized to:

- Arabic
- Basque
- Bengali
- Brazilian Portuguese
- Catalan
- Danish
- Dutch
- Esperanto
- European Portuguese
- Finnish
- French
- German
- Greek
- Hebrew
- Indonesian
- Italian
- Japanese
- Klingon
- Korean
- Norwegian
- Persian
- Polish
- Russian
- Simplified Chinese
- Slovak
- Slovenian
- Spanish
- Swedish
- Turkish
- Ukrainian
- Vietnamese

## API reference

[https://humanize.readthedocs.io](https://humanize.readthedocs.io/)

<!-- usage-start -->

## Installation

### From PyPI

```bash
python3 -m pip install --upgrade humanize
```

### From source

```bash
git clone https://github.com/python-humanize/humanize
cd humanize
python3 -m pip install -e .
```

## Usage

### Integer humanization

```pycon
>>> import humanize
>>> humanize.intcomma(12345)
'12,345'
>>> humanize.intword(123455913)
'123.5 million'
>>> humanize.intword(12345591313)
'12.3 billion'
>>> humanize.apnumber(4)
'four'
>>> humanize.apnumber(41)
'41'
```

### Date & time humanization

```pycon
>>> import humanize
>>> import datetime as dt
>>> humanize.naturalday(dt.datetime.now())
'today'
>>> humanize.naturaldelta(dt.timedelta(seconds=1001))
'16 minutes'
>>> humanize.naturalday(dt.datetime.now() - dt.timedelta(days=1))
'yesterday'
>>> humanize.naturalday(dt.date(2007, 6, 5))
'Jun 05'
>>> humanize.naturaldate(dt.date(2007, 6, 5))
'Jun 05 2007'
>>> humanize.naturaltime(dt.datetime.now() - dt.timedelta(seconds=1))
'a second ago'
>>> humanize.naturaltime(dt.datetime.now() - dt.timedelta(seconds=3600))
'an hour ago'
```

### Precise time delta

```pycon
>>> import humanize
>>> import datetime as dt
>>> delta = dt.timedelta(seconds=3633, days=2, microseconds=123000)
>>> humanize.precisedelta(delta)
'2 days, 1 hour and 33.12 seconds'
>>> humanize.precisedelta(delta, minimum_unit="microseconds")
'2 days, 1 hour, 33 seconds and 123 milliseconds'
>>> humanize.precisedelta(delta, suppress=["days"], format="%0.4f")
'49 hours and 33.1230 seconds'
```

#### Smaller units

If seconds are too large, set `minimum_unit` to milliseconds or microseconds:

```pycon
>>> import humanize
>>> import datetime as dt
>>> humanize.naturaldelta(dt.timedelta(seconds=2))
'2 seconds'
```

```pycon
>>> delta = dt.timedelta(milliseconds=4)
>>> humanize.naturaldelta(delta)
'a moment'
>>> humanize.naturaldelta(delta, minimum_unit="milliseconds")
'4 milliseconds'
>>> humanize.naturaldelta(delta, minimum_unit="microseconds")
'4 milliseconds'
```

```pycon
>>> humanize.naturaltime(delta)
'now'
>>> humanize.naturaltime(delta, minimum_unit="milliseconds")
'4 milliseconds ago'
>>> humanize.naturaltime(delta, minimum_unit="microseconds")
'4 milliseconds ago'
```

### File size humanization

```pycon
>>> import humanize
>>> humanize.naturalsize(1_000_000)
'1.0 MB'
>>> humanize.naturalsize(1_000_000, binary=True)
'976.6 KiB'
>>> humanize.naturalsize(1_000_000, gnu=True)
'976.6K'
```

### Human-readable floating point numbers

```pycon
>>> import humanize
>>> humanize.fractional(1/3)
'1/3'
>>> humanize.fractional(1.5)
'1 1/2'
>>> humanize.fractional(0.3)
'3/10'
>>> humanize.fractional(0.333)
'333/1000'
>>> humanize.fractional(1)
'1'
```

### Scientific notation

```pycon
>>> import humanize
>>> humanize.scientific(0.3)
'3.00 x 10⁻¹'
>>> humanize.scientific(500)
'5.00 x 10²'
>>> humanize.scientific("20000")
'2.00 x 10⁴'
>>> humanize.scientific(1**10)
'1.00 x 10⁰'
>>> humanize.scientific(1**10, precision=1)
'1.0 x 10⁰'
>>> humanize.scientific(1**10, precision=0)
'1 x 10⁰'
```

## Localization

How to change locale at runtime:

```pycon
>>> import humanize
>>> import datetime as dt
>>> humanize.naturaltime(dt.timedelta(seconds=3))
'3 seconds ago'
>>> _t = humanize.i18n.activate("ru_RU")
>>> humanize.naturaltime(dt.timedelta(seconds=3))
'3 секунды назад'
>>> humanize.i18n.deactivate()
>>> humanize.naturaltime(dt.timedelta(seconds=3))
'3 seconds ago'
```

You can pass additional parameter `path` to `activate` to specify a path to search
locales in.

```pycon
>>> import humanize
>>> humanize.i18n.activate("xx_XX")
<...>
FileNotFoundError: [Errno 2] No translation file found for domain: 'humanize'
>>> humanize.i18n.activate("pt_BR", path="path/to/my/own/translation/")
<gettext.GNUTranslations instance ...>
```

<!-- usage-end -->

How to add new phrases to existing locale files:

```sh
xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -k'NS_:1,2' -k'_ngettext:1,2' -l python src/humanize/*.py  # extract new phrases
msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files
```

How to add a new locale:

```sh
msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name>
```

Where `<locale name>` is a locale abbreviation, eg. `en_GB`, `pt_BR` or just `ru`, `fr`
etc.

List the language at the top of this README.

https://github.com/python-humanize/humanize/actions/runs/13092885419

After: has .mo files

Package Contents

SDist contents
[2025-02-11T17:06:01Z]  humanize-4.11.1.dev33
├── [2025-02-11T17:05:33Z]  .coveragerc
├── [2025-02-11T17:06:01Z]  .github
│   ├── [2025-02-11T17:05:33Z]  CONTRIBUTING.md
│   ├── [2025-02-11T17:05:33Z]  FUNDING.yml
│   ├── [2025-02-11T17:05:33Z]  ISSUE_TEMPLATE.md
│   ├── [2025-02-11T17:05:33Z]  PULL_REQUEST_TEMPLATE.md
│   ├── [2025-02-11T17:05:33Z]  SECURITY.md
│   ├── [2025-02-11T17:05:33Z]  labels.yml
│   ├── [2025-02-11T17:05:33Z]  release-drafter.yml
│   ├── [2025-02-11T17:05:33Z]  renovate.json
│   └── [2025-02-11T17:06:01Z]  workflows
│       ├── [2025-02-11T17:05:33Z]  docs.yml
│       ├── [2025-02-11T17:05:33Z]  labels.yml
│       ├── [2025-02-11T17:05:33Z]  lint.yml
│       ├── [2025-02-11T17:05:33Z]  release-drafter.yml
│       ├── [2025-02-11T17:05:33Z]  release.yml
│       ├── [2025-02-11T17:05:33Z]  require-pr-label.yml
│       └── [2025-02-11T17:05:33Z]  test.yml
├── [2025-02-11T17:05:33Z]  .gitignore
├── [2025-02-11T17:05:33Z]  .pre-commit-config.yaml
├── [2025-02-11T17:05:33Z]  .readthedocs.yml
├── [2025-02-11T17:05:33Z]  LICENCE
├── [2025-02-11T17:05:33Z]  PKG-INFO
├── [2025-02-11T17:05:33Z]  README.md
├── [2025-02-11T17:05:33Z]  RELEASING.md
├── [2025-02-11T17:06:01Z]  docs
│   ├── [2025-02-11T17:06:01Z]  css
│   │   └── [2025-02-11T17:05:33Z]  code_select.css
│   ├── [2025-02-11T17:05:33Z]  filesize.md
│   ├── [2025-02-11T17:05:33Z]  i18n.md
│   ├── [2025-02-11T17:05:33Z]  index.md
│   ├── [2025-02-11T17:05:33Z]  lists.md
│   ├── [2025-02-11T17:05:33Z]  number.md
│   ├── [2025-02-11T17:05:33Z]  requirements.txt
│   └── [2025-02-11T17:05:33Z]  time.md
├── [2025-02-11T17:05:33Z]  mkdocs.yml
├── [2025-02-11T17:05:33Z]  pyproject.toml
├── [2025-02-11T17:06:01Z]  scripts
│   ├── [2025-02-11T17:05:33Z]  generate-translation-binaries.sh
│   └── [2025-02-11T17:05:33Z]  update-translations.sh
├── [2025-02-11T17:06:01Z]  src
│   └── [2025-02-11T17:06:01Z]  humanize
│       ├── [2025-02-11T17:05:33Z]  __init__.py
│       ├── [2025-02-11T17:05:33Z]  _version.py
│       ├── [2025-02-11T17:05:33Z]  filesize.py
│       ├── [2025-02-11T17:05:33Z]  i18n.py
│       ├── [2025-02-11T17:05:33Z]  lists.py
│       ├── [2025-02-11T17:06:01Z]  locale
│       │   ├── [2025-02-11T17:06:01Z]  ar
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  bn_BD
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  ca_ES
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  da_DK
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  de_DE
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  el_GR
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  eo
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  es_ES
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  eu
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  fa_IR
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  fi_FI
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  fr_FR
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  he_IL
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  hu_HU
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  id_ID
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  it_IT
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  ja_JP
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  ko_KR
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  nb
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  nl_NL
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  pl_PL
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  pt_BR
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  pt_PT
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  ru_RU
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  sk_SK
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  sl_SI
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  sv_SE
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  tlh
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  tr_TR
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  uk_UA
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  vi_VN
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   ├── [2025-02-11T17:06:01Z]  zh_CN
│       │   │   └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │   │       ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │   │       └── [2025-02-11T17:05:33Z]  humanize.po
│       │   └── [2025-02-11T17:06:01Z]  zh_HK
│       │       └── [2025-02-11T17:06:01Z]  LC_MESSAGES
│       │           ├── [2025-02-11T17:05:33Z]  humanize.mo
│       │           └── [2025-02-11T17:05:33Z]  humanize.po
│       ├── [2025-02-11T17:05:33Z]  number.py
│       ├── [2025-02-11T17:05:33Z]  py.typed
│       └── [2025-02-11T17:05:33Z]  time.py
├── [2025-02-11T17:06:01Z]  tests
│   ├── [2025-02-11T17:05:33Z]  __init__.py
│   ├── [2025-02-11T17:05:33Z]  test_filesize.py
│   ├── [2025-02-11T17:05:33Z]  test_i18n.py
│   ├── [2025-02-11T17:05:33Z]  test_lists.py
│   ├── [2025-02-11T17:05:33Z]  test_number.py
│   └── [2025-02-11T17:05:33Z]  test_time.py
└── [2025-02-11T17:05:33Z]  tox.ini

76 directories, 116 files
Wheel contents
humanize-4.11.1.dev33
├── humanize
│   ├── __init__.py
│   ├── _version.py
│   ├── filesize.py
│   ├── i18n.py
│   ├── lists.py
│   ├── locale
│   │   ├── ar
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── bn_BD
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── ca_ES
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── da_DK
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── de_DE
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── el_GR
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── eo
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── es_ES
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── eu
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── fa_IR
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── fi_FI
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── fr_FR
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── he_IL
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── hu_HU
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── id_ID
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── it_IT
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── ja_JP
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── ko_KR
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── nb
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── nl_NL
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── pl_PL
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── pt_BR
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── pt_PT
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── ru_RU
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── sk_SK
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── sl_SI
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── sv_SE
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── tlh
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── tr_TR
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── uk_UA
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── vi_VN
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   ├── zh_CN
│   │   │   └── LC_MESSAGES
│   │   │       ├── humanize.mo
│   │   │       └── humanize.po
│   │   └── zh_HK
│   │       └── LC_MESSAGES
│   │           ├── humanize.mo
│   │           └── humanize.po
│   ├── number.py
│   ├── py.typed
│   └── time.py
└── humanize-4.11.1.dev33.dist-info
    ├── METADATA
    ├── RECORD
    ├── WHEEL
    └── licenses
        └── LICENCE

71 directories, 78 files
Metadata
Metadata-Version: 2.4
Name: humanize
Version: 4.11.1.dev33
Summary: Python humanize utilities
Project-URL: Documentation, https://humanize.readthedocs.io/
Project-URL: Funding, https://tidelift.com/subscription/pkg/pypi-humanize?utm_source=pypi-humanize&utm_medium=pypi
Project-URL: Homepage, https://github.com/python-humanize/humanize
Project-URL: Issue tracker, https://github.com/python-humanize/humanize/issues
Project-URL: Release notes, https://github.com/python-humanize/humanize/releases
Project-URL: Source, https://github.com/python-humanize/humanize
Author-email: Jason Moiron <jmoiron@jmoiron.net>
Maintainer: Hugo van Kemenade
License: MIT
License-File: LICENCE
Keywords: humanize time size
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Text Processing
Classifier: Topic :: Text Processing :: General
Requires-Python: >=3.9
Provides-Extra: tests
Requires-Dist: freezegun; extra == 'tests'
Requires-Dist: pytest; extra == 'tests'
Requires-Dist: pytest-cov; extra == 'tests'
Description-Content-Type: text/markdown

# humanize

[![PyPI version](https://img.shields.io/pypi/v/humanize.svg?logo=pypi&logoColor=FFE873)](https://pypi.org/project/humanize/)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/humanize.svg?logo=python&logoColor=FFE873)](https://pypi.org/project/humanize/)
[![Documentation Status](https://readthedocs.org/projects/python-humanize/badge/?version=latest)](https://humanize.readthedocs.io/en/latest/?badge=latest)
[![PyPI downloads](https://img.shields.io/pypi/dm/humanize.svg)](https://pypistats.org/packages/humanize)
[![GitHub Actions status](https://github.com/python-humanize/humanize/workflows/Test/badge.svg)](https://github.com/python-humanize/humanize/actions)
[![codecov](https://codecov.io/gh/python-humanize/humanize/branch/main/graph/badge.svg)](https://codecov.io/gh/python-humanize/humanize)
[![MIT License](https://img.shields.io/github/license/python-humanize/humanize.svg)](LICENCE)
[![Tidelift](https://tidelift.com/badges/package/pypi/humanize)](https://tidelift.com/subscription/pkg/pypi-humanize?utm_source=pypi-humanize&utm_medium=badge)

This modest package contains various common humanization utilities, like turning a
number into a fuzzy human-readable duration ("3 minutes ago") or into a human-readable
size or throughput. It is localized to:

- Arabic
- Basque
- Bengali
- Brazilian Portuguese
- Catalan
- Danish
- Dutch
- Esperanto
- European Portuguese
- Finnish
- French
- German
- Greek
- Hebrew
- Indonesian
- Italian
- Japanese
- Klingon
- Korean
- Norwegian
- Persian
- Polish
- Russian
- Simplified Chinese
- Slovak
- Slovenian
- Spanish
- Swedish
- Turkish
- Ukrainian
- Vietnamese

## API reference

[https://humanize.readthedocs.io](https://humanize.readthedocs.io/)

<!-- usage-start -->

## Installation

### From PyPI

```bash
python3 -m pip install --upgrade humanize
```

### From source

```bash
git clone https://github.com/python-humanize/humanize
cd humanize
python3 -m pip install -e .
```

## Usage

### Integer humanization

```pycon
>>> import humanize
>>> humanize.intcomma(12345)
'12,345'
>>> humanize.intword(123455913)
'123.5 million'
>>> humanize.intword(12345591313)
'12.3 billion'
>>> humanize.apnumber(4)
'four'
>>> humanize.apnumber(41)
'41'
```

### Date & time humanization

```pycon
>>> import humanize
>>> import datetime as dt
>>> humanize.naturalday(dt.datetime.now())
'today'
>>> humanize.naturaldelta(dt.timedelta(seconds=1001))
'16 minutes'
>>> humanize.naturalday(dt.datetime.now() - dt.timedelta(days=1))
'yesterday'
>>> humanize.naturalday(dt.date(2007, 6, 5))
'Jun 05'
>>> humanize.naturaldate(dt.date(2007, 6, 5))
'Jun 05 2007'
>>> humanize.naturaltime(dt.datetime.now() - dt.timedelta(seconds=1))
'a second ago'
>>> humanize.naturaltime(dt.datetime.now() - dt.timedelta(seconds=3600))
'an hour ago'
```

### Precise time delta

```pycon
>>> import humanize
>>> import datetime as dt
>>> delta = dt.timedelta(seconds=3633, days=2, microseconds=123000)
>>> humanize.precisedelta(delta)
'2 days, 1 hour and 33.12 seconds'
>>> humanize.precisedelta(delta, minimum_unit="microseconds")
'2 days, 1 hour, 33 seconds and 123 milliseconds'
>>> humanize.precisedelta(delta, suppress=["days"], format="%0.4f")
'49 hours and 33.1230 seconds'
```

#### Smaller units

If seconds are too large, set `minimum_unit` to milliseconds or microseconds:

```pycon
>>> import humanize
>>> import datetime as dt
>>> humanize.naturaldelta(dt.timedelta(seconds=2))
'2 seconds'
```

```pycon
>>> delta = dt.timedelta(milliseconds=4)
>>> humanize.naturaldelta(delta)
'a moment'
>>> humanize.naturaldelta(delta, minimum_unit="milliseconds")
'4 milliseconds'
>>> humanize.naturaldelta(delta, minimum_unit="microseconds")
'4 milliseconds'
```

```pycon
>>> humanize.naturaltime(delta)
'now'
>>> humanize.naturaltime(delta, minimum_unit="milliseconds")
'4 milliseconds ago'
>>> humanize.naturaltime(delta, minimum_unit="microseconds")
'4 milliseconds ago'
```

### File size humanization

```pycon
>>> import humanize
>>> humanize.naturalsize(1_000_000)
'1.0 MB'
>>> humanize.naturalsize(1_000_000, binary=True)
'976.6 KiB'
>>> humanize.naturalsize(1_000_000, gnu=True)
'976.6K'
```

### Human-readable floating point numbers

```pycon
>>> import humanize
>>> humanize.fractional(1/3)
'1/3'
>>> humanize.fractional(1.5)
'1 1/2'
>>> humanize.fractional(0.3)
'3/10'
>>> humanize.fractional(0.333)
'333/1000'
>>> humanize.fractional(1)
'1'
```

### Scientific notation

```pycon
>>> import humanize
>>> humanize.scientific(0.3)
'3.00 x 10⁻¹'
>>> humanize.scientific(500)
'5.00 x 10²'
>>> humanize.scientific("20000")
'2.00 x 10⁴'
>>> humanize.scientific(1**10)
'1.00 x 10⁰'
>>> humanize.scientific(1**10, precision=1)
'1.0 x 10⁰'
>>> humanize.scientific(1**10, precision=0)
'1 x 10⁰'
```

## Localization

How to change locale at runtime:

```pycon
>>> import humanize
>>> import datetime as dt
>>> humanize.naturaltime(dt.timedelta(seconds=3))
'3 seconds ago'
>>> _t = humanize.i18n.activate("ru_RU")
>>> humanize.naturaltime(dt.timedelta(seconds=3))
'3 секунды назад'
>>> humanize.i18n.deactivate()
>>> humanize.naturaltime(dt.timedelta(seconds=3))
'3 seconds ago'
```

You can pass additional parameter `path` to `activate` to specify a path to search
locales in.

```pycon
>>> import humanize
>>> humanize.i18n.activate("xx_XX")
<...>
FileNotFoundError: [Errno 2] No translation file found for domain: 'humanize'
>>> humanize.i18n.activate("pt_BR", path="path/to/my/own/translation/")
<gettext.GNUTranslations instance ...>
```

<!-- usage-end -->

How to add new phrases to existing locale files:

```sh
xgettext --from-code=UTF-8 -o humanize.pot -k'_' -k'N_' -k'P_:1c,2' -k'NS_:1,2' -k'_ngettext:1,2' -l python src/humanize/*.py  # extract new phrases
msgmerge -U src/humanize/locale/ru_RU/LC_MESSAGES/humanize.po humanize.pot # add them to locale files
```

How to add a new locale:

```sh
msginit -i humanize.pot -o humanize/locale/<locale name>/LC_MESSAGES/humanize.po --locale <locale name>
```

Where `<locale name>` is a locale abbreviation, eg. `en_GB`, `pt_BR` or just `ru`, `fr`
etc.

List the language at the top of this README.

https://github.com/python-humanize/humanize/actions/runs/13268419681?pr=232

@hugovk hugovk merged commit de8b8a1 into python-humanize:main Feb 11, 2025
32 checks passed
@hugovk hugovk deleted the generate-translation-binaries branch February 11, 2025 17:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
changelog: Fixed For any bug fixes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Generate translation binaries during deploy
1 participant