Browse Source

Finish Korean name module.

scossu 1 year ago
parent
commit
7bb65e13f9

+ 3 - 0
scriptshifter/hooks/korean/FKR_index.csv

@@ -178,3 +178,6 @@ FKR177,한자 率(률)의 발음 처리,Chinese characters 率(률)의 발음 
 FKR178,한자 慄(률)의 발음 처리,Chinese characters 慄(률)의 발음 처리
 FKR179,한자 栗(률)의 발음 처리,Chinese characters 栗(률)의 발음 처리
 FKR180,,Katakana
+FKR181,,2-character names
+FKR182,,1-character Chinese names
+FKR183,,1-character names

+ 477 - 0
scriptshifter/hooks/korean/data.yml

@@ -11938,3 +11938,480 @@ fkr180:
   "ヱ": "에"
   "ヲ": "오"
 
+fkr181:
+  # #1
+  "南宮": "Namgung"
+  "諸葛": "Chegal"
+  "皇甫": "Hwangbo"
+  "鮮于": "Sŏnu"
+  "西門": "Sŏmun"
+  "東方": "Tongbang"
+  "獨孤": "Tokko"
+  "司空": "Sagong"
+  "司馬": "Sama"
+  "乙支": "Ŭlchi"
+  # #2
+  "남궁": "Namgung"
+  "제갈": "Chegal"
+  "황보": "Hwangbo"
+  "선우": "Sŏnu"
+  "서문": "Sŏmun"
+  "동방": "Tongbang"
+  "독고": "Tokko"
+  "사공": "Sagong"
+  "사마": "Sama"
+  "을지": "Ŭlchi"
+
+fkr182:
+  "賈": "가"
+  "簡": "간"
+  "葛": "갈"
+  "甘": "감"
+  "剛": "강"
+  "姜": "강"
+  "康": "강"
+  "强": "강"
+  "彊": "강"
+  "介": "개"
+  "堅": "견"
+  "甄": "견"
+  "京": "경"
+  "慶": "경"
+  "景": "경"
+  "桂": "계"
+  "高": "고"
+  "曲": "곡"
+  "公": "공"
+  "孔": "공"
+  "郭": "곽"
+  "橋": "교"
+  "丘": "구"
+  "具": "구"
+  "邱": "구"
+  "國": "국"
+  "菊": "국"
+  "鞠": "국"
+  "君": "군"
+  "弓": "궁"
+  "鴌": "궉"
+  "權": "권"
+  "斤": "근"
+  "琴": "금"
+  "奇": "기"
+  "箕": "기"
+  "吉": "길"
+  "金": "김"
+  "金": "김"
+  "羅": "나"
+  "欒": "난"
+  "南": "남"
+  "浪": "낭"
+  "乃": "내"
+  "奈": "내"
+  "盧": "노"
+  "路": "노"
+  "魯": "노"
+  "賴": "뇌"
+  "雷": "뇌"
+  "樓": "누"
+  "單": "단"
+  "段": "단"
+  "端": "단"
+  "譚": "담"
+  "唐": "당"
+  "大": "대"
+  "道": "도"
+  "都": "도"
+  "陶": "도"
+  "敦": "돈"
+  "頓": "돈"
+  "董": "동"
+  "杜": "두"
+  "頭": "두"
+  "柳": "류"
+  "馬": "마"
+  "麻": "마"
+  "萬": "만"
+  "梅": "매"
+  "孟": "맹"
+  "明": "명"
+  "毛": "모"
+  "牟": "모"
+  "睦": "목"
+  "苗": "묘"
+  "墨": "묵"
+  "文": "문"
+  "米": "미"
+  "閔": "민"
+  "朴": "박"
+  "潘": "반"
+  "班": "반"
+  "房": "방"
+  "方": "방"
+  "邦": "방"
+  "龐": "방"
+  "裵": "배"
+  "白": "백"
+  "凡": "범"
+  "范": "범"
+  "卞": "변"
+  "邊": "변"
+  "卜": "복"
+  "奉": "봉"
+  "鳳": "봉"
+  "傅": "부"
+  "夫": "부"
+  "丕": "비"
+  "彬": "빈"
+  "賓": "빈"
+  "冰": "빙"
+  "氷": "빙"
+  "史": "사"
+  "舍": "사"
+  "謝": "사"
+  "杉": "삼"
+  "森": "삼"
+  "尙": "상"
+  "徐": "서"
+  "西": "서"
+  "昔": "석"
+  "石": "석"
+  "宣": "선"
+  "楔": "설"
+  "薛": "설"
+  "葉": "섭"
+  "成": "성"
+  "星": "성"
+  "肖": "소"
+  "蘇": "소"
+  "邵": "소"
+  "孫": "손"
+  "宋": "송"
+  "松": "송"
+  "水": "수"
+  "洙": "수"
+  "淳": "순"
+  "舜": "순"
+  "荀": "순"
+  "順": "순"
+  "承": "승"
+  "昇": "승"
+  "施": "시"
+  "柴": "시"
+  "愼": "신"
+  "申": "신"
+  "辛": "신"
+  "沈": "심"
+  "沈": "심"
+  "什": "십"
+  "阿": "아"
+  "安": "안"
+  "艾": "애"
+  "夜": "야"
+  "梁": "양"
+  "楊": "양"
+  "樑": "양"
+  "襄": "양"
+  "魚": "어"
+  "嚴": "엄"
+  "余": "여"
+  "呂": "여"
+  "汝": "여"
+  "延": "연"
+  "燕": "연"
+  "連": "연"
+  "廉": "염"
+  "葉": "엽"
+  "影": "영"
+  "榮": "영"
+  "永": "영"
+  "乂": "예"
+  "芮": "예"
+  "吳": "오"
+  "玉": "옥"
+  "溫": "온"
+  "邕": "옹"
+  "雍": "옹"
+  "王": "왕"
+  "姚": "요"
+  "龍": "용"
+  "于": "우"
+  "宇": "우"
+  "禹": "우"
+  "芸": "운"
+  "雲": "운"
+  "元": "원"
+  "苑": "원"
+  "袁": "원"
+  "韋": "위"
+  "魏": "위"
+  "兪": "유"
+  "劉": "유"
+  "庾": "유"
+  "陸": "육"
+  "尹": "윤"
+  "殷": "은"
+  "陰": "음"
+  "伊": "이"
+  "李": "이"
+  "異": "이"
+  "印": "인"
+  "任": "임"
+  "林": "임"
+  "慈": "자"
+  "張": "장"
+  "章": "장"
+  "莊": "장"
+  "蔣": "장"
+  "邸": "저"
+  "全": "전"
+  "田": "전"
+  "錢": "전"
+  "占": "점"
+  "丁": "정"
+  "程": "정"
+  "鄭": "정"
+  "諸": "제"
+  "齊": "제"
+  "曺": "조"
+  "趙": "조"
+  "宗": "종"
+  "鍾": "종"
+  "左": "좌"
+  "周": "주"
+  "朱": "주"
+  "俊": "준"
+  "汁": "즙"
+  "增": "증"
+  "曾": "증"
+  "智": "지"
+  "池": "지"
+  "晋": "진"
+  "眞": "진"
+  "秦": "진"
+  "陳": "진"
+  "車": "차"
+  "倉": "창"
+  "昌": "창"
+  "菜": "채"
+  "蔡": "채"
+  "采": "채"
+  "千": "천"
+  "天": "천"
+  "初": "초"
+  "楚": "초"
+  "肖": "초"
+  "崔": "최"
+  "秋": "추"
+  "鄒": "추"
+  "椿": "춘"
+  "卓": "탁"
+  "彈": "탄"
+  "太": "태"
+  "判": "판"
+  "彭": "팽"
+  "扁": "편"
+  "片": "편"
+  "平": "평"
+  "包": "포"
+  "表": "표"
+  "馮": "풍"
+  "皮": "피"
+  "弼": "필"
+  "夏": "하"
+  "河": "하"
+  "學": "학"
+  "漢": "한"
+  "韓": "한"
+  "咸": "함"
+  "海": "해"
+  "許": "허"
+  "玄": "현"
+  "邢": "형"
+  "扈": "호"
+  "胡": "호"
+  "鎬": "호"
+  "洪": "홍"
+  "化": "화"
+  "桓": "환"
+  "黃": "황"
+  "候": "후"
+  "后": "후"
+  "興": "흥"
+
+fkr183:
+  "김": "Kim"
+  "가": "Ka"
+  "간": "Kan"
+  "갈": "Kal"
+  "감": "Kam"
+  "강": "Kang"
+  "개": "Kae"
+  "견": "Kyŏn"
+  "경": "Kyŏng"
+  "계": "Kye"
+  "고": "Ko"
+  "곡": "Kok"
+  "공": "Kong"
+  "곽": "Kwak"
+  "교": "Kyo"
+  "구": "Ku"
+  "국": "Kuk"
+  "군": "Kun"
+  "궁": "Kung"
+  "궉": "Kwŏk"
+  "권": "Kwŏn"
+  "근": "Kŭn"
+  "금": "Kŭm"
+  "기": "Ki"
+  "길": "Kil"
+  "나": "Na"
+  "난": "Nan"
+  "남": "Nam"
+  "낭": "Nang"
+  "내": "Nae"
+  "노": "No"
+  "뇌": "Noe"
+  "누": "Nu"
+  "단": "Tan"
+  "담": "Tam"
+  "당": "Tang"
+  "대": "Tae"
+  "도": "To"
+  "독": "Tok"
+  "돈": "Ton"
+  "동": "Tong"
+  "두": "Tu"
+  "라": "Na"
+  "로": "No"
+  "류": "Yu"
+  "리": "Yi"
+  "림": "Im"
+  "마": "Ma"
+  "만": "Man"
+  "매": "Mae"
+  "맹": "Maeng"
+  "명": "Myŏng"
+  "모": "Mo"
+  "목": "Mok"
+  "묘": "Myo"
+  "묵": "Muk"
+  "문": "Mun"
+  "미": "Mi"
+  "민": "Min"
+  "박": "Pak"
+  "반": "Pan"
+  "방": "Pang"
+  "배": "Pae"
+  "백": "Paek"
+  "범": "Pŏm"
+  "변": "Pyŏn"
+  "복": "Pok"
+  "봉": "Pong"
+  "부": "Pu"
+  "비": "Pi"
+  "빈": "Pin"
+  "빙": "Ping"
+  "사": "Sa"
+  "삼": "Sam"
+  "상": "Sang"
+  "서": "Sŏ"
+  "석": "Sŏk"
+  "선": "Sŏn"
+  "설": "Sŏl"
+  "섭": "Sŏp"
+  "성": "Sŏng"
+  "소": "So"
+  "손": "Son"
+  "송": "Song"
+  "수": "Su"
+  "순": "Sun"
+  "승": "Sŭng"
+  "시": "Si"
+  "신": "Sin"
+  "심": "Sim"
+  "십": "Sip"
+  "아": "A"
+  "안": "An"
+  "애": "Ae"
+  "야": "Ya"
+  "양": "Yang"
+  "어": "Ŏ"
+  "엄": "Ŏm"
+  "여": "Yŏ"
+  "연": "Yŏn"
+  "염": "Yŏm"
+  "엽": "Yŏp"
+  "영": "Yŏng"
+  "예": "Ye"
+  "오": "O"
+  "옥": "Ok"
+  "온": "On"
+  "옹": "Ong"
+  "왕": "Wang"
+  "요": "Yo"
+  "용": "Yong"
+  "우": "U"
+  "운": "Un"
+  "원": "Wŏn"
+  "위": "Wi"
+  "유": "Yu"
+  "육": "Yuk"
+  "윤": "Yun"
+  "은": "Ŭn"
+  "음": "Ŭm"
+  "이": "Yi"
+  "인": "In"
+  "임": "Im"
+  "자": "Cha"
+  "장": "Chang"
+  "저": "Chŏ"
+  "전": "Chŏn"
+  "점": "Chŏm"
+  "정": "Chŏng"
+  "제": "Che"
+  "조": "Cho"
+  "종": "Chong"
+  "좌": "Chwa"
+  "주": "Chu"
+  "준": "Chun"
+  "즙": "Chŭp"
+  "증": "Chŭng"
+  "지": "Chi"
+  "진": "Chin"
+  "차": "Ch'a"
+  "창": "Ch'ang"
+  "채": "Ch'ae"
+  "천": "Ch'ŏn"
+  "초": "Ch'o"
+  "최": "Ch'oe"
+  "추": "Ch'u"
+  "춘": "Ch'un"
+  "침": "Sim"
+  "탁": "T'ak"
+  "탄": "T'an"
+  "태": "T'ae"
+  "판": "P'an"
+  "팽": "P'aeng"
+  "편": "P'yŏn"
+  "평": "P'yŏng"
+  "포": "P'o"
+  "표": "P'yo"
+  "풍": "P'ung"
+  "피": "P'i"
+  "필": "P'il"
+  "하": "Ha"
+  "학": "Hak"
+  "한": "Han"
+  "함": "Ham"
+  "해": "Hae"
+  "허": "Hŏ"
+  "현": "Hyŏn"
+  "형": "Hyŏng"
+  "호": "Ho"
+  "홍": "Hong"
+  "화": "Hwa"
+  "환": "Hwan"
+  "황": "Hwang"
+  "후": "Hu"
+  "흥": "Hŭng"

+ 54 - 15
scriptshifter/hooks/korean/romanizer.py

@@ -122,10 +122,6 @@ def _romanize_names(src):
 
     warnings = []
 
-    if re.find("[a-z]|[A-Z]|[0-9]", src):
-        warnings.append("Source may not be a personal name.")
-        return None, warnings
-
     # FKR001: Conversion, Family names in Chinese (dealing with 金 and 李)
     # FKR002: Family names, Initial sound law
     replaced = False
@@ -141,24 +137,51 @@ def _romanize_names(src):
     # FKR003: First name, Chinese Character Conversion
     src = _hancha2hangul(_marc8_hancha(src))
 
-    if re.find("[a-zA-Z0-9]", src):
-        warnings.append(f"{src} may not be a personal name.")
+    if re.search("[a-zA-Z0-9]", src):
+        warnings.append(f"{src} is not a recognized personal name.")
         return None, warnings
 
-    src, _warnings = _parse_kor_name(re.sub(r"\s{2,}", " ", src.strip()))
+    # `parsed` can either be a modified Korean string with markers, or in case
+    # of a foreign name, the final romanized name.
+    parsed, _warnings = _parse_kor_name(re.sub(r"\s{2,}", " ", src.strip()))
 
     if len(_warnings):
         warnings += _warnings
 
-    if "~" in src:
-        lname, fname = src.split("~", 1)
-        fname_rom = _kor_fname_rom(fname)
+    if parsed:
+        if "~" in parsed:
+            lname, fname = parsed.split("~", 1)
+            fname_rom = _kor_fname_rom(fname)
 
-    return rom, warnings
+            lname_rom_ls = [_kor_lname_rom(n) for n in lname.split("+")]
+
+            if not any(lname_rom_ls):
+                warnings.append(f"{parsed} is not a recognized Korean name.")
+                return None, warnings
+
+            lname_rom = " ".join(lname_rom_ls)
+
+            rom = f"{lname_rom} {fname_rom}"
+
+            if False:
+                # TODO add option for authoritative name.
+                rom_ls = rom.rsplit(" ", 1)
+                rom = ", ".join(rom_ls)
+
+            return rom, warnings
+
+        else:
+            warnings.append("Romanized as a foreign name.")
+            return parsed, warnings
+
+    warnings.append(f"{src} is not a recognized Korean name.")
+    return None, warnings
 
 
 def _parse_kor_name(src):
+    parsed = None
     warnings = []
+
     # FKR004: Check first two characters. Two-syllable family name or not?
     two_syl_fname = False
     for ptn in KCONF["fkr004"]:
@@ -174,7 +197,7 @@ def _parse_kor_name(src):
     # FKR0006: Error if more than 2 spaces
     if ct_spaces > 2:
         warnings.append("ERROR: not a name (too many spaces)")
-        return None, warnings
+        return parsed, warnings
 
     # FKR007: 2 spaces (two family names)
     if ct_spaces == 2:
@@ -545,7 +568,7 @@ def _kor_fname_rom(fname):
             j = True
 
     k = False
-    for tok in KCONF["fkr011"]["dino_ini"]:
+    for tok in KCONF["fkr011"]["sino_ini"]:
         if tok in rom:
             k = True
 
@@ -595,7 +618,7 @@ def _kor_fname_rom(fname):
     _fkr_log(30)
     for k, cmap in KCONF["fkr030"].items():
         logger.debug(f"Applying FKR030[\"{k}\"]")
-        rom = _replace_map(cmap)
+        rom = _replace_map(rom, cmap)
 
     rom = _replace_map(rom.replace("#", ""), {"swi": "shwi", "Swi": "Shwi"}, 1)
 
@@ -608,7 +631,7 @@ def _kor_fname_rom(fname):
     _fkr_log(31)
     for k, cmap in KCONF["fkr031"].items():
         logger.debug(f"Applying FKR031[\"{k}\"]")
-        rom = _replace_map(cmap)
+        rom = _replace_map(rom, cmap)
 
     # FKR032: Capitalization
     rom = rom[0].upper() + rom[1:]
@@ -627,6 +650,22 @@ def _kor_fname_rom(fname):
     return rom
 
 
+def _kor_lname_rom(lname):
+    if len(lname) == 2:
+        # FKR181: 2-charater names.
+        _fkr_log(181)
+        rom = _replace_map(lname, KCONF["fkr181"])
+    else:
+        # FKR182: 1-charater Chinese names.
+        _fkr_log(182)
+        lname = _replace_map(lname, KCONF["fkr182"])
+        # FKR183: 1-charater names.
+        _fkr_log(183)
+        rom = _replace_map(lname, KCONF["fkr183"])
+
+    return rom if lname != rom else False
+
+
 def _fkr_log(fkr_i):
     fkr_k = f"FKR{fkr_i:03}"
     logger.debug(f"Applying {fkr_k}: {FKR_IDX[fkr_k]}")

+ 869 - 0
tests/korean_tests.txt

