Skip to content

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
@codecov
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 52 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.01% <ø> (ø)
ubuntu-latest 97.01% <ø> (ø)
windows-latest 94.96% <ø> (ø)

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.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@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 <[email protected]>
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 <[email protected]>
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