Skip to main content

turkificate

A Turkish text normalization library. It converts numbers, dates, times, phone numbers, Turkish identity numbers and IBANs, company names, technology terms, abbreviations, currencies, percentages, fractions, ranges, Roman ordinals and symbols into their written Turkish form. Productive suffix harmony is supported for common expressions. Built for TTS pre-processing, search indexing and text cleaning.

"The language is the core of our being - Noam Chomsky"

No external dependencies — pure standard library.

Installation

pip install turkificate

Or from a local checkout:

pip install -e .

Quick start

import turkificate

turkificate.turkificate("Dr. Ahmet 15.03.2024'te %25 indirimle 1.250 TL ödedi.")
# "doktor Ahmet on beş Mart iki bin yirmi dörtte yüzde yirmi beş
#  indirimle bin iki yüz elli lira ödedi."

turkificate() is the main function; normalize() is a kept alias for the same call.

The output is intentionally Turkish (e.g. yüz, bin, Mart) — that is the whole point of the library. Only the code, API and docs are in English.

Selecting concepts

from turkificate import TurkishNormalizer

tn = TurkishNormalizer(features=["numbers", "dates"])
tn.normalize("Saat 14:30, fiyat 99,90 TL")
# "Saat 14:30, fiyat doksan dokuz virgül doksan TL"  (times & currency untouched)

Enable or disable company/brand name normalization through the same feature list:

TurkishNormalizer(features=["companies"]).normalize("Turkcell ve Vodafone")
# "türksel ve vodafon"

TurkishNormalizer(features=["companies"]).normalize("Google, Apple ve Microsoft")
# "gugıl, epıl ve maykrosoft"

TurkishNormalizer(features=["currency"]).normalize("Turkcell 100 TL")
# "Turkcell yüz lira"  (company names untouched)

Technology term normalization is also selectable:

TurkishNormalizer(features=["technology_terms"]).normalize("GPT, FP16 ve API")
# "ci pi ti, ef pi on altı ve ey pi ay"

TurkishNormalizer(features=["numbers"]).normalize("GPT ve 2")
# "GPT ve iki"  (technology terms untouched)

Normalize everything

Pass nothing (the default), or the explicit "all" keyword:

TurkishNormalizer()                          # all concepts (default)
TurkishNormalizer(features="all")            # all concepts
TurkishNormalizer(features=["all"])          # all concepts
TurkishNormalizer(features=turkificate.ALL)  # all concepts

List available concepts with turkificate.available_features().

Concept Description Example
emails e-mail addresses info@firma.com → info et firma nokta com
urls URLs https://firma.com/detay → firma nokta com bölü detay
phones Turkish phone numbers 0532 123 45 67 → sıfır beş yüz otuz iki yüz yirmi üç kırk beş altmış yedi
turkish_ids valid Turkish identity numbers 10000000146 → bir sıfır sıfır sıfır sıfır sıfır sıfır sıfır bir dört altı
companies company and brand names Google → gugıl, Garanti BBVA → Garanti bebevea
technology_terms AI, ML and common technology terms GPT → ci pi ti, FP16 → ef pi on altı
ibans checksum-valid Turkish IBANs TR330006100519786457841326 → te re üç üç sıfır…
numbers integer / decimal / signed 3,5 → üç virgül beş
dates DD.MM.YYYY and ISO dates 2024-03-15 → on beş Mart iki bin yirmi dört
times HH:MM(:SS) 14:30 → on dört otuz
percent percent sign %50 → yüzde elli
currency currencies 100 TL → yüz lira
fractions fractions 2/3'ü → iki bölü üçü
ranges numeric ranges / scores 10-15 → on tire on beş
ordinals ordinal numbers 5'inci → beşinci, 3. kat → üçüncü kat
roman_numerals contextual Roman ordinals IV. Murat → dördüncü Murat
units units of measure 42 km → kırk iki kilometre, -3 °C → eksi üç derece
abbreviations lexical abbreviations Dr. → doktor
symbols single-character symbols & → ve, × → çarpı, ÷ → bölü
whitespace whitespace cleanup (always the final step)

Per-concept options

tn = TurkishNormalizer(options={
    "times":   {"prefix_hour":     True},  # 09:05 → "saat dokuz beş"
    "ordinals": {"period_ordinals": False}, # disable "3. kat" → "üçüncü kat" (on by default)
})

Custom pronunciation dictionary

Pass a per-instance dictionary to override bundled company and technology pronunciations, or to add application-specific terms. Entries match complete words or phrases case-insensitively and run before bundled lexical normalizers.

from turkificate import TurkishNormalizer

tn = TurkishNormalizer(lexicon={
    "OpenAI": "open ey ay",
    "Acme Labs": "ekmi lebs",
})
tn.normalize("OpenAI ve Acme Labs")
# "open ey ay ve ekmi lebs"

For a one-off call, use turkificate.normalize_with_lexicon(text, lexicon).

Per-concept helpers

