Skip to main content

axorn

English | ไทย

Pāli script converter, roman ↔ Thai (อักษร), for Python and JS from one shared table.

Pāli has no script of its own, so the same text is written in roman (evaṃ me sutaṃ) and in Thai script (เอวํ เม สุตํ). axorn converts between the two, both ways, and gives exactly the same output in Python (for backends) and JS (for web pages). It follows the conventions of the VRI Tipiṭaka (tipitaka.org), and is tested against VRI's own files.

Use

Try it in the browser: https://korakot.github.io/axorn/ — paste roman or Thai and the other follows as you type. It runs the same axorn.js, entirely in your browser.

Python:

from axorn import roman_to_thai, thai_to_roman

roman_to_thai("Evaṃ me sutaṃ.")   # 'เอวํ เม สุตํฯ'
thai_to_roman("เอวํ เม สุตํฯ")     # 'evaṃ me sutaṃ.'

JavaScript (ES module, Node 22+ or a recent browser):

import { romanToThai, thaiToRoman } from "./axorn/axorn.js";

romanToThai("Evaṃ me sutaṃ.");  // "เอวํ เม สุตํฯ"
thaiToRoman("เอวํ เม สุตํฯ");    // "evaṃ me sutaṃ."

Command line: python3 -m axorn thai < roman.txt > thai.txt (or roman for the other way).

Options:

  • ue (roman → Thai): write -iṃ as ึ, as many Thai prints do (กึ), instead of VRI's ิํ (กิํ).
  • punct (both ways, on by default): convert digits (12 ↔ ๑๒) and full stops (. ↔ ฯ). Turn it off to convert letters only.

Conventions

Thai-script Pāli is written in more than one way. axorn writes the VRI way and reads all the common ones:

axorn writes (VRI) axorn also reads
-iṃ, e.g. kiṃ กิํ กึ
e/o before a consonant cluster, e.g. tumhe ตุมฺเห (before the last consonant) ตุเมฺห (before the whole cluster)
ṭ ฏ ฎ
virama (the dot under a consonant) ฺ (phinthu) ๎ (yamakkan)
niggahita ṃ ṁ, ŋ in roman input

Two Pāli facts the converter relies on:

  • a + i and a + u are two vowels. Pāli has no ai or au diphthong, so sauddesaṃ (sa-uddesaṃ) is สอุทฺเทสํ, not เสาทฺเทสํ.
  • A vowel that starts a syllable takes อ, e.g. okkāka → โอกฺกาก.

Full stops. VRI's master text is in Devanagari, which has two marks where roman has one dot. The full stop (।) is ฯ in Thai, while the abbreviation sign (॰) stays "." in Thai, as in dī. ni. (ที. นิ.). Going roman → Thai, axorn treats a dot as an abbreviation when it:

  • touches a digit ("12.", "1.7");
  • sits inside parentheses;
  • comes before ")" or ",";
  • is followed by a number or another short abbreviation;
  • or ends a chain of them ("sī. pī. potthakesu").

Every other dot is a full stop. The elision mark …pe… is written …เป.… in Thai.

Thai has no capital letters, so Thai → roman returns lower case.

Tested on

tests/vri_check.py converts every paragraph of a VRI book roman → Thai and Thai → roman, compares each with VRI's file in the other script, and checks that Python and JS agree. On 14 Oct 2026:

Book Paragraphs Words Mismatches (of 2 × paragraphs)
Dīgha Nikāya 1 (s0101m) 1,046 45,891 2
DN 1 commentary (s0101a) 1,477 61,232 4
Jātaka verses 1 (s0513m) 10,473 53,074 6
Majjhima Nikāya 1 (s0201m) 1,785 85,305 5
Dhammasaṅgaṇī (abh01m) 2,436 53,189 2
Vinaya, Pārājika (vin01m) 2,465 72,253 4

Python and JS gave identical output on all of them, and every letter matched. The 23 mismatches are all punctuation and spacing, most of them inconsistencies inside VRI's own files. For example, the Thai file has a ฯ before the Namo tassa title that the roman file lacks, and …pe… is sometimes written …เป… without the dot.

Running the tests:

python3 tests/test_cases.py            # 18 fixed cases, Python and JS
git clone --depth 1 --filter=blob:none --sparse https://github.com/VipassanaTech/tipitaka-xml vri
git -C vri sparse-checkout set --no-cone /romn/s0101m.mul.xml /thai/s0101m.mul.xml
python3 tests/vri_check.py vri s0101m.mul

Design

axorn/thai.json holds the letters: consonants, vowels (with their position before or after the consonant), virama, niggahita, digits and punctuation. __init__.py and axorn.js both read it and mirror each other line for line, so a fix to the table reaches both languages at once.

Roman is the hub. Other scripts (Myanmar, Sinhala, …) can be added later as one table each, and any script → any script goes through roman. The reasoning, history and plan are in wiki/.

Credits

axorn was written by Claude (Anthropic) for Korakot Chaovavanich in 2026. Its design builds on Korakot's 2018 notebook, a Python port of the pitaka.lk JavaScript converter. Two ideas carry over from it: spelling each Thai syllable from a consonant + vowel pair, with เ/โ placed before the consonant, and the consonant table itself. Korakot's notebook already matched VRI exactly on DN 1, letter for letter.

Aksharamukha served as a cross-check during development.

License

MIT

Metadata

Release files for axorn 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for axorn 0.1.0
File Size Uploaded
axorn-0.1.0.tar.gz 7.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for axorn 0.1.0
File Interpreter ABI Platform
axorn-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 16.0 kB

Release files / axorn-0.1.0.tar.gz

Download URL axorn-0.1.0.tar.gz
Size 7.9 kB
Tags Source
SHA-256 checksum
How to use checksums
6f0e18d7c1f78a87707ec17047fd59319481de8d86654bfff45dffc4646f1b9b
BLAKE2b-256 checksum
How to use checksums
15199edd1d88d78f84732654852ea871bd33619b15209e19bd4ed5e6d7638070
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / axorn-0.1.0-py3-none-any.whl

Download URL axorn-0.1.0-py3-none-any.whl
Size 8.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
5740848ea65bcaa9b8f0856381ae2b808e1c9b06f8c22ccad58fcc70e38ef05b
BLAKE2b-256 checksum
How to use checksums
02d1638c7d9770686f657853024a3871304b1e24096b61f20449cfe026608fdb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page