Skip to main content
Pre-release

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


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

tugaphone-0.8.0a1.tar.gz (97.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tugaphone-0.8.0a1-py3-none-any.whl (78.7 kB view details)

Uploaded Python 3

File details

Details for the file tugaphone-0.8.0a1.tar.gz.

File metadata

  • Download URL: tugaphone-0.8.0a1.tar.gz
  • Upload date:
  • Size: 97.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tugaphone-0.8.0a1.tar.gz
Algorithm Hash digest
SHA256 10457ae477b7b8e3b1c12e71e9139d29c9ae77a6ecfb08f2110e9bfe5837fa35
MD5 022e96210d40e0742b102df1ab8be6b4
BLAKE2b-256 013daab5d5b9f41cdca78c499b84944ff71a95aa0a45096431a08d95c2881102

See more details on using hashes here.

File details

Details for the file tugaphone-0.8.0a1-py3-none-any.whl.

File metadata

  • Download URL: tugaphone-0.8.0a1-py3-none-any.whl
  • Upload date:
  • Size: 78.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for tugaphone-0.8.0a1-py3-none-any.whl
Algorithm Hash digest
SHA256 508c98ea406dab5512245fac3b4ad4487fae9f1ae19d3d37e7a02304107dd94e
MD5 f8308468f94d6e0b2207b1b56bb5ddbe
BLAKE2b-256 96b434c0db3ea8727f6768a70bb7b34cacac78c965f0bf0028f4a25f8e783a34

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page