This release is a pre-release and may not be stable for production use.
tugaphone — dialect-aware Portuguese phonemizer
tugaphone converts Portuguese text to IPA across all five Lusophone dialect groups. It combines a curated phonetic lexicon, meaning-based heterophone resolution via bifonia, and a scientifically- grounded regional-accent layer.
O gato dorme.
pt-PT → ˈu gˈa·tu ˈdoɾ·mɨ
pt-BR → ˈu gˈa·tʊ ˈdoɾ·mɪ
pt-AO → ˈu gˈa·tʊ ˈdoɾ·me
pt-MZ → ˈu gˈa·tu ˈdoɾ·me
pt-TL → ˈu gˈa·tʊ ˈdoɾ·me
Install
pip install tugaphone
30-second quick start
from tugaphone import TugaPhonemizer
ph = TugaPhonemizer()
print(ph.phonemize_sentence("O gato dorme.", "pt-PT"))
# ˈu gˈa·tu ˈdoɾ·mɨ ˈ···
TugaPhonemizer() loads the lexicon once; then call phonemize_sentence(text, lang) as many times as you like. Output is a space-separated phoneme string —
one token per word — with ˈ marking primary stress and · marking syllable
boundaries.
Features
Five dialect inventories
| 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ˈũj·tu ˈõ·tẽ
# pt-BR → ʃo·ˈvew mwˈĩ·tʊ ˈõ·tẽ
# pt-AO → ʃo·ˈvew mˈũjn·tʊ ˈõ·tẽ
# pt-MZ → ʃu·ˈvew mˈũj·tu ˈõ·tẽ
# pt-TL → ʃo·ˈvew mˈuj·tʊ ˈõ·tẽ
Homograph disambiguation
Heterophonic homographs are resolved by meaning via bifonia: sede thirst vs HQ, forma mould vs shape, gosto noun vs verb. bifonia inserts open/closed-vowel diacritics that the grapheme rules read directly, so the same spelling can map to different pronunciations depending on sentence context.
print(ph.phonemize_sentence("Eu gosto de música.")) # verb → ˈgɔʃ·tu
print(ph.phonemize_sentence("Tenho bom gosto.")) # noun → ˈgoʃ·tu
Sub-regional accents
RegionalTransforms presets layer phonological rules on top of any dialect.
Rules are grounded in published phonology (Cintra 1971; ALEPG). Every preset
is reachable by its BCP-47 private-use code:
# Porto: stressed /o/ → [uo] (rising diphthong)
print(ph.phonemize_sentence("O vinho é muito bom.", "pt-PT-x-porto"))
# ˈu bˈi·ɲu ˈɛ mˈũj·tu bˈuõ ˈ···
# Açores: stressed /u/ → [y], l-palatalisation
print(ph.phonemize_sentence("O vinho é muito bom.", "pt-PT-x-azores"))
# ˈy vˈi·ɲu ˈɛ mˈỹj·tu bˈõ ˈ···
from tugaphone import list_dialects
print(list_dialects()) # all 20 registered codes
Available presets: NorthernDialect, PortoDialect, MinhoDialect,
BragaDialect, FamalicaoDialect, FafeDialect, TrasMontanoDialect,
CoimbraDialect, AlentejoDialect, AlgarveDialect, MadeiraDialect,
AzoresDialect — importable from tugaphone.regional and passable as
regional_dialect=, which overrides the code-derived preset.
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
Syllabification is handled by silabificador,
registered as an orthography2ipa syllabifier plugin. Stress detection delegates to
orthography2ipa's declarative StressRules.
Rules-only mode
Pass an IRREGULAR_WORDS-emptied dialect inventory to bypass the lexicon and use
only grapheme rules — useful for testing rule coverage or synthesising unknown words.
orthography2ipa plugin interface
TugaphoneG2PPlugin implements orthography2ipa's G2PPlugin interface;
SilabificadorSyllabifier implements its SyllabifierPlugin interface and
is registered at the orthography2ipa.syllabify entry point.
from tugaphone.plugin import TugaphoneG2PPlugin
p = TugaphoneG2PPlugin(lang="pt-BR")
print(p.transcribe("o gato dorme")) # ˈu gˈa·tʊ ˈdoɾ·mɪ
IPA is built word-by-word (no cross-word sandhi)
tugaphone builds a sentence's IPA from a character-level cascade: each
CharToken.ipa composes into a GraphemeToken, graphemes into a
WordToken.ipa, and Sentence.ipa is those word IPAs joined with spaces —
each word transcribed independently. tugaphone does not route generation
through orthography2ipa's pronunciation lattice (G2P.ipa_lattice) or its
G2P.transcribe; it consumes only o2i's shared primitives (the
PhonetokTokenizer grapheme trie, vowels classification, StressRules, and
LanguageSpec loading) and applies its own dialect grapheme rules.
A consequence is that genuinely cross-word phonology is not modelled on the
generation path. Standard European Portuguese external /s-sandhi — a
word-final coda /s/ (isolated [ʃ]) voicing before a vowel-initial next word
(os amigos → [ˈuz ɐˈmiɡuʃ], Mateus & d'Andrade 2000) — is not applied
in the base pt-PT output (os stays [ˈuʃ]). The southern/insular presets'
sibilant_voicing_sandhi is a per-token approximation: it voices a token's own
final [ʃ]→[ʒ] when the word ends in <s>, with no visibility of the
following word.
orthography2ipa (≥1.70) now carries this cross-word phonology natively — a
declarative sandhi_rules set on the pt-PT spec (PT_FINAL_S_PREVOCALIC_VOICE
→ [z]; pt-PT-x-algarve/acores → [ʒ]) run through its SandhiEngine, and
a SentenceRescorer / SentenceLattice sentence-context seam for
boundary-aware rewrites. tugaphone cannot consume either today because neither
its per-word IPA nor its lattice flows through o2i's G2P. Adopting the seam is
a scoped follow-up (a "B6 stage-2" refactor) that routes sentence-level
generation through o2i so cross-word sandhi is modelled once, upstream, instead
of re-approximated per token. See docs/advanced.md.
Sibling libraries
tugaphone is part of the TigreGotico Portuguese NLP stack:
| Library | Role |
|---|---|
| tugalex | Phonetic lexicon |
| silabificador | Syllabifier |
| bifonia | Heterophone sense disambiguation |
| orthography2ipa | G2P plugin base + stress rules |
Documentation
- docs/quickstart.md — install, first call, dialect overview
- docs/dialects.md — five inventories and sub-regional accent presets
- 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 Sentence → Word → Grapheme → Character model
- docs/advanced.md — accents, serialization, integration
- docs/benchmarking.md — the gold benchmark: rules-only PER per dialect, offline in CI
- docs/scoreboard.md — current accuracy per dialect
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-0.9.2a1.tar.gz.
File metadata
- Download URL: tugaphone-0.9.2a1.tar.gz
- Upload date:
- Size: 106.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 |
ca281b732438f59fbc7ad8593d5639b8d0d1de9027a3c076653e9e52ae3da6f2
|
|
| MD5 |
8d352433d657973bab19d0ff31929d67
|
|
| BLAKE2b-256 |
aeb1cf531d091759e42783cc442012fda4404b436c66fa7409372cc94c26eb51
|
File details
Details for the file tugaphone-0.9.2a1-py3-none-any.whl.
File metadata
- Download URL: tugaphone-0.9.2a1-py3-none-any.whl
- Upload date:
- Size: 83.7 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 |
220b083146fca89e8a60ef6d0aef1dfe985149c8240fb48aa5dbb1178c7cb1e5
|
|
| MD5 |
03de2b01fdc969ac60445b68444f5338
|
|
| BLAKE2b-256 |
313f4eae55fd9be4ab0509c6e98b3e93b431da46177f538f8c892917f259e7d8
|