@@ -0,0 +1,869 @@
+- Kim chŏngil kongp'o rŭl ssoa ollida
+?     ^
++ Kim Chŏng-il kongp'o rŭl ssoa ollida
+?     ^    +
+ : S2R transliteration error for korean_nonames!
+Original: 김 정일 공포 를 쏘아 올리다
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Kim ch'angmo ŭi Taehan Min'guk sŏnmul opsyŏn kyogwasŏ" != "Kim Ch'ang-mo ŭi Taehan Min'guk sŏnmul opsyŏn kyogwasŏ"
+- Kim ch'angmo ŭi Taehan Min'guk sŏnmul opsyŏn kyogwasŏ
+?     ^
++ Kim Ch'ang-mo ŭi Taehan Min'guk sŏnmul opsyŏn kyogwasŏ
+?     ^     +
+ : S2R transliteration error for korean_nonames!
+Original: 김 창모 의 대한 민국 선물 옵션 교과서
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Tasŏk ryu yŏngmo - uri mal kwa uri kŭl ro ch'ŏrhakhan k'ŭn sasangga" != "Tasŏk Yu Yŏng-mo - uri mal kwa uri kŭl ro ch'ŏrhakhan k'ŭn sasangga"
+- Tasŏk ryu yŏngmo - uri mal kwa uri kŭl ro ch'ŏrhakhan k'ŭn sasangga
+?       ^^  ^
++ Tasŏk Yu Yŏng-mo - uri mal kwa uri kŭl ro ch'ŏrhakhan k'ŭn sasangga
+?       ^  ^   +
+ : S2R transliteration error for korean_nonames!
+Original: 다석 류 영모 - 우리 말 과 우리 글 로 철학한 큰 사상가
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Taehan Min'guk 20-tae chŏlmang ŭi t'ŭraiaenggŭl ŭl nŏmŏ" != "Taehan Min 'guk 20-tae chŏlmang ŭi t'ŭraiaenggŭl ŭl nŏmŏ"
+- Taehan Min'guk 20-tae chŏlmang ŭi t'ŭraiaenggŭl ŭl nŏmŏ
++ Taehan Min 'guk 20-tae chŏlmang ŭi t'ŭraiaenggŭl ŭl nŏmŏ
+?           +
+ : S2R transliteration error for korean_nonames!
+Original: 대한민국 20대 절망 의 트라이앵글 을 넘어
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'To yŏnmyŏng ŭi sasang kwa munhak' != 'To Yŏn-myŏng ŭi sasang kwa munhak'
+- To yŏnmyŏng ŭi sasang kwa munhak
+?    ^
++ To Yŏn-myŏng ŭi sasang kwa munhak
+?    ^  +
+ : S2R transliteration error for korean_nonames!
+Original: 도 연명 의 사상 과 문학
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Munhak cheguk: ch'oe kangmin p'yŏngnonjip" != "Munhak cheguk: Ch'oe Kang-min p'yŏngnonjip"
+- Munhak cheguk: ch'oe kangmin p'yŏngnonjip
+?                ^     ^
++ Munhak cheguk: Ch'oe Kang-min p'yŏngnonjip
+?                ^     ^   +
+ : S2R transliteration error for korean_nonames!
+Original: 문학 제국 : 최 강민 평론집
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Pak kijun ŭi Han'guk manhwa yasa" != "Pak Ki-jun ŭi Han'guk manhwa yasa"
+- Pak kijun ŭi Han'guk manhwa yasa
+?     ^
++ Pak Ki-jun ŭi Han'guk manhwa yasa
+?     ^ +
+ : S2R transliteration error for korean_nonames!
+Original: 박 기준 의 한국 만화 야사
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Pak nohong ŭi taejung yŏnyesa 1' != 'Pak No-hong ŭi taejung yŏnyesa 1'
+- Pak nohong ŭi taejung yŏnyesa 1
+?     ^
++ Pak No-hong ŭi taejung yŏnyesa 1
+?     ^ +
+ : S2R transliteration error for korean_nonames!
+Original: 박 노홍 의 대중 연예사 1
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Sarang ŭi hakkyo (ma kwangsu sosŏlchip)' != 'Sarang ŭi hakkyo (Ma Kwang-su sosŏlchip)'
+- Sarang ŭi hakkyo (ma kwangsu sosŏlchip)
+?                   ^  ^
++ Sarang ŭi hakkyo (Ma Kwang-su sosŏlchip)
+?                   ^  ^    +
+ : S2R transliteration error for korean_nonames!
+Original: 사랑 의 학교 (마 광수 소설집)
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Sahoe pokchi yulli wa ch'ŏrhak (kaejŏngp'an)" != "Sahoe pokchi yulli wa ch 'ŏrhak (kaejŏngp' an)"
+- Sahoe pokchi yulli wa ch'ŏrhak (kaejŏngp'an)
++ Sahoe pokchi yulli wa ch 'ŏrhak (kaejŏngp' an)
+?                         +                 +
+ : S2R transliteration error for korean_nonames!
+Original: 사회 복지 윤리 와 철학 (개정판)
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Sebŏphak 1 (2009) kaejŏngp'an" != "Sepŏphak 1 (2009) kaejŏngp'an"
+- Sebŏphak 1 (2009) kaejŏngp'an
+?   ^
++ Sepŏphak 1 (2009) kaejŏngp'an
+?   ^
+ : S2R transliteration error for korean_nonames!
+Original: 세법학 1 (2009) 개정판
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Sebŏphak 2 (2009) kaejŏngp'an" != "Sepŏphak 2 (2009) kaejŏngp'an"
+- Sebŏphak 2 (2009) kaejŏngp'an
+?   ^
++ Sepŏphak 2 (2009) kaejŏngp'an
+?   ^
+ : S2R transliteration error for korean_nonames!
+Original: 세법학 2 (2009) 개정판
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Sop'ŭrano sin yŏngok ŭi kkum kkun hu e" != "Sop'ŭrano Sin Yŏng-ok ŭi kkum kkun hu e"
+- Sop'ŭrano sin yŏngok ŭi kkum kkun hu e
+?           ^   ^
++ Sop'ŭrano Sin Yŏng-ok ŭi kkum kkun hu e
+?           ^   ^   +
+ : S2R transliteration error for korean_nonames!
+Original: 소프라노 신 영옥 의 꿈 꾼 후 에
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Son yŏngun ŭi uri ttang kwahak tapsagi' != 'Son Yŏng-un ŭi uri ttang kwahak tapsagi'
+- Son yŏngun ŭi uri ttang kwahak tapsagi
+?     ^
++ Son Yŏng-un ŭi uri ttang kwahak tapsagi
+?     ^   +
+ : S2R transliteration error for korean_nonames!
+Original: 손 영운 의 우리 땅 과학 답사기
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Song uk ŭi sam kwa munhak' != 'Song Uk ŭi sam kwa munhak'
+- Song uk ŭi sam kwa munhak
+?      ^
++ Song Uk ŭi sam kwa munhak
+?      ^
+ : S2R transliteration error for korean_nonames!
+Original: 송 욱 의 삶 과 문학
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Sukpin ch'oessi charyojip 2" != "Sukpin Ch'oe Ssi charyojip 2"
+- Sukpin ch'oessi charyojip 2
+?        ^    ^
++ Sukpin Ch'oe Ssi charyojip 2
+?        ^    ^^
+ : S2R transliteration error for korean_nonames!
+Original: 숙빈 최씨 자료집 2
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Sunjong Hwangje wa ch'ininch'ŏk" != "Sunjong hwangje wa ch'ininch'ŏk"
+- Sunjong Hwangje wa ch'ininch'ŏk
+?         ^
++ Sunjong hwangje wa ch'ininch'ŏk
+?         ^
+ : S2R transliteration error for korean_nonames!
+Original: 순종 황제 와 친인척
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Syup'ŏ Ait'i K'oria 2020" != "Syup'ŏ Ait'i k'oria 2020"
+- Syup'ŏ Ait'i K'oria 2020
+?              ^
++ Syup'ŏ Ait'i k'oria 2020
+?              ^
+ : S2R transliteration error for korean_nonames!
+Original: 슈퍼 아이티 코리아 2020
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Singminji ihu rŭl sayuhada: t'alsingminhwa wa chaesingminhwa ŭi kyŏnggye" != "Singminji ihu rŭl sayu hada: t'alsingminhwa wa chaesingminhwa ŭi kyŏnggye"
+- Singminji ihu rŭl sayuhada: t'alsingminhwa wa chaesingminhwa ŭi kyŏnggye
++ Singminji ihu rŭl sayu hada: t'alsingminhwa wa chaesingminhwa ŭi kyŏnggye
+?                       +
+ : S2R transliteration error for korean_nonames!
+Original: 식민지 이후 를 사유하다 : 탈식민화 와 재식민화 의 경계
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Sin hyŏnsu sijip 1985-2004 chŏn 2-kwŏn' != 'Sin Hyŏn-su-sijip 1985-2004 chŏn 2-kwŏn'
+- Sin hyŏnsu sijip 1985-2004 chŏn 2-kwŏn
+?     ^     ^
++ Sin Hyŏn-su-sijip 1985-2004 chŏn 2-kwŏn
+?     ^   +  ^
+ : S2R transliteration error for korean_nonames!
+Original: 신 현수 시집 1985-2004 전 2권
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Sim yŏnsu ŭi simunhak t'amsaek" != "Sim Yŏn-su ŭi simunhak t'amsaek"
+- Sim yŏnsu ŭi simunhak t'amsaek
+?     ^
++ Sim Yŏn-su ŭi simunhak t'amsaek
+?     ^  +
+ : S2R transliteration error for korean_nonames!
+Original: 심 연수 의 시문학 탐색
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Simjang ŭl salligo sahoe rŭl sallinŭn song myŏnggŭn ŭi kŏn'gang kyogwasŏ" != "Simjang ŭl salligo sahoe rŭl sallinŭn Song Myŏng-gŭn ŭi kŏn'gang kyogwasŏ"
+- Simjang ŭl salligo sahoe rŭl sallinŭn song myŏnggŭn ŭi kŏn'gang kyogwasŏ
+?                                       ^    ^
++ Simjang ŭl salligo sahoe rŭl sallinŭn Song Myŏng-gŭn ŭi kŏn'gang kyogwasŏ
+?                                       ^    ^    +
+ : S2R transliteration error for korean_nonames!
+Original: 심장 을 살리고 사회 를 살리는 송 명근 의 건강 교과서
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Yŏmsangsŏp sosŏl tasi ilki' != 'Yŏm sangsŏp sosŏl tasi ilki'
+- Yŏmsangsŏp sosŏl tasi ilki
++ Yŏm sangsŏp sosŏl tasi ilki
+?    +
+ : S2R transliteration error for korean_nonames!
+Original: 염상섭 소설 다시 읽기
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Yŏngwŏnhi kkŏjiji annŭn ŏnyak ŭi tŭngpul 1' != 'Yŏngwŏnhi kkŏjiji annŭn ŏnyak ŭi tŭngbul 1'
+- Yŏngwŏnhi kkŏjiji annŭn ŏnyak ŭi tŭngpul 1
+?                                      ^
++ Yŏngwŏnhi kkŏjiji annŭn ŏnyak ŭi tŭngbul 1
+?                                      ^
+ : S2R transliteration error for korean_nonames!
+Original: 영원히 꺼지지 않는 언약 의 등불 1
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Obama wa kim chŏngil ŭi saengjon' != 'Obama wa Kim Chŏng-il ŭi saengjon'
+- Obama wa kim chŏngil ŭi saengjon
+?          ^   ^
++ Obama wa Kim Chŏng-il ŭi saengjon
+?          ^   ^    +
+ : S2R transliteration error for korean_nonames!
+Original: 오바마 와 김 정일 의 생존
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Wanyŏk i ok chŏnjip 03 pŏlledŭl ŭi koerophim e taehayŏ' != 'Wanyŏk Yi Ok chŏnjip 03 pŏlledŭl ŭi koerophim e taehayŏ'
+- Wanyŏk i ok chŏnjip 03 pŏlledŭl ŭi koerophim e taehayŏ
+?          ^
++ Wanyŏk Yi Ok chŏnjip 03 pŏlledŭl ŭi koerophim e taehayŏ
+?        +  ^
+ : S2R transliteration error for korean_nonames!
+Original: 완역 이 옥 전집 03 벌레들 의 괴롭힘 에 대하여
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Yu t'aeu ŭi chilbyŏng wanch'i (CD1-chang p'oham)" != "Yu T'ae-u ŭi chilbyŏng wanch'i (CD1-chang p'oham)"
+- Yu t'aeu ŭi chilbyŏng wanch'i (CD1-chang p'oham)
+?    ^
++ Yu T'ae-u ŭi chilbyŏng wanch'i (CD1-chang p'oham)
+?    ^   +
+ : S2R transliteration error for korean_nonames!
+Original: 유 태우 의 질병 완치 (CD1장 포함)
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'I kangbaek hŭigok chŏnjip 2' != 'Yi Kang-baek hŭigok chŏnjip 2'
+- I kangbaek hŭigok chŏnjip 2
+? ^^^
++ Yi Kang-baek hŭigok chŏnjip 2
+? ^^^^   +
+ : S2R transliteration error for korean_nonames!
+Original: 이 강백 희곡 전집 2
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'I tŏgil ŭi sesang ŭl pakkun yŏindŭl' != 'Yi Tŏg-il ŭi sesang ŭl pakkun yŏindŭl'
+- I tŏgil ŭi sesang ŭl pakkun yŏindŭl
+? ^^^
++ Yi Tŏg-il ŭi sesang ŭl pakkun yŏindŭl
+? ^^^^  +
+ : S2R transliteration error for korean_nonames!
+Original: 이 덕일 의 세상 을 바꾼 여인들
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'I samno ka chŏngmal pulssang hada' != 'Yi Sam-no ka chŏngmal pulssang hada'
+- I samno ka chŏngmal pulssang hada
+? ^^^
++ Yi Sam-no ka chŏngmal pulssang hada
+? ^^^^  +
+ : S2R transliteration error for korean_nonames!
+Original: 이 삼노 가 정말 불쌍 하다
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "I sang chŏnjip 2 tanp'yŏn sosŏl" != "Yi Sang chŏnjip 2 tanp'yŏn sosŏl"
+- I sang chŏnjip 2 tanp'yŏn sosŏl
+? ^^^
++ Yi Sang chŏnjip 2 tanp'yŏn sosŏl
+? ^^^^
+ : S2R transliteration error for korean_nonames!
+Original: 이 상 전집 2 단편 소설
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "I sang chŏnjip 3: changp'yŏn sosŏl" != "Yi Sang chŏnjip 3: changp'yŏn sosŏl"
+- I sang chŏnjip 3: changp'yŏn sosŏl
+? ^^^
++ Yi Sang chŏnjip 3: changp'yŏn sosŏl
+? ^^^^
+ : S2R transliteration error for korean_nonames!
+Original: 이 상 전집 3 : 장편 소설
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'I sŭngman tongmun sŏhanjip (sang)' != 'Yi Sŭng-man tongmun sŏhanjip (sang)'
+- I sŭngman tongmun sŏhanjip (sang)
+? ^^^
++ Yi Sŭng-man tongmun sŏhanjip (sang)
+? ^^^^   +
+ : S2R transliteration error for korean_nonames!
+Original: 이 승만 동문 서한집 (상)
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "I iksang tanp'yŏn sosŏl chŏnjip" != "Yi Ik-sang tanp'yŏn sosŏl chŏnjip"
+- I iksang tanp'yŏn sosŏl chŏnjip
+?  --
++ Yi Ik-sang tanp'yŏn sosŏl chŏnjip
+? +++  +
+ : S2R transliteration error for korean_nonames!
+Original: 이 익상 단편 소설 전집
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Iginŭn chŏng chuyŏng chiji annŭn i pyŏngch'ŏl" != "Iginŭn Chŏng Chu-yŏng chiji annŭn Yi Pyŏng-ch'ŏl"
+- Iginŭn chŏng chuyŏng chiji annŭn i pyŏngch'ŏl
+?        ^     ^                     ^
++ Iginŭn Chŏng Chu-yŏng chiji annŭn Yi Pyŏng-ch'ŏl
+?        ^     ^  +                 +  ^    +
+ : S2R transliteration error for korean_nonames!
+Original: 이기는 정 주영 지지 않는 이 병철
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Ijae hwang yunsŏk ŭi hangmun kwa sasang' != 'Ijae Hwang Yun-sŏk ŭi hangmun kwa sasang'
+- Ijae hwang yunsŏk ŭi hangmun kwa sasang
+?      ^     ^
++ Ijae Hwang Yun-sŏk ŭi hangmun kwa sasang
+?      ^     ^  +
+ : S2R transliteration error for korean_nonames!
+Original: 이재 황 윤석 의 학문 과 사상
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Chŏjakkwŏnbŏp ŭi chŏngsŏk che 3-p'an" != "Chŏjakkwŏnpŏp ŭi chŏngsŏk che 3-p'an"
+- Chŏjakkwŏnbŏp ŭi chŏngsŏk che 3-p'an
+?           ^
++ Chŏjakkwŏnpŏp ŭi chŏngsŏk che 3-p'an
+?           ^
+ : S2R transliteration error for korean_nonames!
+Original: 저작권법 의 정석 제 3판
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Chŏnsŏl ŭi myŏngch'ang im pangul" != "Chŏnsŏl ŭi myŏngch'ang Im Pang-ul"
+- Chŏnsŏl ŭi myŏngch'ang im pangul
+?                        ^  ^
++ Chŏnsŏl ŭi myŏngch'ang Im Pang-ul
+?                        ^  ^   +
+ : S2R transliteration error for korean_nonames!
+Original: 전설 의 명창 임 방울
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Chŏlmŭn kugŭllŏ ka sesang e tŏnjinŭn yŏljŏngnyŏk' != 'Chŏlmŭn kugŭllŏ ka sesang e tŏnjinŭn yŏlchŏngnyŏk'
+- Chŏlmŭn kugŭllŏ ka sesang e tŏnjinŭn yŏljŏngnyŏk
+?                                         ^
++ Chŏlmŭn kugŭllŏ ka sesang e tŏnjinŭn yŏlchŏngnyŏk
+?                                         ^^
+ : S2R transliteration error for korean_nonames!
+Original: 젊은 구글러 가 세상 에 던지는 열정력
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Cho kŭnho kŏmsajang ŭi wŏryo p'yŏnji" != "Cho Kŭn-ho kŏmsajang ŭi wŏryo p'yŏnji"
+- Cho kŭnho kŏmsajang ŭi wŏryo p'yŏnji
+?     ^
++ Cho Kŭn-ho kŏmsajang ŭi wŏryo p'yŏnji
+?     ^  +
+ : S2R transliteration error for korean_nonames!
+Original: 조 근호 검사장 의 월요 편지
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Cho suung ŭi iyagi munhak (kaejŏngp'an)" != "Cho Su-ung ŭi iyagi munhak (kaejŏngp'an)"
+- Cho suung ŭi iyagi munhak (kaejŏngp'an)
+?     ^
++ Cho Su-ung ŭi iyagi munhak (kaejŏngp'an)
+?     ^ +
+ : S2R transliteration error for korean_nonames!
+Original: 조 수웅 의 이야기 문학 (개정판)
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Chosebŏp (2009)' != 'Chosepŏp (2009)'
+- Chosebŏp (2009)
+?      ^
++ Chosepŏp (2009)
+?      ^
+ : S2R transliteration error for korean_nonames!
+Original: 조세법 (2009)
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Chungso kiŏp ŭi chŏllyakchŏk sŏngkwa kwalli(BSC) ironp'yŏn" != "Chungsogiŏp ŭi chŏllyakchŏk sŏngkwa kwalli (BSC) ironp'yŏn"
+- Chungso kiŏp ŭi chŏllyakchŏk sŏngkwa kwalli(BSC) ironp'yŏn
+?        ^^
++ Chungsogiŏp ŭi chŏllyakchŏk sŏngkwa kwalli (BSC) ironp'yŏn
+?        ^                                  +
+ : S2R transliteration error for korean_nonames!
+Original: 중소 기업 의 전략적 성과 관리(BSC) 이론편
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Chis[40 chars]onggong chŏngbohwa hyŏksin pangan yŏn'gu(Ⅳ) ch'onggwal pogosŏ" != "Chis[40 chars]onggong chŏngbohwa hyŏksin pangan yŏn'gu (Ⅳ) ch'onggwal pogosŏ"
+- Chisik chŏngbohwa ŭi chŏnmyŏnhwa rŭl wihan konggong chŏngbohwa hyŏksin pangan yŏn'gu(Ⅳ) ch'onggwal pogosŏ
++ Chisik chŏngbohwa ŭi chŏnmyŏnhwa rŭl wihan konggong chŏngbohwa hyŏksin pangan yŏn'gu (Ⅳ) ch'onggwal pogosŏ
+?                                                                                     +
+ : S2R transliteration error for korean_nonames!
+Original: 지식 정보화 의 전면화 를 위한 공공 정보화 혁신 방안 연구(Ⅳ) 총괄 보고서
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Chilbyŏng e ttarŭn yang, hanbang siksa yobŏp' != 'Chilbyŏng e ttarŭn yang,-hanbang siksa yobŏp'
+- Chilbyŏng e ttarŭn yang, hanbang siksa yobŏp
+?                         ^
++ Chilbyŏng e ttarŭn yang,-hanbang siksa yobŏp
+?                         ^
+ : S2R transliteration error for korean_nonames!
+Original: 질병 에 따른 양·한방 식사 요법
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Ch'ŏnha cheil chamnom cho yŏngnam ŭi suda" != "Ch'ŏnha cheil chamnom Cho Yŏng-nam Ŭi suda"
+- Ch'ŏnha cheil chamnom cho yŏngnam ŭi suda
+?                       ^   ^       ^
++ Ch'ŏnha cheil chamnom Cho Yŏng-nam Ŭi suda
+?                       ^   ^   +    ^
+ : S2R transliteration error for korean_nonames!
+Original: 천하 제일 잡놈 조 영남 의 수다
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Ch'oe namsŏn ŭi ek'ŭrit'wirŭ wa kŭndae ŏnŏ minjok" != "Ch 'oe Nam-sŏn ŭi ek'ŭrit'wirŭ wa kŭndae ŏnŏ minjok"
+- Ch'oe namsŏn ŭi ek'ŭrit'wirŭ wa kŭndae ŏnŏ minjok
+?       ^
++ Ch 'oe Nam-sŏn ŭi ek'ŭrit'wirŭ wa kŭndae ŏnŏ minjok
+?   +    ^  +
+ : S2R transliteration error for korean_nonames!
+Original: 최 남선 의 에크리튀르 와 근대 언어 민족
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Ch'oe sŭngch'ŏl paksa ka mal hanŭn sŏnginpyŏng ttaeryŏ chapki" != "Ch'oe Sŭng-ch'ŏl paksa ka mal hanŭn sŏnginpyŏng ttaeryŏ chapki"
+- Ch'oe sŭngch'ŏl paksa ka mal hanŭn sŏnginpyŏng ttaeryŏ chapki
+?       ^
++ Ch'oe Sŭng-ch'ŏl paksa ka mal hanŭn sŏnginpyŏng ttaeryŏ chapki
+?       ^   +
+ : S2R transliteration error for korean_nonames!
+Original: 최 승철 박사 가 말 하는 성인병 때려 잡기
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Ch'oe chonghyŏn kŭ ka kkumkkun iltŭng kukka ro kanŭn kil" != "Ch'oe Chong-hyŏn Kŭ ka kkumkkun iltŭng kukka ro kanŭn kil"
+- Ch'oe chonghyŏn kŭ ka kkumkkun iltŭng kukka ro kanŭn kil
+?       ^         ^
++ Ch'oe Chong-hyŏn Kŭ ka kkumkkun iltŭng kukka ro kanŭn kil
+?       ^    +     ^
+ : S2R transliteration error for korean_nonames!
+Original: 최 종현 그 가 꿈꾼 일등 국가 로 가는 길
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "P'aldangho sujil sago yegyŏngbo sisŭt'em kaebal e kwanhan kich'o yŏn'gu" != "P'altangho sujil sago yegyŏngbo sisŭt'em kaebal e kwanhan kich'o yŏn'gu"
+- P'aldangho sujil sago yegyŏngbo sisŭt'em kaebal e kwanhan kich'o yŏn'gu
+?     ^
++ P'altangho sujil sago yegyŏngbo sisŭt'em kaebal e kwanhan kich'o yŏn'gu
+?     ^
+ : S2R transliteration error for korean_nonames!
+Original: 팔당호 수질 사고 예경보 시스템 개발 에 관한 기초 연구
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Hananim kat'i kapsida" != "Hananim kach'i kapsida"
+- Hananim kat'i kapsida
+?           ^
++ Hananim kach'i kapsida
+?           ^^
+ : S2R transliteration error for korean_nonames!
+Original: 하나님 같이 갑시다
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Han'guk ŭi kyoyŏk kujo wa Kyŏngsang suji pyŏndong yoin punsŏk" != "Han'guk ŭi kyoyŏk kujo wa kyŏngsang suji pyŏndong yoin punsŏk"
+- Han'guk ŭi kyoyŏk kujo wa Kyŏngsang suji pyŏndong yoin punsŏk
+?                           ^
++ Han'guk ŭi kyoyŏk kujo wa kyŏngsang suji pyŏndong yoin punsŏk
+?                           ^
+ : S2R transliteration error for korean_nonames!
+Original: 한국 의 교역 구조 와 경상 수지 변동 요인 분석
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Han'guk hŏnbŏmnon [5 p'an]" != "Han'guk hŏnpŏmnon [5 p'an]"
+- Han'guk hŏnbŏmnon [5 p'an]
+?            ^
++ Han'guk hŏnpŏmnon [5 p'an]
+?            ^
+ : S2R transliteration error for korean_nonames!
+Original: 한국 헌법론 [5 판]
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Han'guk hŏnbŏmnon [chŏnjŏng 5-p'an]" != "Han'guk hŏnpŏmnon [chŏnjŏng 5-p'an]"
+- Han'guk hŏnbŏmnon [chŏnjŏng 5-p'an]
+?            ^
++ Han'guk hŏnpŏmnon [chŏnjŏng 5-p'an]
+?            ^
+ : S2R transliteration error for korean_nonames!
+Original: 한국 헌법론 [전정 5판]
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Han'guksa ŭi ihae yochŏm" != "Han'guksa ŭi ihae yojŏm"
+- Han'guksa ŭi ihae yochŏm
+?                     ^^
++ Han'guksa ŭi ihae yojŏm
+?                     ^
+ : S2R transliteration error for korean_nonames!
+Original: 한국사 의 이해 요점
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Han'gugŏ paldalsa chŭngbo" != "Han'gugŏ paltalsa chŭngbo"
+- Han'gugŏ paldalsa chŭngbo
+?             ^
++ Han'gugŏ paltalsa chŭngbo
+?             ^
+ : S2R transliteration error for korean_nonames!
+Original: 한국어 발달사 증보
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Han'gugŏ wa Oegugŏ taejo punsŏngnon" != "Han'gugŏ wa oegugŏ taejo punsŏngnon"
+- Han'gugŏ wa Oegugŏ taejo punsŏngnon
+?             ^
++ Han'gugŏ wa oegugŏ taejo punsŏngnon
+?             ^
+ : S2R transliteration error for korean_nonames!
+Original: 한국어 와 외국어 대조 분석론
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: 'Haengjŏng chŏngbohwa(G4C) sŏngkwa punsŏk' != 'Haengjŏng chŏngbohwa (G4C) sŏngkwa punsŏk'
+- Haengjŏng chŏngbohwa(G4C) sŏngkwa punsŏk
++ Haengjŏng chŏngbohwa (G4C) sŏngkwa punsŏk
+?                     +
+ : S2R transliteration error for korean_nonames!
+Original: 행정 정보화(G4C) 성과 분석
+
+======================================================================
+FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
+Test S2R transliteration for one CSV sample.
+----------------------------------------------------------------------
+Traceback (most recent call last):
+  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
+    self.assertEqual(
+AssertionError: "Hyŏndaesahoe wa seksyuŏllit'i" != "Hyŏndae sahoe wa seksyuŏllit'i"
+- Hyŏndaesahoe wa seksyuŏllit'i
++ Hyŏndae sahoe wa seksyuŏllit'i
+?        +
+ : S2R transliteration error for korean_nonames!
+Original: 현대사회 와 섹슈얼리티

+ 96 - 0
tests/test03_rest_api.py

@@ -0,0 +1,96 @@
+import json
+
+from os import environ
+from unittest import TestCase
+
+from scriptshifter.rest_api import app
+from tests import TEST_DATA_DIR, reload_tables
+
+
+EP = "http://localhost:8000"
+
+
+class TestRestAPI(TestCase):
+    """ Test REST API interaction. """
+    def setUp(self):
+        environ["TXL_CONFIG_TABLE_DIR"] = TEST_DATA_DIR
+        # if "TXL_CONFIG_TABLE_DIR" in environ:
+        #     del environ["TXL_CONFIG_TABLE_DIR"]
+        reload_tables()
+
+        # Start webapp.
+        app.testing = True
+
+    def test_health(self):
+        with app.test_client() as c:
+            rsp = c.get("/health")
+
+        self.assertEqual(rsp.status_code, 200)
+
+    def test_language_list(self):
+        with app.test_client() as c:
+            rsp = c.get("/languages")
+
+        self.assertEqual(rsp.status_code, 200)
+
+        data = json.loads(rsp.get_data(as_text=True))
+        self.assertIn("inherited", data)
+        self.assertIn("name", data["inherited"])
+        self.assertNotIn("_base1", data)
+        self.assertNotIn("_base2", data)
+        self.assertNotIn("_base3", data)
+
+    def test_lang_table(self):
+        with app.test_client() as c:
+            rsp = c.get("/table/ordering")
+
+        self.assertEqual(rsp.status_code, 200)
+        data = json.loads(rsp.get_data(as_text=True))
+
+        self.assertIn("general", data)
+        self.assertIn("roman_to_script", data)
+        self.assertIn("map", data["roman_to_script"])
+        self.assertEqual(data["roman_to_script"]["map"][0], ["ABCD", ""])
+
+    def test_trans_api_s2r(self):
+        with app.test_client() as c:
+            rsp = c.post("/trans/rot3", data={"text": "defg"})
+
+        self.assertEqual(rsp.status_code, 200)
+        data = json.loads(rsp.get_data(as_text=True))
+
+        self.assertEqual(data["output"], "abcd")
+
+    def test_trans_api_r2s(self):
+        with app.test_client() as c:
+            rsp = c.post("/trans/rot3/r2s", data={"text": "abcd"})
+
+        self.assertEqual(rsp.status_code, 200)
+        data = json.loads(rsp.get_data(as_text=True))
+
+        self.assertEqual(data["output"], "defg")
+
+    def test_trans_api_capitalize(self):
+        with app.test_client() as c:
+            rsp = c.post(
+                    "/trans/rot3/r2s",
+                    data={"capitalize": "first", "text": "bcde"})
+
+        self.assertEqual(rsp.status_code, 200)
+        data = json.loads(rsp.get_data(as_text=True))
+
+        self.assertEqual(data["output"], "Efgh")
+
+    def test_trans_form(self):
+        with app.test_client() as c:
+            rsp = c.post(
+                    "/transliterate", data={
+                        "text": "abcd",
+                        "r2s": "true",
+                        "lang": "rot3",
+                    })
+
+        self.assertEqual(rsp.status_code, 200)
+        data = json.loads(rsp.get_data(as_text=True))
+
+        self.assertEqual(data["output"], "defg")

+ 3 - 18
tests/unittest.log

@@ -1171,7 +1171,7 @@ INFO:scriptshifter.trans:Loaded table for korean_nonames.
 INFO:scriptshifter.trans:Loaded table for korean_nonames.
 ..INFO:scriptshifter.trans:Transliteration is from korean_nonames to Latin.
 INFO:scriptshifter.trans:Loaded table for korean_nonames.
-F.INFO:scriptshifter.trans:Transliteration is from korean_nonames to Latin.
+..INFO:scriptshifter.trans:Transliteration is from korean_nonames to Latin.
 INFO:scriptshifter.trans:Loaded table for korean_nonames.
 ..INFO:scriptshifter.trans:Transliteration is from korean_nonames to Latin.
 INFO:scriptshifter.trans:Loaded table for korean_nonames.
@@ -4590,21 +4590,6 @@ AssertionError: "Kim ch'angmo ŭi Taehan Min'guk sŏnmul opsyŏn kyogwasŏ" != "
  : S2R transliteration error for korean_nonames!
 Original: 김 창모 의 대한 민국 선물 옵션 교과서
 
-======================================================================
-FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
-Test S2R transliteration for one CSV sample.
-----------------------------------------------------------------------
-Traceback (most recent call last):
-  File "/home/stefano/code/scriptshifter/src/tests/test02_transliteration.py", line 38, in sample_s2r
-    self.assertEqual(
-AssertionError: 'Nae an ŭi lidŏsip' != 'Nae an ŭi ridŏsip'
-- Nae an ŭi lidŏsip
-?           ^
-+ Nae an ŭi ridŏsip
-?           ^
- : S2R transliteration error for korean_nonames!
-Original: 내 안 의 리더십
-
 ======================================================================
 FAIL: sample_s2r (tests.test02_transliteration.TestTrans.sample_s2r)
 Test S2R transliteration for one CSV sample.
@@ -5822,9 +5807,9 @@ AssertionError: 'Тему[14 chars] даврi тарiхi / [бош муҳаррi
 Original: Temur va Ulughbek : davri tarikhi / [bosh muḣarrir Aḣmadali Asqarov ; masʺul muḣarrir Oqilkhon Odilkhon]. Toshkent : Qomuslar bosh taḣririi︠a︡ti, [1996].
 
 ----------------------------------------------------------------------
-Ran 1608 tests in 2.669s
+Ran 1608 tests in 2.666s
 
-FAILED (failures=99, errors=5)
+FAILED (failures=98, errors=5)
 ......INFO:scriptshifter.trans:Transliteration is from cap_inherited to Latin.
 INFO:scriptshifter.trans:Loaded table for cap_inherited.
 INFO:scriptshifter.trans:Token   (\u20) at position 2 is not mapped.