Exact Round-Trip Indic Transliteration — Python 3.12+ port
This directory is a Python port of the supplied Dart implementation. It keeps the Dart package's default extendedIndic behavior and ports all public conversion directions:
- Latin/IAST → Devanagari
- Latin/IAST → Gujarati
- Latin/IAST → plain English/Hunterian
- Devanagari → canonical Latin/IAST
- Gujarati → canonical Latin/IAST
- metadata-backed exact source recovery
- exact round-trip result envelopes and JSON serialization
The runtime has no third-party dependency. Python's standard unicodedata module supplies NFC/NFD normalization and Unicode mark categories.
Install
cd python
python3.12 -m venv .venv
source .venv/bin/activate
python -m pip install -e .
For tests:
python -m pip install -e '.[dev]'
python -m pytest
Basic conversions
from lipimala import (
to_devanagari_from_iast,
to_gujarati_from_iast,
to_plain_english_from_iast,
to_canonical_iast_from_devanagari,
to_canonical_iast_from_gujarati,
)
assert to_devanagari_from_iast('Kṛṣṇa') == 'कृष्ण'
assert to_gujarati_from_iast('Kṛṣṇa') == 'કૃષ્ણ'
assert to_plain_english_from_iast('Kṛṣṇa') == 'Krishna'
assert to_canonical_iast_from_devanagari('कृष्ण') == 'kṛṣṇa'
assert to_canonical_iast_from_gujarati('કૃષ્ણ') == 'kṛṣṇa'
Exact original-key recovery
Visible Brahmic output is many-to-one. For example, aliases, case, and NFC/NFD forms can render identically. Exact recovery therefore uses the same checksummed invisible Unicode-tag trailer as the Dart implementation.
from lipimala import (
IastToDevanagariOptions,
IastToGujaratiOptions,
to_devanagari_from_iast,
to_gujarati_from_iast,
to_exact_iast_from_devanagari,
to_exact_iast_from_gujarati,
)
source = 'Kṛṣṇa / Kr̥ṣṇa / ḫāna / ṣ́akti'
devanagari = to_devanagari_from_iast(
source,
IastToDevanagariOptions(embed_exact_source_metadata=True),
)
gujarati = to_gujarati_from_iast(
source,
IastToGujaratiOptions(embed_exact_source_metadata=True),
)
assert to_exact_iast_from_devanagari(devanagari) == source
assert to_exact_iast_from_gujarati(gujarati) == source
The metadata stores the exact UTF-16LE code-unit sequence and preserves:
- case
- precomposed versus decomposed spelling
- combining-mark order
- aliases
- punctuation and whitespace
- supplementary Unicode characters
- unpaired UTF-16 surrogates through Python's
surrogatepasshandling
The trailer is rejected if either the visible rendering or encoded source payload is modified.
Exact Round-Trip envelope
import json
from lipimala import (
TransliterationResult,
to_plain_english,
)
result = to_plain_english('Kṛṣṇa ā́tman ḷa')
assert result.restore_original() == 'Kṛṣṇa ā́tman ḷa'
encoded = json.dumps(result.to_json(), ensure_ascii=False)
restored = TransliterationResult.from_json(json.loads(encoded))
assert restored.restore_original() == result.original
Devanagari ↔ Gujarati Direct Converter
This package includes a direct converter between Devanagari and Gujarati.
Canonical visible conversion
from lipimala.deva_gujr_converter import (
to_canonical_gujarati_from_devanagari,
to_canonical_devanagari_from_gujarati,
)
print(to_canonical_gujarati_from_devanagari('कृष्ण')) # કૃષ્ણ
print(to_canonical_devanagari_from_gujarati('કૃષ્ણ')) # कृष्ण
Exact exact round-trip round trip
The visible Gujarati and Devanagari repertoires are not one-to-one. Therefore, exact round-trip recovery uses a checksummed Unicode-tag trailer.
from lipimala.deva_gujr_converter import (
IndicScriptConversionOptions,
to_canonical_gujarati_from_devanagari,
to_exact_devanagari_from_gujarati,
)
source = 'ऄ ऎ ऍ ॲ ऒ ऑ ॵ ळ ऴ ग़ ॻ ड़ ॸ ॾ'
tagged_gujarati = to_canonical_gujarati_from_devanagari(
source,
IndicScriptConversionOptions(embed_exact_source_metadata=True),
)
assert to_exact_devanagari_from_gujarati(tagged_gujarati) == source
The opposite Gujarati → Devanagari → exact Gujarati direction uses to_exact_gujarati_from_devanagari.
Smart exact-or-canonical APIs
These recover a correctly typed exact source trailer if present, and otherwise fall back to canonical visible conversion:
to_devanagari_from_gujarati(text, options)to_gujarati_from_devanagari(text, options)
Strict exact APIs throw when typed metadata is absent or damaged:
to_exact_devanagari_from_gujarati(text)to_exact_gujarati_from_devanagari(text)
Generate the verification outputs
Run from this directory after installation:
python3 -m tools.latn_iast_transliteration_verification.latn_iast_to_deva_test > latn_iast_to_deva_output.txt
python3 -m tools.latn_iast_transliteration_verification.latn_iast_to_gujr_test > latn_iast_to_gujr_output.txt
python3 -m tools.latn_iast_transliteration_verification.latn_iast_transcription_test > latn_iast_transcription_output.txt
python3 -m tools.latn_iast_transliteration_verification.deva_to_latn_iast_test > deva_to_latn_iast_output.txt
python3 -m tools.latn_iast_transliteration_verification.gujr_to_latn_iast_test > gujr_to_latn_iast_output.txt
python3 -m tools.latn_iast_transliteration_verification.deva_to_gujr_test > deva_to_gujr_output.txt
python3 -m tools.latn_iast_transliteration_verification.gujr_to_deva_test > gujr_to_deva_output.txt
Verification performed
The automated parity suite compares the Python implementation against the five supplied Dart-generated output files:
- 497 Latin → Devanagari cases
- 497 Latin → Gujarati cases
- 497 Latin → plain-English cases
- 497 Devanagari → canonical IAST cases
- 497 Gujarati → canonical IAST cases
That is 2,485 exact result comparisons, including the complete supplied Vedic corpus. Additional tests cover exact metadata recovery, normalization distinctions, combining-mark order, supplementary characters, JSON envelopes, and tamper rejection.
Important distinction
to_canonical_iast_from_devanagari() and to_canonical_iast_from_gujarati() generate canonical reverse transliteration from visible text. They cannot infer the exact original alias or case. Use embed_exact_source_metadata=True plus to_exact_iast_from_*() when the exact original key must be recovered.
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 lipimala-1.0.0.tar.gz.
File metadata
- Download URL: lipimala-1.0.0.tar.gz
- Upload date:
- Size: 74.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e1cf20403d800618d21ee640528c46bb4db58fcbcbbd3a603e7322205137d4e
|
|
| MD5 |
a6db892bed6b303be021ed5ef43ea6a4
|
|
| BLAKE2b-256 |
1c9e44cf1838b57a6bde875f0ca4cd5493fa43d16332ee370c64f602f9ed502d
|
Provenance
The following attestation bundles were made for lipimala-1.0.0.tar.gz:
Publisher:
publish.yml on jayeshmepani/indic-script-converter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lipimala-1.0.0.tar.gz -
Subject digest:
4e1cf20403d800618d21ee640528c46bb4db58fcbcbbd3a603e7322205137d4e - Sigstore transparency entry: 2369637677
- Sigstore integration time:
-
Permalink:
jayeshmepani/indic-script-converter@88373a8e913b20dd98925844ad430f80c8a5055d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/jayeshmepani
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@88373a8e913b20dd98925844ad430f80c8a5055d -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file lipimala-1.0.0-py3-none-any.whl.
File metadata
- Download URL: lipimala-1.0.0-py3-none-any.whl
- Upload date:
- Size: 32.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3ab6a7e5d584e88d3cff686b5eed24b72c3f68c6e3fb912ffbb586d337889d8e
|
|
| MD5 |
6d99ce793e1293f178ee2f44399260d3
|
|
| BLAKE2b-256 |
3c3f2f9fda7be04d134ec1066263c852657e5ab70309d9c4e7b36b2074addad5
|
Provenance
The following attestation bundles were made for lipimala-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on jayeshmepani/indic-script-converter
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
lipimala-1.0.0-py3-none-any.whl -
Subject digest:
3ab6a7e5d584e88d3cff686b5eed24b72c3f68c6e3fb912ffbb586d337889d8e - Sigstore transparency entry: 2369637753
- Sigstore integration time:
-
Permalink:
jayeshmepani/indic-script-converter@88373a8e913b20dd98925844ad430f80c8a5055d -
Branch / Tag:
refs/heads/main - Owner: https://github.com/jayeshmepani
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@88373a8e913b20dd98925844ad430f80c8a5055d -
Trigger Event:
workflow_dispatch
-
Statement type: