Skip to main content

Dialect-aware Basque (Euskara) text-to-IPA phonemizer over the orthography2ipa lattice

Project description

euskaphone

Dialect-aware Basque (Euskara) text-to-IPA phonemizer — a TTS frontend built on the shared orthography2ipa pronunciation lattice. euskaphone is the Basque sibling of tugaphone (Portuguese) and mwl_phonemizer (Mirandese), and is offered to the Basque research and speech-technology community as an open, inspectable, source-cited pipeline.

A dialect is an orthography2ipa Basque lect spec: the spec's grapheme table, allophony and cross-word sandhi produce the dialect's phonology directly — the apical/laminal sibilant contrast, the affricates, Souletin aspiration and /y/. euskaphone adds only the stages orthography2ipa leaves to the caller.

Install

pip install euskaphone

Quickstart

from euskaphone import EuskaPhonemizer

ph = EuskaPhonemizer()
ph.phonemize_sentence("Zazpi katu zuri ikusi ditut.")          # Batua (default)
# 's̻as̻pi katu s̻uɾi ikus̺i ditut'

ph.phonemize_sentence("Hotza egiten du gaur mendian.", "souletin")
# 'hots̻a eɡiten dy ɡauɾ mendian'   (Souletin: aspiration, /y/)

Dialects

Eight lects, selectable by BCP-47 code or by a human-readable alias:

code dialect aliases
eu Standard Basque batua, standard
eu-x-bizkaiera Biscayan biscayan, western
eu-x-gipuzkera Gipuzkoan guipuzcoan, central
eu-x-lapurtera Lapurdian labourdin
eu-x-nafarra-garaia High Navarrese high-navarrese
eu-x-nafarra-beherea Low Navarrese low-navarrese
eu-x-zuberera Souletin souletin, xiberotarra
eu-x-erronkariera Roncalese (†) roncalese

The three things euskaphone adds

1. Vigesimal number normalization (the flagship)

Basque cardinals are base-20: hogei (20), berrogei (40 = 2×20), hirurogei (60), laurogei (80); 30/50/70/90 are the preceding twenty plus ten; and the copulative eta ("and") contracts to -ta on the twenties.

from euskaphone.number_utils import BasqueNumberParser, normalize_numbers

p = BasqueNumberParser("eu")
p.cardinal(31)     # 'hogeita hamaika'   (20-and-11)
p.cardinal(1936)   # 'mila bederatziehun eta hogeita hamasei'
p.ordinal(16)      # 'hamaseigarren'

# case-suffixed numerals and clock time in running text (declension on the
# last element of the numeral phrase)
normalize_numbers("1936ko gerra", "eu")   # '… hogeita hamaseiko gerra'
normalize_numbers("20:00etan", "eu")      # 'hogeietan'

Every base form is cited to Euskaltzaindia Araua 7 (cardinals) and Araua 18 (ordinals), and each is tagged attested-in-source vs derived-by-rule in euskaphone.number_utils (the ATTESTED / DERIVED sets). One notable correction the sources force: Araua 7 records bost (not bortz) for Zuberoa and most of Low Navarre, so euskaphone keeps bost everywhere by default and offers the bortz series only for Lapurdian — null beats a wrong dialect swap. See docs/numbers.md.

2. Code-switch handling

Real Basque text embeds Spanish (Hegoalde), French (Iparralde) and — in the tech/music/media register — English. Word-level detection identifies the embedded material, classifies each contact word per word among es/fr/en, routes it through the orthography2ipa es-ES/fr-FR/en-US lattice, and nativizes the result onto the Basque inventory (project every foreign phone onto its nearest Basque phone — never drop, always project). The contact parameter is auto (per-word detection), es, fr, en, or none.

Detection prefers a small bundled char-Markov language detector (Basque / Spanish / French / English, ~180 KB total, scored by markovonnx; install with euskaphone[langdetect]) and falls back to an orthographic heuristic when the models are unavailable. Basque is the in-language default: a word is routed out of Basque only when a foreign model beats the Basque model by a clear margin (and short, plausibly-native words need orthographic corroboration), so a weak signal never misroutes a native word.

ph.phonemize_sentence("Madrilen Plaza Mayor ikusi dut.", "eu")
# '… plas̻a majoɾ …'  (Spanish routed + nativized: no θ, no stress)

ph.phonemize_sentence("Streaming plataforma berria erabili dugu.")
# 'strimin platafoɾma …'  (English routed + nativized onto the 5-vowel system)

ph.phonemize_sentence("Maison Rouge etxean.", "souletin")
# continental dialect → French contact by default

See docs/codeswitch.md.

3. Lexicon hook + shipped lexicons

