This release is a pre-release and may not be stable for production use.
tugaphone — dialect-aware Portuguese phonemizer
tugaphone turns Portuguese text into IPA, and it does it per Lusophone dialect. Give it a sentence and a dialect code, get back a phoneme string with stress marks.
O gato dorme.
pt-PT → ˈo ˈgatu ˈdɔɾmɨ
pt-BR → ˈu ˈgatʊ ˈdoɾmi
pt-AO → ˈʊ ˈgatʊ ˈdɔʁmɨ
pt-MZ → ˈu ˈgatu ˈdɔrme
pt-TL → ˈo ˈgatʊ ˈdɔrme
Under the hood it drives the orthography2ipa candidate lattice: a dialect is an orthography2ipa lect spec, and the spec's grapheme table, allophone rules and cross-word sandhi produce that dialect's phonology directly. tugaphone adds the stages orthography2ipa leaves to the caller — a phonetic lexicon, meaning-based homograph resolution, and gender- and scale-aware number expansion — wired through orthography2ipa's own extension points. See docs/architecture.md.
Install
pip install tugaphone
Its runtime dependencies (orthography2ipa, silabificador, tugalex,
bifonia, unicode-rbnf) install automatically. The phonetic lexicon rides in
through tugalex.
30-second quick start
from tugaphone import TugaPhonemizer
ph = TugaPhonemizer()
print(ph.phonemize_sentence("O gato dorme.", "pt-PT"))
# ˈo ˈgatu ˈdɔɾmɨ
Construct TugaPhonemizer() once, then call phonemize_sentence(text, lang) as
often as you like. The result is a space-separated phoneme string, one token per
word, with ˈ marking primary stress. lang selects the orthography2ipa lect
spec, so it changes the phonology, not just the spelling.
Digits are best spelled out first, with gender agreement:
from tugaphone.number_utils import normalize_numbers
text = normalize_numbers("comprei 2 casas") # 'comprei duas casas'
print(ph.phonemize_sentence(text, "pt-PT"))
Why tugaphone
Most Portuguese G2P you can reach for treats Portuguese as one or two varieties. tugaphone's reason to exist is dialect granularity: one API that spans the whole Lusophone space and, within European Portuguese, a set of sub-regional accents.
| Tool | Portuguese coverage | Notes |
|---|---|---|
| espeak-ng | pt (European) + pt-br (Brazilian) |
Tiny, fast, rule-based, ~100 languages, battle-tested as a TTS front-end. Two Portuguese varieties only; no African/Asian Lusophone, no sub-regional accents. |
| phonemizer (bootphon) | via espeak-ng | A backend wrapper; for Portuguese it delegates to espeak-ng, so the same two varieties. Needs the espeak binary. |
| Single-variety Portuguese toolkits (e.g. Brazilian-focused phonetic transcribers) | one national variety | Strong within their variety; not built to cover the full Lusophone range from one interface. |
| tugaphone | 41 lects: five national standards + European, Brazilian, African, Asian and other varieties | Pure Python, IPA output with stress, meaning-based homograph resolution, one API across the whole Lusophone space. |
What tugaphone buys you over the coarse options:
- 41 Portuguese-family lects reachable by BCP-47 code — the five national
standards (
pt-PT,pt-BR,pt-AO,pt-MZ,pt-TL) plus European and Brazilian sub-regional varieties and the African, Asian and other lects. - Meaning-based homograph resolution — sede thirst vs headquarters, gosto verb vs noun — via bifonia.
- Gender- and scale-aware number expansion (long scale for
pt-PT, short scale forpt-BR). - A phonology-accurate core — each dialect's sounds come from its orthography2ipa lect spec, not from a post-hoc string-edit layer.
Honest trade-offs: tugaphone is Portuguese-only and younger than espeak-ng, which covers far more languages and years of field use. Its accuracy against the per-lect gold is measured openly — see docs/benchmarking.md.
Features
Dialect coverage
The five national standards, plus European, Brazilian, African, Asian and other
sub-regional lects — 41 codes in all, from list_dialects():
| Code | Region |
|---|---|
pt-PT |
European Portuguese — heavy vowel reduction, post-alveolar fricatives, uvular /ʁ/ |
pt-BR |
Brazilian Portuguese — fuller vowels, /t d/ palatalisation, l-vocalisation |
pt-AO |
Angolan Portuguese — moderate reduction, alveolar trill, Bantu substrate |
pt-MZ |
Mozambican Portuguese — similar to European with regional variation |
pt-TL |
Timorese Portuguese — conservative pronunciation, Tetum substrate |
for code in ["pt-PT", "pt-BR", "pt-AO", "pt-MZ", "pt-TL"]:
print(code, "→", ph.phonemize_sentence("Choveu muito ontem.", code))
# pt-PT → ʃuˈvew ˈmũjtu ˈõtɐ̃j
# pt-BR → ʃoˈvew ˈmwĩtʊ ˈõtẽj
# pt-AO → ʃoˈvew ˈmũjntʊ ˈõntẽj
# pt-MZ → ʃoˈvew ˈmũjtu ˈõtẽj
# pt-TL → ʃoˈvew ˈmujtʊ ˈõntɐ̃j
The European sub-regional lects (pt-PT-x-porto, -braga, -trasosmontes,
-madeira, -acores, …), the Brazilian ones (pt-BR-x-sp, -rj, -caipira,
-bahia, …) and the rest are all reachable the same way. See
docs/dialects.md for the full list and the legacy aliases.
Homograph disambiguation
Heterophonic homographs are resolved by meaning via bifonia: sede thirst vs headquarters, forma mould vs shape, gosto noun vs verb. bifonia inserts open/closed-vowel diacritics during the pipeline's normalization stage, before the lattice transcribes the sentence, so the same spelling maps to different pronunciations depending on sentence context.
print(ph.phonemize_sentence("Eu gosto de música.")) # verb → ˈew ˈɡɔʃtu ˈdɨ ˈmuzikɐ
print(ph.phonemize_sentence("Tenho bom gosto.")) # noun → ˈtɛɲu ˈbõ ˈɡoʃtu
Sub-regional accents
Sub-regional accents are lects like any other — select one by its BCP-47
private-use code. Its phonology (betacism, rising diphthongs, palatalization,
/u/ fronting, coda-sibilant sandhi, …) is encoded in the orthography2ipa lect
spec, so no extra argument is needed:
# Porto: rising diphthongs, betacism (/v/ → [b])
print(ph.phonemize_sentence("O vinho é muito bom.", "pt-PT-x-porto"))
# ˈwo ˈbiɲu ˈjɛ ˈmujtu ˈbõ
# Trás-os-Montes: <ch> → [tʃ], betacism
print(ph.phonemize_sentence("A chave.", "pt-PT-x-trasosmontes"))
# ˈɐ ˈtʃabɨ
from tugaphone import list_dialects
print(list_dialects()) # all 41 registered lect codes
Legacy tugaphone accent codes resolve as aliases (pt-PT-x-azores →
pt-PT-x-acores, pt-BR-x-sao-paulo → pt-BR-x-sp, …). See
docs/dialects.md.
Number normalization
Digits are spelled out with gender agreement and long/short scale per dialect:
from tugaphone.number_utils import normalize_numbers
normalize_numbers("vou comprar 1 casa") # 'vou comprar uma casa'
normalize_numbers("vou adotar 1 cão") # 'vou adotar um cão'
normalize_numbers("comprei 2 casas") # 'comprei duas casas'
Syllabification and stress
Stress and the dialect's phonology come from the orthography2ipa lect spec;
syllabification is supplied by
silabificador, wired in as
orthography2ipa's syllabify plugin.
orthography2ipa plugin interface
TugaphoneG2PPlugin implements the orthography2ipa G2P plugin interface
(transcribe, transcribe_word, language_codes), so a framework that loads
phonemizers through that interface can drive tugaphone:
from tugaphone.plugin import TugaphoneG2PPlugin
p = TugaphoneG2PPlugin(lang="pt-BR")
print(p.transcribe("o gato dorme")) # ˈu ˈgatʊ ˈdoɾmi
Architecture: relationship to orthography2ipa
tugaphone phonemizes by driving the shared o2i candidate lattice. A dialect
is an o2i lect spec: phonemize_sentence(text, lang) resolves lang to a
lect code and runs orthography2ipa.G2P(lect).transcribe(text). The spec's
grapheme table, allophone_rules and cross-word sandhi_rules produce the
dialect's phonology — including genuinely cross-word processes like
coda-sibilant voicing sandhi — with no string-transform pass after
transcription.
tugaphone contributes only the stages o2i leaves to the caller, wired through o2i's own extension points:
| Concern | Owner |
|---|---|
| Base phonology, dialect phenomena, sandhi, stress | orthography2ipa lect spec |
| Number / ordinal verbalization | tugaphone (number_utils, via the normalize stage) |
| Sense-based homograph marking | tugaphone (bifonia, via the normalize stage) |
| Curated pronunciation lexicon | tugaphone (tugalex, via register_lexicon) |
| Syllabification | tugaphone (silabificador, via the syllabify plugin) |
The lexicon overlay applies only to the lects whose lexical tradition matches a
tugalex region (pt-PT/pt-PT-x-lisbon, pt-BR/pt-BR-x-rj, pt-BR-x-sp,
pt-AO, pt-MZ, pt-TL); every other lect is pure lattice.
tugaphone.tokenizer and tugaphone.dialects remain as a token-tree
linguistic feature API (manner, place, voicing, syllable roles, CV
skeletons) and the rules-only benchmark baseline — not the phonemization path.
See docs/architecture.md and
docs/tokenizer.md.
Sibling libraries
tugaphone is part of the TigreGotico Portuguese NLP stack:
| Library | Role |
|---|---|
| tugalex | Phonetic lexicon |
| silabificador | Syllabifier |
| bifonia | Heterophone sense disambiguation |
| orthography2ipa | The candidate lattice and the Portuguese lect specs |
Documentation
- docs/quickstart.md — install, first call, dialect overview
- docs/architecture.md — the lattice core and the caller-owned layers
- docs/dialects.md — the 41 lect codes, aliases and lexicon overlay
- docs/homographs.md — meaning-based disambiguation
- docs/numbers.md — number normalization and gender agreement
- docs/api.md — full class and function reference
- docs/tokenizer.md — the token-tree feature model
- docs/advanced.md — the pipeline internals and integration
- docs/benchmarking.md — the TTS-gold and rules-only benchmarks
- docs/scoreboard.md — accuracy per dialect
- examples/ — runnable scripts
License
Apache License 2.0. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tugaphone-1.0.0a1.tar.gz.
File metadata
- Download URL: tugaphone-1.0.0a1.tar.gz
- Upload date:
- Size: 80.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3a737b62448be11d074724f684a27a5b2cfac5be4d6961bbfe7b18bc27f9724d
|
|
| MD5 |
d10cc227f0c77b37dcc1ccce036bd9a6
|
|
| BLAKE2b-256 |
350c6cc7eda6b4845fd11fafd436f98de506d805d7a3612661ed744a0fbe17c9
|
File details
Details for the file tugaphone-1.0.0a1-py3-none-any.whl.
File metadata
- Download URL: tugaphone-1.0.0a1-py3-none-any.whl
- Upload date:
- Size: 66.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
141f7b5e5afbf4ec79501abb212bdd0c963a026484f9805fb4a4bb680737aa59
|
|
| MD5 |
f8f07ed945612834e673dd04af05fe81
|
|
| BLAKE2b-256 |
6895d2cd24e6cdfccd5a3adf69bd635679815cb76244ee488e4274bc6a239d86
|