KOROMAN - Korean Romanizer
KOROMAN is a multilingual Romanizer for Korean text, based on the Revised Romanization system (국립국어원 표기법) with additional pronunciation rules. It converts Hangul syllables into Romanized Latin script across multiple languages: JavaScript, Python, and Java.
🌐 Live Demo
📦 Features
- Supports Revised Romanization of Korean
- Applies key Korean phonological rules:
- Liaison (연음화)
- Nasal assimilation (비음화)
- Lateralization (유음화)
- Aspiration / consonant cluster simplification — refined in 1.0.15
- Casing options (lower, upper, capitalized) — accepts full names, short aliases, or numeric codes (1.0.14+)
- Optional hyphen at ambiguous syllable boundaries (
use_hyphen, 1.0.15+) — e.g. 중앙 →jung-ang, 반구대 →ban-gudae, 해운대 →hae-undae - User dictionary (
custom_dictionary, 1.0.15+) — per-call or persistent module-level store; match Korean words and emit user-provided Romanization with the highest priority (casing/phonological rules are not applied to dictionary values) - Fully tested in each language
🆕 1.0.16 changes
- 29항 n-insertion (
-잎trigger), cluster liaison,밟-,ㄷ+ㅎ+ㅣ→치 - Persistent dictionary starts empty — see CHANGELOG.md
1.0.15 changes (heads-up)
- Aspiration policy changed. Receiver-final ㄱ/ㄷ/ㅂ + initial ㅎ is now romanized as a single fortis (
k/t/p/ch) consistently. The previous noun-only exception (e.g. 묵호 →Mukho, 집현전 →Jiphyeonjeon) required morphological analysis we cannot perform reliably, so it has been dropped:묵호 → muko,집현전 → jipyeonjeon,잡혀 → japyeo,놓다 → nota
- Consonant cluster simplification (자음군 단순화) fixed: 흙→
heuk, 닭→dak, 삶→sam, 읊→eup, 값→gap. - ᆶ + ᄋ liaison preserved: 잃어→
ireo(previouslyileo). - Final ㄷ / ㅎ map to
tin standard mode (previouslyd/h). The legacy mapping is kept foruse_pronunciation_rules=Falseto preserve 1.0.14 behaviour.
🚀 Getting Started
Python
pip install koroman
from koroman import romanize
# Basic usage
romanize("한글") # → "hangeul"
# With pronunciation rules disabled
romanize("해돋이", use_pronunciation_rules=False) # → "haedodi"
# With pronunciation rules enabled (default)
romanize("해돋이") # → "haedoji"
# Casing options (full names)
romanize("한글", casing_option="uppercase") # → "HANGEUL"
romanize("안녕 한글", casing_option="capitalize-word") # → "Annyeong Hangeul"
romanize("안녕\n한글 로마자 변환", casing_option="capitalize-line") # → "Annyeong\nHangeul romaja byeonhwan"
# 1.0.14+ : short aliases / numeric codes are also accepted
romanize("한글", casing_option="u") # → "HANGEUL"
romanize("한글", casing_option="uc") # → "HANGEUL"
romanize("한글", casing_option=1) # → "HANGEUL"
romanize("안녕 한글", casing_option="cw") # → "Annyeong Hangeul"
romanize("안녕\n한글 로마자 변환", casing_option=2) # → "Annyeong\nHangeul romaja byeonhwan"
# Combining options
romanize("해돋이", use_pronunciation_rules=False, casing_option="uc") # → "HAEDODI"
romanize("해돋이", use_pronunciation_rules=False, casing_option=1) # → "HAEDODI"
# 1.0.15+ : use_hyphen — insert '-' at ambiguous syllable boundaries
romanize("중앙", use_hyphen=True) # → "jung-ang"
romanize("반구대", use_hyphen=True) # → "ban-gudae"
romanize("해운대", use_hyphen=True) # → "hae-undae"
# 1.0.15+ : custom_dictionary — per-call user dictionary (highest priority, casing-safe)
romanize("나는 김철수입니다",
custom_dictionary={"김철수": "Kim Chul-soo"}) # → "naneun Kim Chul-sooimnida"
# 1.0.15+ : persistent dictionary (module-level store)
from koroman import (
set_custom_dictionary, add_custom_dictionary,
remove_custom_dictionary_entry, clear_custom_dictionary, get_custom_dictionary,
)
set_custom_dictionary({"김철수": "Kim Chul-soo", "서울": "Seoul"})
add_custom_dictionary("부산", "Busan")
romanize("서울에 사는 김철수") # → "Seoule saneun Kim Chul-soo"
romanize("부산", use_custom_dictionary=False) # → "busan"
clear_custom_dictionary()
casing_option aliases (1.0.14+)
| Canonical | Aliases | Numeric |
|---|---|---|
lowercase |
lower, l, lc |
0 |
uppercase |
upper, u, uc |
1 |
capitalize-line |
cap-line, cline, cl |
2 |
capitalize-word |
cap-word, cword, cw |
3 |
Case-insensitive. Unknown / None falls back to lowercase.
Persistent custom_dictionary API (1.0.15+)
| API | Description |
|---|---|
set_custom_dictionary(dict) |
Replace the entire store. None/empty dict clears it. |
add_custom_dictionary(dict) / add_custom_dictionary(key, value) |
Merge/insert entries. |
remove_custom_dictionary_entry(key) |
Remove a single key (returns True on success). |
clear_custom_dictionary() |
Empty the store. |
get_custom_dictionary() |
Shallow snapshot of the current store. |
Combine with the per-call custom_dictionary option to override the store on a single call (same-key entries in the option win). Set use_custom_dictionary=False on a call to ignore the persistent store entirely.
📜 LICENSE
2025 ⓒ Donghe Youn (Daissue)
Metadata
Release files for koroman 1.0.16
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| koroman-1.0.16.tar.gz | 18.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| koroman-1.0.16-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 31.5 kB
Release files / koroman-1.0.16.tar.gz
| Download URL | koroman-1.0.16.tar.gz |
|---|---|
| Size | 18.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
77ff76e6c7d9c93d22294467b0eff569bb1cdb7df1c0d89c5b42ffa96c92e342
|
|
BLAKE2b-256 checksum How to use checksums |
04eccdc4db2d82fbeef422f6cde456c323683c12c7154945745e73f3e521a9bc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|
Release files / koroman-1.0.16-py3-none-any.whl
| Download URL | koroman-1.0.16-py3-none-any.whl |
|---|---|
| Size | 13.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c718185d3c2dd713caf58c66c09804ffd8a49641da5cca0b25d938e66b79c6fa
|
|
BLAKE2b-256 checksum How to use checksums |
29b3bef065694b5d2f9d32524f83c20f654378ecc57ee2424b8f2938f2418919
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.2
|