register_lexicon(dialect, source) registers a proper-name/loan pronunciation table (the orthography2ipa lexicon contract: a word<TAB>ipa path, URL or hf:// id); a covered word bypasses the lattice.

Two lexicons ship built-in: a curated Euskaltzaindia toponym seed (on by default, EuskaPhonemizer(toponyms=False) to opt out) and an opt-in HiTZ proper-noun overlay (EuskaPhonemizer(lexicon="hitz")) that carries a benchmark circularity caveat. A caller's own lexicon always wins. See docs/lexicons.md.

4. Orthographic normalization

Before the lattice runs, everything written as a symbol, abbreviation, Roman numeral or numeric date is spelled into Basque words (euskaphone.normalize.normalize_text, wired in as the orthography2ipa normalize stage):

from euskaphone.normalize import normalize_text

normalize_text("XX. mendean %20 igo da", "eu")
# 'hogeigarren mendean ehuneko hogei igo da'
normalize_text("Luis XIV.a errege zen", "eu")     # '… hamalaugarrena …'
normalize_text("Sarrera €5eko da", "eu")          # '… bost euroko …'
normalize_text("15/01/2024", "eu")   # 'bi mila eta hogeita lauko urtarrilaren hamabostean'

Roman-numeral ordinals (XX.hogeigarren) and monarch numerals (Luis XIV.ahamalaugarrena), a cited abbreviation list (etab.eta abar), unit/currency/percent symbols with Basque word order and declension (%5 and 5% both → ehuneko bost), and numeric dates — each cited to Euskaltzaindia (Araua 18/37/196/197) and the EIMA Ortotipografia guide. The abbreviation and unit tables are expandable data files (euskaphone/data/*.tsv). See docs/normalization.md.

No homograph subsystem — by design

Basque orthography is near-phonemic: a grapheme's reading is essentially fixed and sense-independent. Unlike tugaphone's Portuguese (which needs bifonia to resolve heterophonic homographs), euskaphone deliberately ships no homograph stage. This is a scope decision, documented so it is not mistaken for a gap.

OVOS plugin

from euskaphone.plugin import EuskaphoneG2PPlugin
EuskaphoneG2PPlugin("souletin").transcribe("kaixo mundua")

Registered under the opm.g2p entry-point group as euskaphone.

How it measures up

euskaphone drives the shared orthography2ipa lattice, so it is only as accurate as that lattice — these numbers measure the lattice, honestly labelled. Run them with python scripts/benchmark.py [--hitz].

gold kind figure
orthography2ipa eu gold (166 rows, 8 lects) regression fixture (same lattice made it) PER 0.0000 — proves the lattice is untouched, not accuracy
WikiPron eus_latn broad independent word gold PER 0.0749, word-acc 0.4563 (full set, 20,115 words)
HiTZ/EHU Wikipedia G2P independent cross-engine (Univ. of the Basque Country) PER 0.1384 folded (3k-sentence sample)

The WikiPron and HiTZ figures are the honest ones: a pure lattice with no lexicon, on proper-name-heavy and raw-Wikipedia text, where transcription conventions and multiple valid pronunciations account for much of the gap. That gap is exactly what the lexicon hook exists to close. Comparable open tools: AhoTTS (the EHU TTS front end) covers Standard Batua only; espeak-ng's eu voice is single-dialect and rule-thin — euskaphone's contribution is the eight-lect coverage, the sourced vigesimal numerals, and the code-switch nativization, over a lattice shared across the whole Iberian family.

License

Apache-2.0.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

euskaphone-0.1.0a2.tar.gz (250.3 kB view details)

Uploaded Source

Built Distribution

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

euskaphone-0.1.0a2-py3-none-any.whl (237.2 kB view details)

Uploaded Python 3

File details

Details for the file euskaphone-0.1.0a2.tar.gz.

File metadata

  • Download URL: euskaphone-0.1.0a2.tar.gz
  • Upload date:
  • Size: 250.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for euskaphone-0.1.0a2.tar.gz
Algorithm Hash digest
SHA256 a45463255e8bbb928eeba5058d5cb54b4a801d19fe0db486cdbf16115177ea49
MD5 ccb2bac25956b63daa16417761936cec
BLAKE2b-256 eef44e5ae8a139429ce98c5204e55b62b04ce0d1e8cbcaacd7b07183ad24a08b

See more details on using hashes here.

File details

Details for the file euskaphone-0.1.0a2-py3-none-any.whl.

File metadata

  • Download URL: euskaphone-0.1.0a2-py3-none-any.whl
  • Upload date:
  • Size: 237.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for euskaphone-0.1.0a2-py3-none-any.whl
Algorithm Hash digest
SHA256 de075815a375251f20187ceb226e2ab3f8a412bccfd28ac4ca38d2c82dc38f32
MD5 19a6ec8f6e26831008ab9e8ecac9fa96
BLAKE2b-256 a0d58138aa579af77f5858996383a367bf03b847964606e801f8b5371626aeb8

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 Pingdom Monitoring Sentry Error logging StatusPage Status page