nutq
Script conversion and text normalization for Tajik, Persian, Dari and Uzbek — in pure Python, with no dependencies.
nutq (нутқ · نطق · nutq) means "speech" in all three languages.
More than 150 million people speak these languages, and many of them write them in more than one script. Text-to-speech systems, chat bots, search engines and language models need the same text in a consistent form and the numbers spelled out, and there is little open tooling for that. nutq gives you one small, tested API for both jobs, and other languages can be added as plugins.
Tajik tg |
Persian fa |
Dari fa-AF |
Uzbek uz |
|
|---|---|---|---|---|
| Scripts | Cyrillic · Latin · Perso-Arabic | Perso-Arabic | Perso-Arabic | Latin · Cyrillic |
| Script conversion | Cyrl ↔ Latn, Cyrl → Arab, Arab → Cyrl (experimental) | via tg |
via tg |
Cyrl ↔ Latn |
| Numbers → words | cardinal, ordinal | cardinal, ordinal | cardinal, ordinal | cardinal, ordinal |
| Normalization for speech | numbers, decimals, %, money, dates, times, phone and version numbers, °C, abbreviations | + Solar Hijri dates | + Afghan month names | Latin and Cyrillic |
| Character cleanup | look-alike letters | ي/ك → ی/ک, digits, ZWNJ | same as fa |
apostrophes oʻ gʻ ʼ |
Status: beta. Each rule is tested, but native speakers still need to review many of them. See Linguistic review.
Install
pip install nutq
(Not yet published. Until then: pip install -e . from a clone.)
Usage
import nutq
# Script conversion
nutq.convert("Забони тоҷикӣ", "tg", to="Arab") # 'زبان تاجیکی'
nutq.convert("Тоҷикистон", "tg", to="Latn") # 'Tojikiston'
nutq.convert("Ўзбекистон", "uz", to="Latn") # 'Oʻzbekiston'
nutq.convert("O'zbekiston", "uz", to="Cyrl") # 'Ўзбекистон'
# Numbers to words
nutq.number_to_words(2026, "tg") # 'ду ҳазору бисту шаш'
nutq.number_to_words(2026, "fa") # 'دو هزار و بیست و شش'
nutq.number_to_words(3, "uz", ordinal=True) # 'uchinchi'
nutq.number_to_words(4, "uz", script="Cyrl", ordinal=True) # 'тўртинчи'
# Normalization for TTS and language models
nutq.normalize("Нархи 25 $ аст, 12.03.2026", "tg")
# 'Нархи бисту панҷ доллар аст, дувоздаҳуми марти соли ду ҳазору бисту шаш'
nutq.normalize("۱۴۰۵/۰۱/۱۲، ۱۵٪", "fa")
# 'دوازدهم فروردین هزار و چهارصد و پنج، پانزده درصد'
nutq.normalize("2026-yil 12-mart, 2,5 kg", "uz")
# 'ikki ming yigirma oltinchi yil oʻn ikkinchi mart, ikki butun oʻndan besh kilogramm'
# Character cleanup only
nutq.clean("Тoҷик", "tg") # 'Тоҷик' (the "o" was Latin)
nutq.clean("كتابي", "fa") # 'کتابی'
Language codes follow BCP-47 / ISO 639 (tg, fa, fa-AF, prs, uz, ...). Scripts are ISO 15924 codes (Cyrl, Latn, Arab) or names ("latin"). If you don't pass source=, convert detects the source script.
Command line
nutq convert --lang tg --to Arab "Забони тоҷикӣ"
nutq normalize --lang uz "Narxi 25 $, 15% chegirma"
nutq number --lang fa --ordinal 23
echo "O'zbekiston" | nutq convert -l uz -t Cyrl
nutq languages
How Tajik → Perso-Arabic works
Tajik Cyrillic writes every vowel. Persian script leaves out short vowels and has several letters for one sound (с = س ص ث). A rule-only converter therefore cannot be exact. nutq works in three steps:
- Word list —
lang/tg/data/arabic_words.tsvholds the spellings rules can't guess (китоб → کتاب, илм → علم). - Suffixes and stems — plural -ҳо/-ён, object -ро → را, izafat -и, comparative -тар/-тарин, the linking -у → و, verb prefixes ме-/наме- → می/نمی, and stems like хонд → خواند, кун → کن.
- Letter rules for everything else. They are correct for many common words (нон → نان, Самарқанд → سمرقند).
Arabic → Cyrillic is experimental. Without a dictionary, an unvowelled word can only be read approximately.
Adding a language
Each language is one folder under src/nutq/lang/. It registers a Language object, and third-party packages can add languages through an entry point without changing nutq. See CONTRIBUTING.md. Kazakh, Turkmen, Azerbaijani, Serbian and Kurdish are next on the roadmap, and we are looking for native speakers to help.
Linguistic review
Some forms are our best guess and still need a native editor to confirm them. Each one is marked verify in the source:
- Tajik: decimals (
ду бутуну панҷ даҳум) and the Perso-Arabic word list. Dates and times were confirmed by a native speaker. - Persian / Dari:
ممیزvsاعشاریه,درصدvsفیصد, Afghan spellings of Gregorian months,یکمvsاول. - Uzbek: all forms. Open questions:
yuzvsbir yuz,mingvsbir ming, time and date reading, andts→цin Latin → Cyrillic.
If you find a mistake, please open an issue with the correct form. Issues may be written in English, Tajik, Persian, Uzbek or Russian.
Development
pip install -e .
python -m unittest discover -s tests
Python 3.9+ and no dependencies.
Бо забони тоҷикӣ
nutq (нутқ) — китобхонаи кушода (open source) барои забонҳои тоҷикӣ, форсӣ, дарӣ ва ӯзбекӣ. Он ду кор мекунад:
- Табдили хат: тоҷикии кириллӣ ↔ лотинӣ ↔ хати форсӣ (Perso-Arabic), ӯзбекии кириллӣ ↔ лотинӣ.
- Тайёр кардани матн барои нутқ (TTS) ва зеҳни сунъӣ: рақамҳо, санаҳо, вақт, пул, фоиз ва ихтисораҳо бо калима навишта мешаванд. Масалан, «25 $» → «бисту панҷ доллар».
import nutq
nutq.convert("Забони тоҷикӣ", "tg", to="Arab") # 'زبان تاجیکی'
nutq.normalize("Соати 14:30, 15% тахфиф", "tg")
# 'Соати чордаҳу сӣ, понздаҳ фоиз тахфиф'
Ҳар кас метавонад онро бепул истифода барад ва дар рушди он саҳм гузорад. Агар хатое ёбед, масалан калимае, ки бо хати форсӣ нодуруст навишта шудааст, лутфан дар GitHub issue кушоед ё калимаро ба файли arabic_words.tsv илова кунед. Ба забондонҳои ӯзбек, қазоқ, туркман, озарӣ, серб ва курд барои илова кардани забонҳои нав ниёз дорем.
License
MIT
Metadata
Release files for nutq 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nutq-0.1.0.tar.gz | 39.7 kB | With provenance | Details for nutq-0.1.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nutq-0.1.0-py3-none-any.whl | Python 3 | none | any | Details for nutq-0.1.0-py3-none-any.whl |
Total release size: 77.8 kB
Release files / nutq-0.1.0.tar.gz
| Download URL | nutq-0.1.0.tar.gz |
|---|---|
| Size | 39.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
aab65a36a6317e4e07abec1f04f539bcae977075d7a2a642b54ea9a1f090133e
|
|
BLAKE2b-256 checksum How to use checksums |
ab652b4667018b6c9f7f864e0227111fc11e1c9988fb9e6bc8c930692f24e7e5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logRelease files / nutq-0.1.0-py3-none-any.whl
| Download URL | nutq-0.1.0-py3-none-any.whl |
|---|---|
| Size | 38.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
02dcc9f3083637b4450c3a6b1a672338bc9d55ae942c46228ebdd484b5d106a5
|
|
BLAKE2b-256 checksum How to use checksums |
1188b99b385ec992051137bcf2915002ba1ad78af397e9447366e0dfcd7d51af
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logSecurity for nutq 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for nutq-0.1.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 30, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.