thairom 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- thairom-0.1.0/.gitignore +8 -0
- thairom-0.1.0/AGENTS.md +15 -0
- thairom-0.1.0/LICENSE +21 -0
- thairom-0.1.0/PKG-INFO +131 -0
- thairom-0.1.0/README.md +106 -0
- thairom-0.1.0/notes/context.md +20 -0
- thairom-0.1.0/notes/decisions.md +13 -0
- thairom-0.1.0/notes/open-questions.md +5 -0
- thairom-0.1.0/notes/release_checklist.md +44 -0
- thairom-0.1.0/notes/thai_syllable_coverage.md +124 -0
- thairom-0.1.0/pyproject.toml +38 -0
- thairom-0.1.0/src/thairom/__init__.py +23 -0
- thairom-0.1.0/src/thairom/lao.py +69 -0
- thairom-0.1.0/src/thairom/maps.py +290 -0
- thairom-0.1.0/src/thairom/thai.py +173 -0
- thairom-0.1.0/src/thairom/utils.py +23 -0
- thairom-0.1.0/tests/__init__.py +0 -0
- thairom-0.1.0/tests/test_romanize.py +221 -0
thairom-0.1.0/.gitignore
ADDED
thairom-0.1.0/AGENTS.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Codex Project Instructions
|
|
2
|
+
|
|
3
|
+
Before meaningful work in this repository:
|
|
4
|
+
|
|
5
|
+
1. Read `notes/context.md`.
|
|
6
|
+
2. Read `notes/open-questions.md`.
|
|
7
|
+
3. Check `git status --short` and do not overwrite unrelated user changes.
|
|
8
|
+
|
|
9
|
+
After meaningful work:
|
|
10
|
+
|
|
11
|
+
1. Update `notes/context.md` if architecture, commands, routes, services, or important paths changed.
|
|
12
|
+
2. Update `notes/decisions.md` when a durable technical/product decision was made.
|
|
13
|
+
3. Update `notes/open-questions.md` when a blocker is resolved or a new follow-up is discovered.
|
|
14
|
+
|
|
15
|
+
Keep notes concise and factual. Do not put secrets, passwords, tokens, private raw messages, or full document contents in notes.
|
thairom-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alex Sears
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
thairom-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: thairom
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Accurate Thai and Lao/Isan romanization for real-world text -- song lyrics, colloquial speech, and dialects.
|
|
5
|
+
Project-URL: Homepage, https://github.com/alexsears/thairom
|
|
6
|
+
Project-URL: Repository, https://github.com/alexsears/thairom
|
|
7
|
+
Project-URL: Issues, https://github.com/alexsears/thairom/issues
|
|
8
|
+
Author-email: Alex Sears <asears2@gmail.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: isan,lao,nlp,romanization,thai,transliteration
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: pythainlp>=5.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# thairom
|
|
27
|
+
|
|
28
|
+
[](https://pypi.org/project/thairom/)
|
|
29
|
+
[](https://pypi.org/project/thairom/)
|
|
30
|
+
[](https://opensource.org/licenses/MIT)
|
|
31
|
+
|
|
32
|
+
Accurate Thai and Lao/Isan romanization for real-world text -- song lyrics, colloquial speech, and dialects.
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
pip install thairom
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Quick Start
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
from thairom import romanize
|
|
44
|
+
|
|
45
|
+
# Thai
|
|
46
|
+
print(romanize('สวัสดีครับ')) # sawatdee krap
|
|
47
|
+
print(romanize('ขอบคุณมาก')) # khop khun mak
|
|
48
|
+
print(romanize('หัวใจ')) # hua jai
|
|
49
|
+
print(romanize('หก')) # hok
|
|
50
|
+
|
|
51
|
+
# Lao/Isan
|
|
52
|
+
print(romanize('ฮักเจ้าหลาย', lang='lo')) # hak jao laai
|
|
53
|
+
print(romanize('ม่วนคัก', lang='lo')) # muan khak
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
- **Thai romanization** using pythainlp's royin engine with word-level corrections
|
|
59
|
+
- **Lao/Isan dialect support** for Thai-script Isan text with proper pronunciation rules (r-to-l substitution, etc.)
|
|
60
|
+
- **Word correction maps** that fix common pythainlp errors on colloquial vocabulary, song lyrics, and everyday phrases
|
|
61
|
+
- **Handles real-world text** -- tested against song lyrics, spoken Thai, and Isan dialect ground truth data
|
|
62
|
+
- **Clean output** -- strips leaked Thai/Lao characters and normalizes whitespace
|
|
63
|
+
|
|
64
|
+
## Why thairom instead of pythainlp alone?
|
|
65
|
+
|
|
66
|
+
pythainlp's royin romanization engine is solid for formal Thai, but it struggles with colloquial speech, song lyrics, and regional dialects. thairom builds on pythainlp and fixes these gaps:
|
|
67
|
+
|
|
68
|
+
| Thai Text | pythainlp (royin) | thairom | Correct |
|
|
69
|
+
|-----------|-------------------|---------|---------|
|
|
70
|
+
| หัวใจ | hua chai | hua jai | hua jai |
|
|
71
|
+
| น้ำตา | nam ta | nam ta | nam ta |
|
|
72
|
+
| เข้าใจ | khao chai | khao jai | khao jai |
|
|
73
|
+
| หก | hok | hok | hok |
|
|
74
|
+
| ก็ | ko | kaw | kaw |
|
|
75
|
+
| เวลา | wela | welaa | welaa |
|
|
76
|
+
| ตลอดเวลา | talot wela | talod welaa | talod welaa |
|
|
77
|
+
| ขอบคุณ | khop khun | khop khun | khop khun |
|
|
78
|
+
| ฮักเจ้าหลาย | (no Isan support) | hak jao laai | hak jao laai |
|
|
79
|
+
|
|
80
|
+
thairom also handles Isan/Lao dialect written in Thai script, which pythainlp does not support at all.
|
|
81
|
+
|
|
82
|
+
## API Reference
|
|
83
|
+
|
|
84
|
+
### `romanize(text, lang='th')`
|
|
85
|
+
|
|
86
|
+
Top-level convenience function. Dispatches to `romanize_thai` or `romanize_lao` based on `lang`.
|
|
87
|
+
|
|
88
|
+
**Parameters:**
|
|
89
|
+
- `text` (str): Text to romanize.
|
|
90
|
+
- `lang` (str): `'th'` for Thai (default), `'lo'` for Lao/Isan.
|
|
91
|
+
|
|
92
|
+
**Returns:** Lowercase romanized string.
|
|
93
|
+
|
|
94
|
+
### `romanize_thai(text)`
|
|
95
|
+
|
|
96
|
+
Romanize Thai text using pythainlp with word-level corrections from `THAI_WORD_MAP`.
|
|
97
|
+
|
|
98
|
+
**Parameters:**
|
|
99
|
+
- `text` (str): Thai text to romanize.
|
|
100
|
+
|
|
101
|
+
**Returns:** Lowercase romanized string.
|
|
102
|
+
|
|
103
|
+
### `romanize_lao(text)`
|
|
104
|
+
|
|
105
|
+
Romanize Isan/Lao text written in Thai script. Applies Lao pronunciation rules (e.g., initial r becomes l) and word corrections from `LAO_WORD_MAP`.
|
|
106
|
+
|
|
107
|
+
**Parameters:**
|
|
108
|
+
- `text` (str): Isan/Lao text in Thai script.
|
|
109
|
+
|
|
110
|
+
**Returns:** Lowercase romanized string.
|
|
111
|
+
|
|
112
|
+
### Word Maps
|
|
113
|
+
|
|
114
|
+
The correction maps are available as importable dictionaries for inspection or extension:
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
from thairom.maps import THAI_WORD_MAP, LAO_WORD_MAP
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Contributing
|
|
121
|
+
|
|
122
|
+
Contributions are welcome, especially additions to the word correction maps. The maps were developed using an autoresearch pipeline that scores romanization output against ground truth data. If you find a word that romanizes incorrectly:
|
|
123
|
+
|
|
124
|
+
1. Add the word and its correct romanization to `THAI_WORD_MAP` or `LAO_WORD_MAP` in `src/thairom/maps.py`.
|
|
125
|
+
2. Add a test case to `tests/test_romanize.py`.
|
|
126
|
+
3. Run `pytest` to verify.
|
|
127
|
+
4. Submit a pull request.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT
|
thairom-0.1.0/README.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# thairom
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/thairom/)
|
|
4
|
+
[](https://pypi.org/project/thairom/)
|
|
5
|
+
[](https://opensource.org/licenses/MIT)
|
|
6
|
+
|
|
7
|
+
Accurate Thai and Lao/Isan romanization for real-world text -- song lyrics, colloquial speech, and dialects.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install thairom
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from thairom import romanize
|
|
19
|
+
|
|
20
|
+
# Thai
|
|
21
|
+
print(romanize('สวัสดีครับ')) # sawatdee krap
|
|
22
|
+
print(romanize('ขอบคุณมาก')) # khop khun mak
|
|
23
|
+
print(romanize('หัวใจ')) # hua jai
|
|
24
|
+
print(romanize('หก')) # hok
|
|
25
|
+
|
|
26
|
+
# Lao/Isan
|
|
27
|
+
print(romanize('ฮักเจ้าหลาย', lang='lo')) # hak jao laai
|
|
28
|
+
print(romanize('ม่วนคัก', lang='lo')) # muan khak
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Features
|
|
32
|
+
|
|
33
|
+
- **Thai romanization** using pythainlp's royin engine with word-level corrections
|
|
34
|
+
- **Lao/Isan dialect support** for Thai-script Isan text with proper pronunciation rules (r-to-l substitution, etc.)
|
|
35
|
+
- **Word correction maps** that fix common pythainlp errors on colloquial vocabulary, song lyrics, and everyday phrases
|
|
36
|
+
- **Handles real-world text** -- tested against song lyrics, spoken Thai, and Isan dialect ground truth data
|
|
37
|
+
- **Clean output** -- strips leaked Thai/Lao characters and normalizes whitespace
|
|
38
|
+
|
|
39
|
+
## Why thairom instead of pythainlp alone?
|
|
40
|
+
|
|
41
|
+
pythainlp's royin romanization engine is solid for formal Thai, but it struggles with colloquial speech, song lyrics, and regional dialects. thairom builds on pythainlp and fixes these gaps:
|
|
42
|
+
|
|
43
|
+
| Thai Text | pythainlp (royin) | thairom | Correct |
|
|
44
|
+
|-----------|-------------------|---------|---------|
|
|
45
|
+
| หัวใจ | hua chai | hua jai | hua jai |
|
|
46
|
+
| น้ำตา | nam ta | nam ta | nam ta |
|
|
47
|
+
| เข้าใจ | khao chai | khao jai | khao jai |
|
|
48
|
+
| หก | hok | hok | hok |
|
|
49
|
+
| ก็ | ko | kaw | kaw |
|
|
50
|
+
| เวลา | wela | welaa | welaa |
|
|
51
|
+
| ตลอดเวลา | talot wela | talod welaa | talod welaa |
|
|
52
|
+
| ขอบคุณ | khop khun | khop khun | khop khun |
|
|
53
|
+
| ฮักเจ้าหลาย | (no Isan support) | hak jao laai | hak jao laai |
|
|
54
|
+
|
|
55
|
+
thairom also handles Isan/Lao dialect written in Thai script, which pythainlp does not support at all.
|
|
56
|
+
|
|
57
|
+
## API Reference
|
|
58
|
+
|
|
59
|
+
### `romanize(text, lang='th')`
|
|
60
|
+
|
|
61
|
+
Top-level convenience function. Dispatches to `romanize_thai` or `romanize_lao` based on `lang`.
|
|
62
|
+
|
|
63
|
+
**Parameters:**
|
|
64
|
+
- `text` (str): Text to romanize.
|
|
65
|
+
- `lang` (str): `'th'` for Thai (default), `'lo'` for Lao/Isan.
|
|
66
|
+
|
|
67
|
+
**Returns:** Lowercase romanized string.
|
|
68
|
+
|
|
69
|
+
### `romanize_thai(text)`
|
|
70
|
+
|
|
71
|
+
Romanize Thai text using pythainlp with word-level corrections from `THAI_WORD_MAP`.
|
|
72
|
+
|
|
73
|
+
**Parameters:**
|
|
74
|
+
- `text` (str): Thai text to romanize.
|
|
75
|
+
|
|
76
|
+
**Returns:** Lowercase romanized string.
|
|
77
|
+
|
|
78
|
+
### `romanize_lao(text)`
|
|
79
|
+
|
|
80
|
+
Romanize Isan/Lao text written in Thai script. Applies Lao pronunciation rules (e.g., initial r becomes l) and word corrections from `LAO_WORD_MAP`.
|
|
81
|
+
|
|
82
|
+
**Parameters:**
|
|
83
|
+
- `text` (str): Isan/Lao text in Thai script.
|
|
84
|
+
|
|
85
|
+
**Returns:** Lowercase romanized string.
|
|
86
|
+
|
|
87
|
+
### Word Maps
|
|
88
|
+
|
|
89
|
+
The correction maps are available as importable dictionaries for inspection or extension:
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
from thairom.maps import THAI_WORD_MAP, LAO_WORD_MAP
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Contributing
|
|
96
|
+
|
|
97
|
+
Contributions are welcome, especially additions to the word correction maps. The maps were developed using an autoresearch pipeline that scores romanization output against ground truth data. If you find a word that romanizes incorrectly:
|
|
98
|
+
|
|
99
|
+
1. Add the word and its correct romanization to `THAI_WORD_MAP` or `LAO_WORD_MAP` in `src/thairom/maps.py`.
|
|
100
|
+
2. Add a test case to `tests/test_romanize.py`.
|
|
101
|
+
3. Run `pytest` to verify.
|
|
102
|
+
4. Submit a pull request.
|
|
103
|
+
|
|
104
|
+
## License
|
|
105
|
+
|
|
106
|
+
MIT
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Context
|
|
2
|
+
|
|
3
|
+
Project: thairom
|
|
4
|
+
Path: C:\code\thairom
|
|
5
|
+
|
|
6
|
+
Purpose:
|
|
7
|
+
|
|
8
|
+
- TODO: Summarize what this project does and who/what uses it.
|
|
9
|
+
|
|
10
|
+
Important files and directories:
|
|
11
|
+
|
|
12
|
+
- TODO: Add key source paths, config paths, deployment paths, and data locations.
|
|
13
|
+
|
|
14
|
+
Run/test/deploy commands:
|
|
15
|
+
|
|
16
|
+
- TODO: Add the commands future sessions should use.
|
|
17
|
+
|
|
18
|
+
Operational notes:
|
|
19
|
+
|
|
20
|
+
- TODO: Add services, URLs, ports, scheduled jobs, and environment assumptions.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Release Checklist
|
|
2
|
+
|
|
3
|
+
Use this before publishing `thairom` or shipping a romanization update.
|
|
4
|
+
|
|
5
|
+
## Before Release
|
|
6
|
+
|
|
7
|
+
1. Add or update romanization rules in `src/thairom/maps.py` or `src/thairom/thai.py`.
|
|
8
|
+
2. Add regression tests in `tests/test_romanize.py`.
|
|
9
|
+
3. Run:
|
|
10
|
+
|
|
11
|
+
```powershell
|
|
12
|
+
python -m pytest -q
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
4. If this is an update after the first PyPI publish, bump both versions:
|
|
16
|
+
- `pyproject.toml`
|
|
17
|
+
- `src/thairom/__init__.py`
|
|
18
|
+
|
|
19
|
+
5. Rebuild clean artifacts:
|
|
20
|
+
|
|
21
|
+
```powershell
|
|
22
|
+
Remove-Item -Recurse -Force dist
|
|
23
|
+
python -m build
|
|
24
|
+
python -m twine check dist\*
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## First Publish
|
|
28
|
+
|
|
29
|
+
The current first-release version is `0.1.0`.
|
|
30
|
+
|
|
31
|
+
```powershell
|
|
32
|
+
$env:TWINE_USERNAME="__token__"
|
|
33
|
+
$env:TWINE_PASSWORD="pypi-your-token-here"
|
|
34
|
+
python -m twine upload dist\*
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Later Updates
|
|
38
|
+
|
|
39
|
+
PyPI does not allow replacing an existing uploaded version. For every update:
|
|
40
|
+
|
|
41
|
+
1. Bump the version, for example `0.1.0` to `0.1.1`.
|
|
42
|
+
2. Rebuild from a clean `dist` folder.
|
|
43
|
+
3. Upload the new version.
|
|
44
|
+
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Thai Syllable Coverage Review
|
|
2
|
+
|
|
3
|
+
This is a practical review set for `thairom`, not a complete dictionary. Thai syllables combine:
|
|
4
|
+
|
|
5
|
+
- Initial consonant sound
|
|
6
|
+
- Vowel shape
|
|
7
|
+
- Final sound, including open syllables
|
|
8
|
+
- Tone/mark context
|
|
9
|
+
|
|
10
|
+
A full start x vowel x finish matrix across every Thai letter would create thousands of forms, many of them unnatural or not real words. This file uses real or common words to cover the important sound patterns.
|
|
11
|
+
|
|
12
|
+
## Initial Consonants
|
|
13
|
+
|
|
14
|
+
| Letter | Example | Current Target |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| ก | กา | ga |
|
|
17
|
+
| ข | ขา | kha |
|
|
18
|
+
| ฃ | ฃวด | khuad |
|
|
19
|
+
| ค | คน | khon |
|
|
20
|
+
| ฅ | ฅน | khon |
|
|
21
|
+
| ฆ | ฆ่า | kha |
|
|
22
|
+
| ง | งาน | ngan |
|
|
23
|
+
| จ | ใจ | jai |
|
|
24
|
+
| ฉ | ฉัน | chan |
|
|
25
|
+
| ช | ชา | cha |
|
|
26
|
+
| ซ | ซื้อ | sue |
|
|
27
|
+
| ฌ | เฌอ | choe |
|
|
28
|
+
| ญ | ผู้หญิง | phu ying |
|
|
29
|
+
| ฎ | ฎีกา | deeka |
|
|
30
|
+
| ฏ | ปฏัก | bpatak |
|
|
31
|
+
| ฐ | ฐาน | than |
|
|
32
|
+
| ฑ | มณฑล | monthon |
|
|
33
|
+
| ฒ | ผู้เฒ่า | phu thao |
|
|
34
|
+
| ณ | เณร | nen |
|
|
35
|
+
| ด | เด็ก | dek |
|
|
36
|
+
| ต | ตา | dta |
|
|
37
|
+
| ถ | ถนน | thanon |
|
|
38
|
+
| ท | ไทย | thai |
|
|
39
|
+
| ธ | ธรรม | tham |
|
|
40
|
+
| น | นา | na |
|
|
41
|
+
| บ | บ้าน | baan |
|
|
42
|
+
| ป | ปลา | bplaa |
|
|
43
|
+
| ผ | ผม | pom |
|
|
44
|
+
| ฝ | ฝัน | fan |
|
|
45
|
+
| พ | พ่อ | paw |
|
|
46
|
+
| ฟ | ฟัง | fang |
|
|
47
|
+
| ภ | ภาษา | phasaa |
|
|
48
|
+
| ม | มา | ma |
|
|
49
|
+
| ย | ยา | ya |
|
|
50
|
+
| ร | รัก | rak |
|
|
51
|
+
| ล | ลูก | luk |
|
|
52
|
+
| ว | วัน | wan |
|
|
53
|
+
| ศ | ศูนย์ | soon |
|
|
54
|
+
| ษ | ภาษา | phasaa |
|
|
55
|
+
| ส | สบาย | sabai |
|
|
56
|
+
| ห | ห้า | haa |
|
|
57
|
+
| ฬ | กีฬา | geelaa |
|
|
58
|
+
| อ | อร่อย | aroi |
|
|
59
|
+
| ฮ | ฮา | ha |
|
|
60
|
+
|
|
61
|
+
## Core Vowel Shapes
|
|
62
|
+
|
|
63
|
+
| Vowel Sound | Example | Current Target |
|
|
64
|
+
|---|---|---|
|
|
65
|
+
| a short | กะ | ga |
|
|
66
|
+
| aa long | กา | gaa |
|
|
67
|
+
| i short | กิน | gin |
|
|
68
|
+
| ee long | ดี | dee |
|
|
69
|
+
| ue short | ดึก | duek |
|
|
70
|
+
| uea long | เมือง | mueang |
|
|
71
|
+
| u short | ลุก | luk |
|
|
72
|
+
| oo long | ดู | du |
|
|
73
|
+
| e | เจ็ด | jed |
|
|
74
|
+
| ae | แม่ | mae |
|
|
75
|
+
| o short | คน | khon |
|
|
76
|
+
| oh long | โต | dto |
|
|
77
|
+
| aw | พ่อ | paw |
|
|
78
|
+
| eu | เธอ | ter |
|
|
79
|
+
| ia | เรียน | rian |
|
|
80
|
+
| ua | ครัว | krua |
|
|
81
|
+
| ai | ไทย | thai |
|
|
82
|
+
| ao | เข้า | khao |
|
|
83
|
+
| am | ทำ | tam |
|
|
84
|
+
|
|
85
|
+
## Final Sound Categories
|
|
86
|
+
|
|
87
|
+
| Final Sound | Thai Final Letters | Example | Current Target |
|
|
88
|
+
|---|---|---|---|
|
|
89
|
+
| open | none | มา | ma |
|
|
90
|
+
| k | ก ข ค ฆ | รัก | rak |
|
|
91
|
+
| t | จ ช ซ ฎ ฏ ฐ ฑ ฒ ด ต ถ ท ธ ศ ษ ส | เจ็ด | jed |
|
|
92
|
+
| p | บ ป พ ฟ ภ | ครับ | krap |
|
|
93
|
+
| n | น ณ ญ ร ล ฬ | คน | khon |
|
|
94
|
+
| m | ม | ผม | pom |
|
|
95
|
+
| ng | ง | เพลง | pleng |
|
|
96
|
+
| y | ย | สบาย | sabai |
|
|
97
|
+
| w | ว | แล้ว | laew |
|
|
98
|
+
|
|
99
|
+
## Starter Combination Matrix
|
|
100
|
+
|
|
101
|
+
These are compact start-vowel-finish examples for regression tests.
|
|
102
|
+
|
|
103
|
+
| Pattern | Example | Current Target |
|
|
104
|
+
|---|---|---|
|
|
105
|
+
| g + aa + open | กา | ga |
|
|
106
|
+
| g + a + k | กัก | gak |
|
|
107
|
+
| g + a + n | กัน | gan |
|
|
108
|
+
| g + a + m | กำ | gam |
|
|
109
|
+
| g + a + ng | กัง | gang |
|
|
110
|
+
| g + a + p | กับ | gap |
|
|
111
|
+
| g + a + t | กัด | gad |
|
|
112
|
+
| g + ai + open | ไก่ | gai |
|
|
113
|
+
| j + e + t | เจ็ด | jed |
|
|
114
|
+
| d + e + k | เด็ก | dek |
|
|
115
|
+
| dt + aa + open | ตา | dta |
|
|
116
|
+
| n + am + open | น้ำ | nam |
|
|
117
|
+
| n + am + dta | น้ำตา | nam dta |
|
|
118
|
+
| s + a + bai | สบาย | sabai |
|
|
119
|
+
| s + a + bai dee | สบายดี | sabai dee |
|
|
120
|
+
| y + oo + open | อยู่ | yoo |
|
|
121
|
+
| y + oo + duay gan | อยู่ด้วยกัน | yoo duay gan |
|
|
122
|
+
| t + awn + nee | ตอนนี้ | tawnnee |
|
|
123
|
+
| t + ee + nee | ที่นี่ | tee nee |
|
|
124
|
+
| kh + on + thai | คนไทย | khontai |
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "thairom"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Accurate Thai and Lao/Isan romanization for real-world text -- song lyrics, colloquial speech, and dialects."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Alex Sears", email = "asears2@gmail.com" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["thai", "lao", "isan", "romanization", "transliteration", "nlp"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.9",
|
|
22
|
+
"Programming Language :: Python :: 3.10",
|
|
23
|
+
"Programming Language :: Python :: 3.11",
|
|
24
|
+
"Programming Language :: Python :: 3.12",
|
|
25
|
+
"Programming Language :: Python :: 3.13",
|
|
26
|
+
"Topic :: Text Processing :: Linguistic",
|
|
27
|
+
]
|
|
28
|
+
dependencies = [
|
|
29
|
+
"pythainlp>=5.0",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/alexsears/thairom"
|
|
34
|
+
Repository = "https://github.com/alexsears/thairom"
|
|
35
|
+
Issues = "https://github.com/alexsears/thairom/issues"
|
|
36
|
+
|
|
37
|
+
[tool.pytest.ini_options]
|
|
38
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""thairom -- Accurate Thai and Lao/Isan romanization for real-world text."""
|
|
2
|
+
|
|
3
|
+
from .thai import romanize_thai
|
|
4
|
+
from .lao import romanize_lao
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def romanize(text, lang='th'):
|
|
8
|
+
"""Romanize Thai or Lao/Isan text.
|
|
9
|
+
|
|
10
|
+
Args:
|
|
11
|
+
text: Text string to romanize.
|
|
12
|
+
lang: Language code -- 'th' for Thai (default), 'lo' for Lao/Isan.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
Lowercase romanized string.
|
|
16
|
+
"""
|
|
17
|
+
if lang == 'lo':
|
|
18
|
+
return romanize_lao(text)
|
|
19
|
+
return romanize_thai(text)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
__version__ = '0.1.0'
|
|
23
|
+
__all__ = ['romanize', 'romanize_thai', 'romanize_lao']
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""Lao/Isan romanization for Thai-script Isan text."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from .maps import LAO_WORD_MAP, LAO_ROM_REPLACEMENTS
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def _apply_lao_pronunciation(romanized, original_thai):
|
|
9
|
+
"""Apply Isan/Lao pronunciation rules to a Thai romanization.
|
|
10
|
+
|
|
11
|
+
Isan dialect uses Lao pronunciation conventions, most notably replacing
|
|
12
|
+
initial 'r' sounds with 'l'. This function applies those rules after
|
|
13
|
+
the base Thai romanization.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
romanized: Base romanized string from pythainlp.
|
|
17
|
+
original_thai: Original Thai-script word (checked against LAO_WORD_MAP first).
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
Romanized string with Lao/Isan pronunciation applied.
|
|
21
|
+
"""
|
|
22
|
+
if original_thai in LAO_WORD_MAP:
|
|
23
|
+
return LAO_WORD_MAP[original_thai]
|
|
24
|
+
result = romanized.lower()
|
|
25
|
+
result = re.sub(r'[\u0E00-\u0E7F\u0E80-\u0EFF]', '', result)
|
|
26
|
+
for pattern, replacement in LAO_ROM_REPLACEMENTS:
|
|
27
|
+
result = pattern.sub(replacement, result)
|
|
28
|
+
return result.strip()
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def romanize_lao(text):
|
|
32
|
+
"""Romanize Isan/Lao text written in Thai script.
|
|
33
|
+
|
|
34
|
+
Uses pythainlp's newmm tokenizer and royin romanization as a base,
|
|
35
|
+
then applies Lao/Isan word corrections and pronunciation rules
|
|
36
|
+
(e.g., r -> l substitution).
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
text: Isan/Lao text in Thai script to romanize.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Lowercase romanized string with Lao/Isan pronunciation.
|
|
43
|
+
"""
|
|
44
|
+
if not text:
|
|
45
|
+
return ''
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
from pythainlp.tokenize import word_tokenize
|
|
49
|
+
from pythainlp.transliterate import romanize
|
|
50
|
+
except ImportError:
|
|
51
|
+
return ''
|
|
52
|
+
|
|
53
|
+
words = word_tokenize(text, engine='newmm')
|
|
54
|
+
pieces = []
|
|
55
|
+
for word in words:
|
|
56
|
+
stripped = word.strip()
|
|
57
|
+
if not stripped:
|
|
58
|
+
continue
|
|
59
|
+
if stripped in LAO_WORD_MAP:
|
|
60
|
+
pieces.append(LAO_WORD_MAP[stripped])
|
|
61
|
+
continue
|
|
62
|
+
try:
|
|
63
|
+
rom = romanize(stripped, engine='royin')
|
|
64
|
+
rom = _apply_lao_pronunciation(rom, stripped)
|
|
65
|
+
if rom:
|
|
66
|
+
pieces.append(rom)
|
|
67
|
+
except Exception:
|
|
68
|
+
pieces.append(stripped)
|
|
69
|
+
return ' '.join(pieces)
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
"""Word correction maps for Thai and Lao/Isan romanization.
|
|
2
|
+
|
|
3
|
+
These maps override pythainlp's royin engine where it produces incorrect
|
|
4
|
+
romanizations for common words, colloquial speech, and Isan dialect.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
|
|
9
|
+
# ============================================================
|
|
10
|
+
# Thai word correction map
|
|
11
|
+
# pythainlp's royin engine gets these wrong -- override here
|
|
12
|
+
# ============================================================
|
|
13
|
+
THAI_WORD_MAP = {
|
|
14
|
+
# Style: roo, gaw, ter, laew, ja, pee, rawng, tam, krap, ka, jing, loei, yoo
|
|
15
|
+
# Long vowels: cheewit, pood, tawng, welaa, sawatdee
|
|
16
|
+
# Joined: sabai, tammai, arai, khaojai, rawnghai
|
|
17
|
+
'ก็': 'gaw',
|
|
18
|
+
'ความสำคัญ': 'khwam sam khan',
|
|
19
|
+
'น้ำตา': 'nam dta',
|
|
20
|
+
'หนำใจ': 'nam jai',
|
|
21
|
+
'ทันที': 'tawntee',
|
|
22
|
+
'อย่างนี้': 'yang nee',
|
|
23
|
+
'ทั้งนั้น': 'thang nan',
|
|
24
|
+
'อะไร': 'a rai',
|
|
25
|
+
'เวลา': 'welaa',
|
|
26
|
+
'ผูกพัน': 'phuk phan',
|
|
27
|
+
'รำพัน': 'ram phan',
|
|
28
|
+
'แกล้ง': 'klaeng',
|
|
29
|
+
'เสียง': 'siang',
|
|
30
|
+
'เพ้อ': 'phoe',
|
|
31
|
+
'ชิ่ง': 'jing',
|
|
32
|
+
'ทุกวัน': 'thuk wan',
|
|
33
|
+
'ทุกคน': 'thuk khon',
|
|
34
|
+
'ตั้งใจ': 'tang jai',
|
|
35
|
+
'หัวใจ': 'hua jai',
|
|
36
|
+
'เข้าใจ': 'khao jai',
|
|
37
|
+
'สบาย': 'sa bai',
|
|
38
|
+
'สวัสดี': 'sawatdee',
|
|
39
|
+
'ขอบคุณ': 'khop khun',
|
|
40
|
+
'ไม่เคย': 'mai koey',
|
|
41
|
+
'เป็นห่วง': 'pen huang',
|
|
42
|
+
'ตลอด': 'talod',
|
|
43
|
+
'สำคัญ': 'sam khan',
|
|
44
|
+
'ต่างคน': 'tang khon',
|
|
45
|
+
'แต่ว่า': 'tae wa',
|
|
46
|
+
'ปุ๊บๆ': 'pup',
|
|
47
|
+
'ปั๊บๆ': 'pap',
|
|
48
|
+
'ปุ๊บ': 'pup',
|
|
49
|
+
'ปั๊บ': 'pap',
|
|
50
|
+
'ให้ความ': 'hai khwam',
|
|
51
|
+
'เสียน้ำตา': 'sia nam ta',
|
|
52
|
+
'ต้องหา': 'tawng ha',
|
|
53
|
+
'ห่วง': 'huang',
|
|
54
|
+
'ต้องมา': 'tawng ma',
|
|
55
|
+
'คนต่าง': 'khon tang',
|
|
56
|
+
'ที่มี': 'thi mi',
|
|
57
|
+
'ต่างบอก': 'tang bok',
|
|
58
|
+
'จะทิ้ง': 'ja thing',
|
|
59
|
+
'ไม่ได้': 'mai dai',
|
|
60
|
+
'ก็ไม่': 'gaw mai',
|
|
61
|
+
'ก็คง': 'gaw khong',
|
|
62
|
+
'ก็เชื่อ': 'gaw juea',
|
|
63
|
+
'ก็แค่': 'gaw khae',
|
|
64
|
+
'บอกว่า': 'bok wa',
|
|
65
|
+
'ให้ความสำคัญ': 'hai khwam sam khan',
|
|
66
|
+
'อยู่อย่าง': 'yoo yang',
|
|
67
|
+
'ความรัก': 'khwam rak',
|
|
68
|
+
'ตลอดเวลา': 'talod welaa',
|
|
69
|
+
'ๆ': '',
|
|
70
|
+
# Common words
|
|
71
|
+
'ใคร': 'khrai',
|
|
72
|
+
'อยู่': 'yoo',
|
|
73
|
+
'ครับ': 'krap',
|
|
74
|
+
'คะ': 'ka',
|
|
75
|
+
'ค่ะ': 'ka',
|
|
76
|
+
# Numbers and first-lesson vocabulary
|
|
77
|
+
'ศูนย์': 'soon',
|
|
78
|
+
'หนึ่ง': 'neung',
|
|
79
|
+
'สอง': 'song',
|
|
80
|
+
'สาม': 'saam',
|
|
81
|
+
'สี่': 'see',
|
|
82
|
+
'ห้า': 'haa',
|
|
83
|
+
'หก': 'hok',
|
|
84
|
+
'เจ็ด': 'jed',
|
|
85
|
+
'แปด': 'paet',
|
|
86
|
+
'เก้า': 'gao',
|
|
87
|
+
'สิบ': 'sip',
|
|
88
|
+
'สิบเอ็ด': 'sip et',
|
|
89
|
+
'ยี่สิบ': 'yee sip',
|
|
90
|
+
'ร้อย': 'roi',
|
|
91
|
+
# People and daily speech
|
|
92
|
+
'ผม': 'pom',
|
|
93
|
+
'เรา': 'rao',
|
|
94
|
+
'คุณ': 'khun',
|
|
95
|
+
'เขา': 'khao',
|
|
96
|
+
'แม่': 'mae',
|
|
97
|
+
'พ่อ': 'paw',
|
|
98
|
+
'ลูก': 'luk',
|
|
99
|
+
'เพื่อน': 'puean',
|
|
100
|
+
'ผู้หญิง': 'phu ying',
|
|
101
|
+
'ผู้ชาย': 'phu chai',
|
|
102
|
+
'คนไทย': 'khontai',
|
|
103
|
+
'ครอบครัว': 'kropkrua',
|
|
104
|
+
'จ้ะ': 'ja',
|
|
105
|
+
'จ้า': 'ja',
|
|
106
|
+
'นะ': 'na',
|
|
107
|
+
'น่ะ': 'na',
|
|
108
|
+
'ล่ะ': 'la',
|
|
109
|
+
'ไหม': 'mai',
|
|
110
|
+
'มั้ย': 'mai',
|
|
111
|
+
'เหรอ': 'ror',
|
|
112
|
+
'ขอโทษ': 'kho thot',
|
|
113
|
+
'วันนี้': 'wan nee',
|
|
114
|
+
'พรุ่งนี้': 'prung nee',
|
|
115
|
+
'เมื่อวาน': 'muea wan',
|
|
116
|
+
'ตรงนี้': 'trong nee',
|
|
117
|
+
'อยู่ตรงนี้': 'yoo trong nee',
|
|
118
|
+
'คิดถึง': 'kit tueng',
|
|
119
|
+
'คิดถึงเธอ': 'kit tueng ter',
|
|
120
|
+
'กิน': 'kin',
|
|
121
|
+
'ข้าว': 'khao',
|
|
122
|
+
'หรือ': 'rue',
|
|
123
|
+
'ยัง': 'yang',
|
|
124
|
+
'สบายดี': 'sabai dee',
|
|
125
|
+
'ไม่เป็นไร': 'mai pen rai',
|
|
126
|
+
'ไม่เป็น': 'mai pen',
|
|
127
|
+
'เป็นไร': 'pen rai',
|
|
128
|
+
'เป็น': 'pen',
|
|
129
|
+
'เจ้าของ': 'jao khong',
|
|
130
|
+
'ดีๆ': 'dee dee',
|
|
131
|
+
'เพลง': 'phleng',
|
|
132
|
+
'เสียงดัง': 'siang dang',
|
|
133
|
+
'ดัง': 'dang',
|
|
134
|
+
'ว่า': 'wa',
|
|
135
|
+
'ไม่มี': 'mai mi',
|
|
136
|
+
'มี': 'mi',
|
|
137
|
+
'ต่าง': 'tang',
|
|
138
|
+
'บอก': 'bok',
|
|
139
|
+
'ไม่': 'mai',
|
|
140
|
+
'กินข้าว': 'kin khao',
|
|
141
|
+
'หรือยัง': 'rue yang',
|
|
142
|
+
'สิ': 'si',
|
|
143
|
+
'บ่': 'baw',
|
|
144
|
+
'รอด': 'rot',
|
|
145
|
+
'ก็สิ': 'gaw si',
|
|
146
|
+
'บ่รอด': 'baw rot',
|
|
147
|
+
'เปิด': 'poet',
|
|
148
|
+
'ก็ต่าง': 'gaw tang',
|
|
149
|
+
'คิดให้': 'khit hai',
|
|
150
|
+
'ให้': 'hai',
|
|
151
|
+
'ดี': 'dee',
|
|
152
|
+
'เด็ก': 'dek',
|
|
153
|
+
'ดู': 'du',
|
|
154
|
+
'เด้อ': 'doe',
|
|
155
|
+
'ต่างบอกว่า': 'tang bok wa',
|
|
156
|
+
'ไม่มีใคร': 'mai mi khrai',
|
|
157
|
+
'กว่า': 'kwa',
|
|
158
|
+
# New preference-aligned entries
|
|
159
|
+
'จริง': 'jing',
|
|
160
|
+
'จะ': 'ja',
|
|
161
|
+
'จาก': 'jaak',
|
|
162
|
+
'จน': 'jon',
|
|
163
|
+
'จม': 'jom',
|
|
164
|
+
'จบ': 'jop',
|
|
165
|
+
'จิต': 'jit',
|
|
166
|
+
'จิตใจ': 'jit jai',
|
|
167
|
+
'จุด': 'jut',
|
|
168
|
+
'เจ้า': 'jao',
|
|
169
|
+
'เจอ': 'jer',
|
|
170
|
+
'เจ็บ': 'jep',
|
|
171
|
+
'ใจ': 'jai',
|
|
172
|
+
'จับ': 'jap',
|
|
173
|
+
'จัด': 'jat',
|
|
174
|
+
'จัง': 'jang',
|
|
175
|
+
'จำ': 'jam',
|
|
176
|
+
'จำเป็น': 'jam pen',
|
|
177
|
+
'รู้': 'roo',
|
|
178
|
+
'รู้สึก': 'roo seuk',
|
|
179
|
+
'เธอ': 'ter',
|
|
180
|
+
'แล้ว': 'laew',
|
|
181
|
+
'เลย': 'loei',
|
|
182
|
+
'ทำ': 'tam',
|
|
183
|
+
'ทำไม': 'tam mai',
|
|
184
|
+
'ร้อง': 'rawng',
|
|
185
|
+
'ร้องไห้': 'rawng hai',
|
|
186
|
+
'พี่': 'pee',
|
|
187
|
+
'ฉัน': 'chan',
|
|
188
|
+
'ช่วย': 'chuay',
|
|
189
|
+
'ชีวิต': 'cheewit',
|
|
190
|
+
'ชอบ': 'chawp',
|
|
191
|
+
'ช้า': 'cha',
|
|
192
|
+
# Compounds the tokenizer often merges
|
|
193
|
+
'ตลอดกาล': 'talod gaan',
|
|
194
|
+
'น่ารัก': 'na rak',
|
|
195
|
+
'ต้องการ': 'tawngkaan',
|
|
196
|
+
'ต้อง': 'tawng',
|
|
197
|
+
'เสียใจ': 'siajai',
|
|
198
|
+
'คิด': 'kit',
|
|
199
|
+
'ถึง': 'tueng',
|
|
200
|
+
'พูด': 'pood',
|
|
201
|
+
'ความ': 'khwaam',
|
|
202
|
+
'ด้วย': 'duay',
|
|
203
|
+
'เพลง': 'pleng',
|
|
204
|
+
'เสีย': 'sia',
|
|
205
|
+
'พี่น้อง': 'pee nong',
|
|
206
|
+
'ที่จะ': 'thi ja',
|
|
207
|
+
'ก็ดี': 'gaw dee',
|
|
208
|
+
'ก็ดีแค่': 'gaw dee khae',
|
|
209
|
+
'หมดสิทธิ์': 'mot sit',
|
|
210
|
+
'ครบครอง': 'khrop khrong',
|
|
211
|
+
'น้อง': 'nong',
|
|
212
|
+
'สิทธิ์': 'sit',
|
|
213
|
+
'คนเดียว': 'khon diao',
|
|
214
|
+
'เดียว': 'diao',
|
|
215
|
+
'โว': 'wo',
|
|
216
|
+
'โวฉัน': 'wo chan',
|
|
217
|
+
'ในใจ': 'nai jai',
|
|
218
|
+
'แม้จะ': 'mae ja',
|
|
219
|
+
'จะไม่': 'ja mai',
|
|
220
|
+
'ฉันจะ': 'chan ja',
|
|
221
|
+
'เก็บเธอ': 'kep ter',
|
|
222
|
+
'ไว้ใน': 'wai nai',
|
|
223
|
+
'กาล': 'gaan',
|
|
224
|
+
'แม้': 'mae',
|
|
225
|
+
'เก็บ': 'kep',
|
|
226
|
+
'ไว้': 'wai',
|
|
227
|
+
'ใน': 'nai',
|
|
228
|
+
'มา': 'ma',
|
|
229
|
+
'ของ': 'khong',
|
|
230
|
+
'กัน': 'gan',
|
|
231
|
+
'คน': 'khon',
|
|
232
|
+
'ที่': 'thi',
|
|
233
|
+
'กับ': 'kap',
|
|
234
|
+
'แต่': 'tae',
|
|
235
|
+
'ก็จะ': 'gaw ja',
|
|
236
|
+
'จะได้': 'ja dai',
|
|
237
|
+
'ได้': 'dai',
|
|
238
|
+
'ตลอดไป': 'talod pai',
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
# ============================================================
|
|
242
|
+
# Lao / Isan word map and pronunciation rules
|
|
243
|
+
# ============================================================
|
|
244
|
+
LAO_WORD_MAP = {
|
|
245
|
+
'บ่': 'baw', 'เด้อ': 'doe', 'หลาย': 'laai', 'อีหลี': 'ii lii',
|
|
246
|
+
'ได๋': 'dai', 'แน': 'nae', 'จั่ง': 'jang', 'ซั่น': 'san',
|
|
247
|
+
'อ้าย': 'aai', 'เฮา': 'hao', 'ฮัก': 'hak', 'ฮู้': 'huu',
|
|
248
|
+
'คัก': 'khak', 'แท้น้อ': 'thae naw', 'สิ': 'si', 'เด': 'de',
|
|
249
|
+
'น้องหล่า': 'nawng laa', 'เอิ้น': 'oen', 'ขวัญ': 'khwan',
|
|
250
|
+
'เฮ็ด': 'het', 'เฮือน': 'huean', 'แม่น': 'maen', 'บ้าน': 'baan',
|
|
251
|
+
'คน': 'khon', 'ผู้': 'phuu', 'เจ้า': 'jao', 'กิน': 'kin',
|
|
252
|
+
'เมือง': 'mueang', 'หมอ': 'maw', 'ลำ': 'lam', 'อยู่': 'yuu',
|
|
253
|
+
'เพิ่น': 'phen', 'ส่ำ': 'sam', 'นำ': 'nam', 'พุ้น': 'phun',
|
|
254
|
+
'หยัง': 'yang', 'เบิ่ง': 'boeng', 'ทาง': 'thaang',
|
|
255
|
+
'ผู้สาว': 'phuu sao', 'ผู้บ่าว': 'phuu bao', 'ผู้เฒ่า': 'phuu thao',
|
|
256
|
+
'ม่วน': 'muan', 'ซ่อย': 'soi', 'เว้า': 'wao', 'ลืม': 'luem',
|
|
257
|
+
'คิด': 'khit', 'ฮ้อง': 'hawng', 'ไป': 'pai', 'มา': 'ma',
|
|
258
|
+
'ตาย': 'taai', 'นอน': 'nawn', 'ร้อง': 'lawng', 'เต้น': 'ten',
|
|
259
|
+
'เมา': 'mao', 'ดื่ม': 'duem', 'ส่ง': 'song', 'รอ': 'law',
|
|
260
|
+
'รัก': 'lak', 'รอด': 'lawt',
|
|
261
|
+
'หัวใจ': 'hua jai', 'ดวง': 'duang',
|
|
262
|
+
'ข้าว': 'khao', 'น้ำ': 'nam', 'เหล้า': 'lao',
|
|
263
|
+
'งาน': 'ngaan', 'เพลง': 'phleng', 'เสียง': 'siang',
|
|
264
|
+
'เป็น': 'pen', 'คือ': 'khue', 'ได้': 'dai', 'แต่': 'tae',
|
|
265
|
+
'มัน': 'man', 'ก็': 'gaw', 'ที่': 'thi',
|
|
266
|
+
'ให้': 'hai', 'กับ': 'kap', 'จาก': 'jaak',
|
|
267
|
+
'งานแต่ง': 'ngaan taeng', 'เจ้าของ': 'jao khawng',
|
|
268
|
+
'หน้าด้าน': 'naa daan', 'ข้างหลัง': 'khaang lang',
|
|
269
|
+
'ดู': 'du', 'ไกล': 'klai', 'กัน': 'kan', 'หน่อย': 'noi',
|
|
270
|
+
'น้อง': 'nawng', 'หล่า': 'laa',
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
# Lao/Isan pronunciation replacement rules (r -> l, etc.)
|
|
274
|
+
LAO_ROM_REPLACEMENTS = [
|
|
275
|
+
(re.compile(r'\bro\b'), 'lo'),
|
|
276
|
+
(re.compile(r'\bra'), 'la'),
|
|
277
|
+
(re.compile(r'\bri'), 'li'),
|
|
278
|
+
(re.compile(r'\bru'), 'lu'),
|
|
279
|
+
(re.compile(r'\brue'), 'lue'),
|
|
280
|
+
(re.compile(r'\brot\b'), 'lot'),
|
|
281
|
+
(re.compile(r'\brok\b'), 'lok'),
|
|
282
|
+
(re.compile(r'\brai\b'), 'lai'),
|
|
283
|
+
(re.compile(r'\brak\b'), 'lak'),
|
|
284
|
+
(re.compile(r'\brap\b'), 'lap'),
|
|
285
|
+
(re.compile(r'\brang'), 'lang'),
|
|
286
|
+
(re.compile(r'\breep'), 'leep'),
|
|
287
|
+
(re.compile(r'\breo'), 'leo'),
|
|
288
|
+
(re.compile(r'khr'), 'kh'),
|
|
289
|
+
(re.compile(r'phr'), 'ph'),
|
|
290
|
+
]
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Thai romanization with word-level corrections."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from .maps import THAI_WORD_MAP
|
|
6
|
+
from .utils import cleanup_romanization
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
# ==========================================================
|
|
10
|
+
# Systematic pronunciation fixes
|
|
11
|
+
# pythainlp's royin engine has consistent issues. Fix them
|
|
12
|
+
# all here rather than adding word-by-word map entries.
|
|
13
|
+
# ==========================================================
|
|
14
|
+
|
|
15
|
+
def _fix_romanization_per_word(rom, thai_word):
|
|
16
|
+
"""Fix systematic royin issues based on the original Thai word."""
|
|
17
|
+
if not rom or not thai_word:
|
|
18
|
+
return rom
|
|
19
|
+
|
|
20
|
+
result = rom
|
|
21
|
+
|
|
22
|
+
# 1. จ is ALWAYS "j", never "ch"
|
|
23
|
+
# royin uses "ch" for both จ and ช — fix จ words
|
|
24
|
+
if thai_word and thai_word[0] == 'จ' and result.startswith('ch'):
|
|
25
|
+
result = 'j' + result[2:]
|
|
26
|
+
|
|
27
|
+
# 2. รู → "roo" not "ru" (long vowel)
|
|
28
|
+
if 'รู' in thai_word and 'ru' in result:
|
|
29
|
+
result = result.replace('ru', 'roo')
|
|
30
|
+
|
|
31
|
+
# 3. Final ร is silent in many words, royin sometimes adds "n" or "r"
|
|
32
|
+
# (handled case by case in maps, hard to generalize)
|
|
33
|
+
|
|
34
|
+
# 4. ทร → "s" sound (not "thr") in certain words
|
|
35
|
+
# e.g. ทราบ = saap, ทราย = saai
|
|
36
|
+
if thai_word.startswith('ทร') and result.startswith('thr'):
|
|
37
|
+
result = 's' + result[3:]
|
|
38
|
+
|
|
39
|
+
return result
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# Global post-processing — systematic royin→preferred pronunciation
|
|
43
|
+
_GLOBAL_FIXES = [
|
|
44
|
+
# Vowels
|
|
45
|
+
(re.compile(r'\bru\b'), 'roo'), # รู → roo
|
|
46
|
+
(re.compile(r'\byu\b'), 'yoo'), # อยู่ → yoo
|
|
47
|
+
(re.compile(r'\bru '), 'roo '),
|
|
48
|
+
(re.compile(r'\byu '), 'yoo '),
|
|
49
|
+
# จ = always j (royin uses "ch" for both จ and ช)
|
|
50
|
+
# Handled per-word in _fix_romanization_per_word
|
|
51
|
+
# ก็ → gaw (not kaw)
|
|
52
|
+
(re.compile(r'\bkaw\b'), 'gaw'),
|
|
53
|
+
# เธอ → ter (not thoe)
|
|
54
|
+
(re.compile(r'\bthoe\b'), 'ter'),
|
|
55
|
+
# แล้ว → laew (not laeo)
|
|
56
|
+
(re.compile(r'\blaeo\b'), 'laew'),
|
|
57
|
+
# เลย → loei (already correct in royin)
|
|
58
|
+
# พี่ → pee (not phi)
|
|
59
|
+
(re.compile(r'\bphi\b'), 'pee'),
|
|
60
|
+
# ร้อง → rawng (not rong)
|
|
61
|
+
(re.compile(r'\brong\b'), 'rawng'),
|
|
62
|
+
# ทำ → tam (not tham)
|
|
63
|
+
(re.compile(r'\btham\b'), 'tam'),
|
|
64
|
+
# จ→j is handled per-word in _fix_romanization_per_word and THAI_WORD_MAP
|
|
65
|
+
# Do NOT globally replace cha→ja — it breaks ช words (ช้า = cha)
|
|
66
|
+
# ครับ → krap (not khrap)
|
|
67
|
+
(re.compile(r'\bkhrap\b'), 'krap'),
|
|
68
|
+
# คะ → ka (not kha when it's the polite particle)
|
|
69
|
+
# ทร → s sound
|
|
70
|
+
(re.compile(r'\bthr(?=a[ap]|ai)'), 's'),
|
|
71
|
+
# User style preferences
|
|
72
|
+
(re.compile(r'\bjet\b'), 'jed'),
|
|
73
|
+
(re.compile(r'\blook\b'), 'luk'),
|
|
74
|
+
(re.compile(r'\bsa bai\b'), 'sabai'),
|
|
75
|
+
(re.compile(r'\bdi\b'), 'dee'),
|
|
76
|
+
(re.compile(r'\bta\b'), 'dta'),
|
|
77
|
+
(re.compile(r'\bkan\b'), 'gan'),
|
|
78
|
+
(re.compile(r'\btonni\b'), 'tawnnee'),
|
|
79
|
+
(re.compile(r'\bthini\b'), 'tee nee'),
|
|
80
|
+
(re.compile(r'\bduaikan\b'), 'duay gan'),
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _apply_preferences(rom):
|
|
85
|
+
"""Apply systematic fixes and user preferences to final romanization."""
|
|
86
|
+
if not rom:
|
|
87
|
+
return rom
|
|
88
|
+
result = rom
|
|
89
|
+
for pattern, replacement in _GLOBAL_FIXES:
|
|
90
|
+
result = pattern.sub(replacement, result)
|
|
91
|
+
return result
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def romanize_thai(text):
|
|
95
|
+
"""Romanize Thai text with improved accuracy over pythainlp alone.
|
|
96
|
+
|
|
97
|
+
Uses pythainlp's newmm tokenizer and royin romanization engine as a base,
|
|
98
|
+
then applies word-level corrections from THAI_WORD_MAP to fix common errors
|
|
99
|
+
in colloquial speech, song lyrics, and everyday vocabulary.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
text: Thai text string to romanize.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
Lowercase romanized string.
|
|
106
|
+
"""
|
|
107
|
+
if not text:
|
|
108
|
+
return ''
|
|
109
|
+
|
|
110
|
+
try:
|
|
111
|
+
from pythainlp.tokenize import word_tokenize
|
|
112
|
+
from pythainlp.transliterate import romanize
|
|
113
|
+
except ImportError:
|
|
114
|
+
return ''
|
|
115
|
+
|
|
116
|
+
words = word_tokenize(text, engine='newmm')
|
|
117
|
+
|
|
118
|
+
# Multi-token compound map (token pairs that should merge)
|
|
119
|
+
COMPOUND_MAP = {
|
|
120
|
+
('บอ', 'กว่า'): 'bok wa',
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
# Pre-pass: merge tokens with following ๆ if the compound is in the map,
|
|
124
|
+
# and handle multi-token compounds
|
|
125
|
+
merged = []
|
|
126
|
+
i = 0
|
|
127
|
+
while i < len(words):
|
|
128
|
+
w = words[i].strip()
|
|
129
|
+
# Check two-token compounds
|
|
130
|
+
if i + 1 < len(words):
|
|
131
|
+
pair = (w, words[i + 1].strip())
|
|
132
|
+
if pair in COMPOUND_MAP:
|
|
133
|
+
merged.append(('__compound__', COMPOUND_MAP[pair]))
|
|
134
|
+
i += 2
|
|
135
|
+
continue
|
|
136
|
+
# Check ๆ compounds
|
|
137
|
+
if words[i + 1].strip() == 'ๆ':
|
|
138
|
+
compound = w + 'ๆ'
|
|
139
|
+
if compound in THAI_WORD_MAP:
|
|
140
|
+
merged.append(compound)
|
|
141
|
+
i += 2
|
|
142
|
+
continue
|
|
143
|
+
merged.append(w)
|
|
144
|
+
i += 1
|
|
145
|
+
|
|
146
|
+
pieces = []
|
|
147
|
+
for stripped in merged:
|
|
148
|
+
# Handle pre-resolved compound tuples
|
|
149
|
+
if isinstance(stripped, tuple) and stripped[0] == '__compound__':
|
|
150
|
+
pieces.append(stripped[1])
|
|
151
|
+
continue
|
|
152
|
+
if not stripped:
|
|
153
|
+
continue
|
|
154
|
+
# Handle ๆ (Mai Yamok) - repeats previous word
|
|
155
|
+
if stripped == 'ๆ':
|
|
156
|
+
if pieces:
|
|
157
|
+
last = pieces[-1].split()[-1]
|
|
158
|
+
pieces.append(last)
|
|
159
|
+
continue
|
|
160
|
+
if stripped in THAI_WORD_MAP:
|
|
161
|
+
val = THAI_WORD_MAP[stripped]
|
|
162
|
+
if val:
|
|
163
|
+
pieces.append(val)
|
|
164
|
+
continue
|
|
165
|
+
try:
|
|
166
|
+
rom = romanize(stripped, engine='royin')
|
|
167
|
+
rom = cleanup_romanization(rom)
|
|
168
|
+
rom = _fix_romanization_per_word(rom, stripped)
|
|
169
|
+
if rom:
|
|
170
|
+
pieces.append(rom)
|
|
171
|
+
except Exception:
|
|
172
|
+
pieces.append(stripped)
|
|
173
|
+
return _apply_preferences(' '.join(pieces))
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Utility functions for romanization cleanup."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def cleanup_romanization(rom):
|
|
7
|
+
"""Strip leaked Thai/Lao characters and fix whitespace artifacts.
|
|
8
|
+
|
|
9
|
+
After romanization, stray Thai (U+0E00-U+0E7F) or Lao (U+0E80-U+0EFF)
|
|
10
|
+
characters sometimes remain. This function removes them and normalizes
|
|
11
|
+
whitespace.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
rom: Raw romanized string.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
Cleaned romanized string.
|
|
18
|
+
"""
|
|
19
|
+
if not rom:
|
|
20
|
+
return ''
|
|
21
|
+
cleaned = re.sub(r'[\u0E00-\u0E7F\u0E80-\u0EFF]', '', rom)
|
|
22
|
+
cleaned = re.sub(r'\s+', ' ', cleaned).strip()
|
|
23
|
+
return cleaned
|
|
File without changes
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"""Tests for thairom romanization.
|
|
2
|
+
|
|
3
|
+
Test cases derived from ground truth data covering song lyrics,
|
|
4
|
+
colloquial speech, common phrases, and Isan/Lao dialect.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from thairom import romanize, romanize_thai, romanize_lao
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# ============================================================
|
|
13
|
+
# Thai romanization tests
|
|
14
|
+
# ============================================================
|
|
15
|
+
|
|
16
|
+
class TestRomanizeThai:
|
|
17
|
+
"""Test romanize_thai against ground truth Thai examples."""
|
|
18
|
+
|
|
19
|
+
def test_empty_input(self):
|
|
20
|
+
assert romanize_thai('') == ''
|
|
21
|
+
|
|
22
|
+
def test_none_input(self):
|
|
23
|
+
assert romanize_thai(None) == ''
|
|
24
|
+
|
|
25
|
+
def test_greeting(self):
|
|
26
|
+
assert romanize_thai('สวัสดีครับ') == 'sawatdee krap'
|
|
27
|
+
|
|
28
|
+
def test_thank_you(self):
|
|
29
|
+
assert romanize_thai('ขอบคุณมาก') == 'khop khun mak'
|
|
30
|
+
|
|
31
|
+
def test_i_love_you(self):
|
|
32
|
+
assert romanize_thai('ฉันรักเธอ') == 'chan rak ter'
|
|
33
|
+
|
|
34
|
+
def test_where_have_you_been(self):
|
|
35
|
+
assert romanize_thai('ไปไหนมา') == 'pai nai ma'
|
|
36
|
+
|
|
37
|
+
def test_how_are_you(self):
|
|
38
|
+
assert romanize_thai('สบายดีไหม') == 'sabai dee mai'
|
|
39
|
+
|
|
40
|
+
def test_never_mind(self):
|
|
41
|
+
assert romanize_thai('ไม่เป็นไร') == 'mai pen rai'
|
|
42
|
+
|
|
43
|
+
def test_heart(self):
|
|
44
|
+
assert romanize_thai('หัวใจ') == 'hua jai'
|
|
45
|
+
|
|
46
|
+
def test_understand(self):
|
|
47
|
+
assert romanize_thai('เข้าใจ') == 'khao jai'
|
|
48
|
+
|
|
49
|
+
def test_tears(self):
|
|
50
|
+
assert romanize_thai('น้ำตา') == 'nam dta'
|
|
51
|
+
|
|
52
|
+
def test_six(self):
|
|
53
|
+
assert romanize_thai('หก') == 'hok'
|
|
54
|
+
|
|
55
|
+
@pytest.mark.parametrize(
|
|
56
|
+
('thai', 'expected'),
|
|
57
|
+
[
|
|
58
|
+
('ศูนย์', 'soon'),
|
|
59
|
+
('หนึ่ง', 'neung'),
|
|
60
|
+
('สอง', 'song'),
|
|
61
|
+
('สาม', 'saam'),
|
|
62
|
+
('สี่', 'see'),
|
|
63
|
+
('ห้า', 'haa'),
|
|
64
|
+
('เจ็ด', 'jed'),
|
|
65
|
+
('แปด', 'paet'),
|
|
66
|
+
('เก้า', 'gao'),
|
|
67
|
+
('สิบ', 'sip'),
|
|
68
|
+
('สิบเอ็ด', 'sip et'),
|
|
69
|
+
('ยี่สิบ', 'yee sip'),
|
|
70
|
+
],
|
|
71
|
+
)
|
|
72
|
+
def test_numbers_preferred_style(self, thai, expected):
|
|
73
|
+
assert romanize_thai(thai) == expected
|
|
74
|
+
|
|
75
|
+
@pytest.mark.parametrize(
|
|
76
|
+
('thai', 'expected'),
|
|
77
|
+
[
|
|
78
|
+
('ผม', 'pom'),
|
|
79
|
+
('เรา', 'rao'),
|
|
80
|
+
('คุณ', 'khun'),
|
|
81
|
+
('เขา', 'khao'),
|
|
82
|
+
('แม่', 'mae'),
|
|
83
|
+
('พ่อ', 'paw'),
|
|
84
|
+
('ลูก', 'luk'),
|
|
85
|
+
('เพื่อน', 'puean'),
|
|
86
|
+
('ผู้หญิง', 'phu ying'),
|
|
87
|
+
('ผู้ชาย', 'phu chai'),
|
|
88
|
+
('คนไทย', 'khontai'),
|
|
89
|
+
('ครอบครัว', 'kropkrua'),
|
|
90
|
+
('เหรอ', 'ror'),
|
|
91
|
+
('ขอโทษ', 'kho thot'),
|
|
92
|
+
('สบายดีไหม', 'sabai dee mai'),
|
|
93
|
+
('วันนี้', 'wan nee'),
|
|
94
|
+
('พรุ่งนี้', 'prung nee'),
|
|
95
|
+
('เมื่อวาน', 'muea wan'),
|
|
96
|
+
('ตอนนี้', 'tawnnee'),
|
|
97
|
+
('ที่นี่', 'tee nee'),
|
|
98
|
+
('อยู่ตรงนี้', 'yoo trong nee'),
|
|
99
|
+
('คิดถึงเธอ', 'kit tueng ter'),
|
|
100
|
+
('อยู่ด้วยกัน', 'yoo duay gan'),
|
|
101
|
+
],
|
|
102
|
+
)
|
|
103
|
+
def test_first_lesson_and_daily_speech_preferred_style(self, thai, expected):
|
|
104
|
+
assert romanize_thai(thai) == expected
|
|
105
|
+
|
|
106
|
+
@pytest.mark.parametrize(
|
|
107
|
+
('thai', 'expected'),
|
|
108
|
+
[
|
|
109
|
+
('เด็ก', 'dek'),
|
|
110
|
+
('ดี', 'dee'),
|
|
111
|
+
('ดู', 'du'),
|
|
112
|
+
('ได้', 'dai'),
|
|
113
|
+
('ด้วย', 'duay'),
|
|
114
|
+
('คนเดียว', 'khon diao'),
|
|
115
|
+
],
|
|
116
|
+
)
|
|
117
|
+
def test_daw_dek_uses_d_not_dt(self, thai, expected):
|
|
118
|
+
assert romanize_thai(thai) == expected
|
|
119
|
+
|
|
120
|
+
def test_love_noun(self):
|
|
121
|
+
assert romanize_thai('ความรัก') == 'khwam rak'
|
|
122
|
+
|
|
123
|
+
def test_time(self):
|
|
124
|
+
assert romanize_thai('เวลา') == 'welaa'
|
|
125
|
+
|
|
126
|
+
def test_all_the_time(self):
|
|
127
|
+
assert romanize_thai('ตลอดเวลา') == 'talod welaa'
|
|
128
|
+
|
|
129
|
+
def test_song_lyric_pretend_to_care(self):
|
|
130
|
+
assert romanize_thai('แกล้งเป็นห่วง') == 'klaeng pen huang'
|
|
131
|
+
|
|
132
|
+
def test_song_lyric_give_importance(self):
|
|
133
|
+
assert romanize_thai('ให้ความสำคัญ') == 'hai khwam sam khan'
|
|
134
|
+
|
|
135
|
+
def test_song_lyric_waste_tears(self):
|
|
136
|
+
assert romanize_thai('เสียน้ำตา') == 'sia nam dta'
|
|
137
|
+
|
|
138
|
+
def test_song_lyric_those_are_all(self):
|
|
139
|
+
assert romanize_thai('ทั้งนั้น') == 'thang nan'
|
|
140
|
+
|
|
141
|
+
def test_song_lyric_never_bound(self):
|
|
142
|
+
assert romanize_thai('ไม่เคยผูกพัน') == 'mai khoei phuk phan'
|
|
143
|
+
|
|
144
|
+
def test_song_lyric_leave_immediately(self):
|
|
145
|
+
assert romanize_thai('ทิ้งชิ่งไปทันที') == 'thing jing pai tawntee'
|
|
146
|
+
|
|
147
|
+
def test_song_lyric_sit_and_lament(self):
|
|
148
|
+
assert romanize_thai('นั่งเพ้อรำพัน') == 'nang phoe ram phan'
|
|
149
|
+
|
|
150
|
+
def test_song_lyric_like_this(self):
|
|
151
|
+
assert romanize_thai('อยู่อย่างนี้') == 'yoo yang nee'
|
|
152
|
+
|
|
153
|
+
def test_colloquial_pup_pap(self):
|
|
154
|
+
assert romanize_thai('ปุ๊บๆปั๊บๆก็คงไป') == 'pup pap gaw khong pai'
|
|
155
|
+
|
|
156
|
+
def test_eaten_yet(self):
|
|
157
|
+
assert romanize_thai('กินข้าวหรือยัง') == 'kin khao rue yang'
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
# ============================================================
|
|
161
|
+
# Lao/Isan romanization tests
|
|
162
|
+
# ============================================================
|
|
163
|
+
|
|
164
|
+
class TestRomanizeLao:
|
|
165
|
+
"""Test romanize_lao against ground truth Lao/Isan examples."""
|
|
166
|
+
|
|
167
|
+
def test_empty_input(self):
|
|
168
|
+
assert romanize_lao('') == ''
|
|
169
|
+
|
|
170
|
+
def test_none_input(self):
|
|
171
|
+
assert romanize_lao(None) == ''
|
|
172
|
+
|
|
173
|
+
def test_love_you_much(self):
|
|
174
|
+
assert romanize_lao('ฮักเจ้าหลาย') == 'hak jao laai'
|
|
175
|
+
|
|
176
|
+
def test_dont_know_what_to_do(self):
|
|
177
|
+
assert romanize_lao('บ่ฮู้จะเฮ็ดจั่งใด') == 'baw huu cha het jang dai'
|
|
178
|
+
|
|
179
|
+
def test_we_will_go_together(self):
|
|
180
|
+
assert romanize_lao('เฮาสิไปนำกัน') == 'hao si pai nam kan'
|
|
181
|
+
|
|
182
|
+
def test_our_house_is_far(self):
|
|
183
|
+
assert romanize_lao('เฮือนเฮาอยู่ไกล') == 'huean hao yuu klai'
|
|
184
|
+
|
|
185
|
+
def test_little_sister_very(self):
|
|
186
|
+
assert romanize_lao('น้องหล่าคัก') == 'nawng laa khak'
|
|
187
|
+
|
|
188
|
+
def test_really_indeed(self):
|
|
189
|
+
assert romanize_lao('อีหลีเด้อ') == 'ii lii doe'
|
|
190
|
+
|
|
191
|
+
def test_talk_a_bit(self):
|
|
192
|
+
assert romanize_lao('เว้ากันหน่อย') == 'wao kan noi'
|
|
193
|
+
|
|
194
|
+
def test_look_and_see(self):
|
|
195
|
+
assert romanize_lao('เบิ่งดูแม่น') == 'boeng du maen'
|
|
196
|
+
|
|
197
|
+
def test_our_lady(self):
|
|
198
|
+
assert romanize_lao('ผู้สาวเฮา') == 'phuu sao hao'
|
|
199
|
+
|
|
200
|
+
def test_very_fun(self):
|
|
201
|
+
assert romanize_lao('ม่วนคัก') == 'muan khak'
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
# ============================================================
|
|
205
|
+
# Top-level romanize() dispatch tests
|
|
206
|
+
# ============================================================
|
|
207
|
+
|
|
208
|
+
class TestRomanizeDispatch:
|
|
209
|
+
"""Test the top-level romanize() function dispatches correctly."""
|
|
210
|
+
|
|
211
|
+
def test_default_is_thai(self):
|
|
212
|
+
assert romanize('หัวใจ') == 'hua jai'
|
|
213
|
+
|
|
214
|
+
def test_explicit_thai(self):
|
|
215
|
+
assert romanize('น้ำตา', lang='th') == 'nam dta'
|
|
216
|
+
|
|
217
|
+
def test_lao_dispatch(self):
|
|
218
|
+
assert romanize('ฮักเจ้าหลาย', lang='lo') == 'hak jao laai'
|
|
219
|
+
|
|
220
|
+
def test_lao_explicit(self):
|
|
221
|
+
assert romanize('ม่วนคัก', lang='lo') == 'muan khak'
|