turkificate.normalize_numbers("3 elma")               # "üç elma"
turkificate.normalize_emails("info@firma.com")         # "info et firma nokta com"
turkificate.normalize_urls("https://firma.com/detay")  # "firma nokta com bölü detay"
turkificate.normalize_phones("0532 123 45 67")
turkificate.normalize_turkish_ids("10000000146")
turkificate.normalize_companies("Google ve Apple")       # "gugıl ve epıl"
turkificate.normalize_technology_terms("GPT ve API")     # "ci pi ti ve ey pi ay"
turkificate.normalize_ibans("TR330006100519786457841326")
turkificate.normalize_dates(...)
turkificate.normalize_currency(...)
# normalize_times, normalize_percent, normalize_fractions, normalize_ranges,
# normalize_ordinals, normalize_roman_numerals, normalize_units,
# normalize_abbreviations, normalize_symbols

Direct number engine:

from turkificate import integer_to_words, integer_to_ordinal, read_number
integer_to_words(1_000_000)   # "bir milyon"
integer_to_ordinal(4)         # "dördüncü"
read_number("1.234,5")        # "bin iki yüz otuz dört virgül beş"

Adding a new concept

Subclass Normalizer and register it with @register:

from turkificate import Normalizer, register
import re

@register
class EmojiNormalizer(Normalizer):
    name = "emoji"

    def configure(self, **opts):
        self._re = re.compile(r":\)")

    def apply(self, text):
        return self._re.sub("gülen yüz", text)

It is now usable via TurkishNormalizer(features=["emoji", ...]) or "all".

Architecture

  • Strategy — each concept is an independent class with a common Normalizer interface.
  • Pipeline (Chain) — normalizers run in order; number-bearing concepts run before the bare numbers concept to avoid double conversion.
  • Registry + Facade — concepts are selected by name; TurkishNormalizer composes them.

Optimization: every regex is compiled once in the constructor; the abbreviation, unit and currency dictionaries are compiled into a single alternation regex; the number-to-words engine is lru_cache-d; and because apply is pure, a single instance is reused across thousands of calls.

Ambiguity-aware results

normalize() preserves the original eager string API. For callers that need to identify a potentially ambiguous dotted number, use normalize_detailed():

from turkificate import TurkishNormalizer, NormalizationAmbiguityError

tn = TurkishNormalizer()
tn.normalize_detailed("Sürüm 1.234 hazır.", ambiguity_policy="preserve")
# NormalizationResult(text='Sürüm 1.234 hazır.', complete=False, issues=(...))

# Existing behaviour remains available explicitly.
tn.normalize_detailed("Sürüm 1.234 hazır.", ambiguity_policy="eager")
# "Sürüm bin iki yüz otuz dört hazır." with an ambiguity issue

try:
    tn.normalize_detailed("Sürüm 1.234 hazır.", ambiguity_policy="reject")
except NormalizationAmbiguityError:
    pass

Issues use zero-based Python character offsets in the original text. Current ambiguity detection intentionally covers bare dotted thousands forms; the API is designed to gain further ambiguity checks without changing normalize().

Known limits (roadmap)

  • The period ordinal form (3. kat → "üçüncü kat") is enabled by default. It requires whitespace + a non-whitespace character after the dot, so sentence-final periods are safe. Disable with period_ordinals=False.
  • The number engine is one-way; the reverse direction (words → digits) is not yet implemented.
  • The suffix layer handles common case, possessive and derivational endings; it is not a full Turkish morphological analyser.
  • Roman numerals are deliberately normalized only in contextual ordinal forms such as IV. Murat; bare IV remains unchanged.
  • Dates are validated against the Gregorian calendar; invalid values such as 31.04.2026 and 29.02.2025 remain unchanged.

Development

pip install -e ".[dev]"
pytest

Publishing

This repo ships a GitHub Actions workflow (.github/workflows/publish.yml) that publishes to PyPI via Trusted Publishing (no API tokens) when you create a GitHub Release. See the project README section below or the PyPI docs on trusted publishers.

License

MIT — see LICENSE.

Metadata

Release files for turkificate 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for turkificate 0.2.0
File Size Uploaded Provenance Actions
turkificate-0.2.0.tar.gz 28.9 kB With provenance Details for turkificate-0.2.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for turkificate 0.2.0
File Interpreter ABI Platform Actions
turkificate-0.2.0-py3-none-any.whl Python 3 none any Details for turkificate-0.2.0-py3-none-any.whl

Total release size: 57.8 kB

Release files / turkificate-0.2.0.tar.gz

Download URL turkificate-0.2.0.tar.gz
Size 28.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e8648e79fec0f458702b18533c617a7a6463528957f55df93c2b1c3cc13d1ec8
BLAKE2b-256 checksum
How to use checksums
9e3b350ee999c31c69d831dad0cd007644d5478e763b302529657a0276f164b9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 6, 2026.

Transparency log

Release files / turkificate-0.2.0-py3-none-any.whl

Download URL turkificate-0.2.0-py3-none-any.whl
Size 28.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
499b9f64a48197caaa18a10b5184ae78490ad0ea4518a62be324cd534a9c4f41
BLAKE2b-256 checksum
How to use checksums
f24fe083cb92b16a7006f910f97a8283fcca4dcda76b2f6226bec985da2242c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 6, 2026.

Transparency log

Security for turkificate 0.2.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.

Select from 2 files

Attestation for turkificate-0.2.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 6, 2026.

Transparency log

A 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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page