summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2024-01-31 08:28:05 -0500
committerGitHub <noreply@github.com>2024-01-31 13:28:05 +0000
commit3e419aa562aab03ca20421aaf7e4d1a39194a5b4 (patch)
tree15e8bfe81fa5e3fae55e54802f14d94a7502a469
parent6807b05e9bd41f013364fae0cbcce83cf1ed37b6 (diff)
Language transformer (#582)
* Set up new deinflection data file * Define types * Test * Add internal types * Set up loading for transforms * Add getPartOfSpeechFlags * Convert static methods * Add note * Add transform function * Update trace structure * Add a language tag to the language transform descriptor * Add clear function * Add function for multiple parts of speech * Clarify naming * Add getConditionFlagsFromConditionType * Add plural function * Replace usages of Deinflector * Update tests * Update config * Remove old * Rename * Rename files
-rw-r--r--.eslintrc.json2
-rw-r--r--dev/jsconfig.json5
-rw-r--r--ext/data/deinflect.json645
-rw-r--r--ext/data/language/japanese-transforms.json851
-rw-r--r--ext/js/background/backend.js6
-rw-r--r--ext/js/background/offscreen-proxy.js6
-rw-r--r--ext/js/background/offscreen.js4
-rw-r--r--ext/js/language/deinflector.js140
-rw-r--r--ext/js/language/language-transformer.js245
-rw-r--r--ext/js/language/translator.js32
-rw-r--r--test/data/json.json10
-rw-r--r--test/fixtures/translator-test.js6
-rw-r--r--test/language-transformer-cycles.test.js (renamed from test/deinflection-cycles.test.js)39
-rw-r--r--test/language-transformer.test.js (renamed from test/deinflector.test.js)37
-rw-r--r--types/ext/language-transformer-internal.d.ts (renamed from types/ext/deinflector.d.ts)40
-rw-r--r--types/ext/language-transformer.d.ts62
-rw-r--r--types/ext/offscreen.d.ts4
-rw-r--r--types/ext/translation-internal.d.ts19
18 files changed, 1258 insertions, 895 deletions
diff --git a/.eslintrc.json b/.eslintrc.json
index eec25b5c..aea94cde 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -684,7 +684,7 @@
"ext/js/general/object-property-accessor.js",
"ext/js/general/regex-util.js",
"ext/js/general/text-source-map.js",
- "ext/js/language/deinflector.js",
+ "ext/js/language/language-transformer.js",
"ext/js/dictionary/dictionary-database.js",
"ext/js/dictionary/dictionary-data-util.js",
"ext/js/language/sandbox/japanese-util.js",
diff --git a/dev/jsconfig.json b/dev/jsconfig.json
index c0ff07d0..db38b6df 100644
--- a/dev/jsconfig.json
+++ b/dev/jsconfig.json
@@ -18,7 +18,6 @@
"core": ["../types/ext/core"],
"css-style-applier": ["../types/ext/css-style-applier"],
"database": ["../types/ext/database"],
- "deinflector": ["../types/ext/deinflector"],
"dictionary": ["../types/ext/dictionary"],
"dictionary-data": ["../types/ext/dictionary-data"],
"dictionary-data-util": ["../types/ext/dictionary-data-util"],
@@ -30,6 +29,8 @@
"event-listener-collection": ["../types/ext/event-listener-collection"],
"japanese-util": ["../types/ext/japanese-util"],
"ext/json-schema": ["../types/ext/json-schema"],
+ "language-transformer": ["../types/ext/language-transformer"],
+ "language-transformer-internal": ["../types/ext/language-transformer-internal"],
"log": ["../types/ext/log"],
"settings": ["../types/ext/settings"],
"structured-content": ["../types/ext/structured-content"],
@@ -64,7 +65,7 @@
"../ext/js/general/cache-map.js",
"../ext/js/general/regex-util.js",
"../ext/js/general/text-source-map.js",
- "../ext/js/language/deinflector.js",
+ "../ext/js/language/language-transformer.js",
"../ext/js/dictionary/dictionary-importer.js",
"../ext/js/dictionary/dictionary-database.js",
"../ext/js/dictionary/dictionary-data-util.js",
diff --git a/ext/data/deinflect.json b/ext/data/deinflect.json
deleted file mode 100644
index 884dbcc1..00000000
--- a/ext/data/deinflect.json
+++ /dev/null
@@ -1,645 +0,0 @@
-{
- "-ba": [
- {"kanaIn": "ければ", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "えば", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "けば", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "げば", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "せば", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "てば", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ねば", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "べば", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "めば", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "れば", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1", "v5", "vk", "vs", "vz"]}
- ],
- "-chau": [
- {"kanaIn": "ちゃう", "kanaOut": "る", "rulesIn": ["v5"], "rulesOut": ["v1"]},
- {"kanaIn": "いじゃう", "kanaOut": "ぐ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "いちゃう", "kanaOut": "く", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "しちゃう", "kanaOut": "す", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちゃう", "kanaOut": "う", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちゃう", "kanaOut": "く", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちゃう", "kanaOut": "つ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちゃう", "kanaOut": "る", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んじゃう", "kanaOut": "ぬ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んじゃう", "kanaOut": "ぶ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んじゃう", "kanaOut": "む", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "じちゃう", "kanaOut": "ずる", "rulesIn": ["v5"], "rulesOut": ["vz"]},
- {"kanaIn": "しちゃう", "kanaOut": "する", "rulesIn": ["v5"], "rulesOut": ["vs"]},
- {"kanaIn": "為ちゃう", "kanaOut": "為る", "rulesIn": ["v5"], "rulesOut": ["vs"]},
- {"kanaIn": "きちゃう", "kanaOut": "くる", "rulesIn": ["v5"], "rulesOut": ["vk"]},
- {"kanaIn": "来ちゃう", "kanaOut": "来る", "rulesIn": ["v5"], "rulesOut": ["vk"]},
- {"kanaIn": "來ちゃう", "kanaOut": "來る", "rulesIn": ["v5"], "rulesOut": ["vk"]}
- ],
- "-chimau": [
- {"kanaIn": "ちまう", "kanaOut": "る", "rulesIn": ["v5"], "rulesOut": ["v1"]},
- {"kanaIn": "いじまう", "kanaOut": "ぐ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "いちまう", "kanaOut": "く", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "しちまう", "kanaOut": "す", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちまう", "kanaOut": "う", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちまう", "kanaOut": "く", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちまう", "kanaOut": "つ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っちまう", "kanaOut": "る", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んじまう", "kanaOut": "ぬ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んじまう", "kanaOut": "ぶ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んじまう", "kanaOut": "む", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "じちまう", "kanaOut": "ずる", "rulesIn": ["v5"], "rulesOut": ["vz"]},
- {"kanaIn": "しちまう", "kanaOut": "する", "rulesIn": ["v5"], "rulesOut": ["vs"]},
- {"kanaIn": "為ちまう", "kanaOut": "為る", "rulesIn": ["v5"], "rulesOut": ["vs"]},
- {"kanaIn": "きちまう", "kanaOut": "くる", "rulesIn": ["v5"], "rulesOut": ["vk"]},
- {"kanaIn": "来ちまう", "kanaOut": "来る", "rulesIn": ["v5"], "rulesOut": ["vk"]},
- {"kanaIn": "來ちまう", "kanaOut": "來る", "rulesIn": ["v5"], "rulesOut": ["vk"]}
- ],
- "-shimau": [
- {"kanaIn": "てしまう", "kanaOut": "て", "rulesIn": ["v5"], "rulesOut": ["iru"]},
- {"kanaIn": "でしまう", "kanaOut": "で", "rulesIn": ["v5"], "rulesOut": ["iru"]}
- ],
- "-nasai": [
- {"kanaIn": "なさい", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いなさい", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "きなさい", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎなさい", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "しなさい", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ちなさい", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "になさい", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "びなさい", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "みなさい", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "りなさい", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じなさい", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しなさい", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為なさい", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きなさい", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来なさい", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來なさい", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "-sou": [
- {"kanaIn": "そう", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "そう", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いそう", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "きそう", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎそう", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "しそう", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ちそう", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "にそう", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "びそう", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "みそう", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "りそう", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じそう", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しそう", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為そう", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きそう", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来そう", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來そう", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "-sugiru": [
- {"kanaIn": "すぎる", "kanaOut": "い", "rulesIn": ["v1"], "rulesOut": ["adj-i"]},
- {"kanaIn": "すぎる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v1"]},
- {"kanaIn": "いすぎる", "kanaOut": "う", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "きすぎる", "kanaOut": "く", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ぎすぎる", "kanaOut": "ぐ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "しすぎる", "kanaOut": "す", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ちすぎる", "kanaOut": "つ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "にすぎる", "kanaOut": "ぬ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "びすぎる", "kanaOut": "ぶ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "みすぎる", "kanaOut": "む", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "りすぎる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "じすぎる", "kanaOut": "ずる", "rulesIn": ["v1"], "rulesOut": ["vz"]},
- {"kanaIn": "しすぎる", "kanaOut": "する", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "為すぎる", "kanaOut": "為る", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "きすぎる", "kanaOut": "くる", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "来すぎる", "kanaOut": "来る", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "來すぎる", "kanaOut": "來る", "rulesIn": ["v1"], "rulesOut": ["vk"]}
- ],
- "-tai": [
- {"kanaIn": "たい", "kanaOut": "る", "rulesIn": ["adj-i"], "rulesOut": ["v1"]},
- {"kanaIn": "いたい", "kanaOut": "う", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "きたい", "kanaOut": "く", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "ぎたい", "kanaOut": "ぐ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "したい", "kanaOut": "す", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "ちたい", "kanaOut": "つ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "にたい", "kanaOut": "ぬ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "びたい", "kanaOut": "ぶ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "みたい", "kanaOut": "む", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "りたい", "kanaOut": "る", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "じたい", "kanaOut": "ずる", "rulesIn": ["adj-i"], "rulesOut": ["vz"]},
- {"kanaIn": "したい", "kanaOut": "する", "rulesIn": ["adj-i"], "rulesOut": ["vs"]},
- {"kanaIn": "為たい", "kanaOut": "為る", "rulesIn": ["adj-i"], "rulesOut": ["vs"]},
- {"kanaIn": "きたい", "kanaOut": "くる", "rulesIn": ["adj-i"], "rulesOut": ["vk"]},
- {"kanaIn": "来たい", "kanaOut": "来る", "rulesIn": ["adj-i"], "rulesOut": ["vk"]},
- {"kanaIn": "來たい", "kanaOut": "來る", "rulesIn": ["adj-i"], "rulesOut": ["vk"]}
- ],
- "-tara": [
- {"kanaIn": "かったら", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "たら", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いたら", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "いだら", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "したら", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ったら", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ったら", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ったら", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだら", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだら", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだら", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じたら", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "したら", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為たら", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きたら", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来たら", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來たら", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "いったら", "kanaOut": "いく", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "おうたら", "kanaOut": "おう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "こうたら", "kanaOut": "こう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "そうたら", "kanaOut": "そう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "とうたら", "kanaOut": "とう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "行ったら", "kanaOut": "行く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "逝ったら", "kanaOut": "逝く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "往ったら", "kanaOut": "往く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "請うたら", "kanaOut": "請う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "乞うたら", "kanaOut": "乞う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "恋うたら", "kanaOut": "恋う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "問うたら", "kanaOut": "問う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "負うたら", "kanaOut": "負う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "沿うたら", "kanaOut": "沿う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "添うたら", "kanaOut": "添う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "副うたら", "kanaOut": "副う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "厭うたら", "kanaOut": "厭う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "のたもうたら", "kanaOut": "のたまう", "rulesIn": [], "rulesOut": ["v5"]}
- ],
- "-tari": [
- {"kanaIn": "かったり", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "たり", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いたり", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "いだり", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "したり", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ったり", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ったり", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ったり", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだり", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだり", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだり", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じたり", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "したり", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為たり", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きたり", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来たり", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來たり", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "いったり", "kanaOut": "いく", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "おうたり", "kanaOut": "おう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "こうたり", "kanaOut": "こう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "そうたり", "kanaOut": "そう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "とうたり", "kanaOut": "とう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "行ったり", "kanaOut": "行く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "逝ったり", "kanaOut": "逝く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "往ったり", "kanaOut": "往く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "請うたり", "kanaOut": "請う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "乞うたり", "kanaOut": "乞う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "恋うたり", "kanaOut": "恋う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "問うたり", "kanaOut": "問う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "負うたり", "kanaOut": "負う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "沿うたり", "kanaOut": "沿う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "添うたり", "kanaOut": "添う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "副うたり", "kanaOut": "副う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "厭うたり", "kanaOut": "厭う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "のたもうたり", "kanaOut": "のたまう", "rulesIn": [], "rulesOut": ["v5"]}
- ],
- "-te": [
- {"kanaIn": "くて", "kanaOut": "い", "rulesIn": ["iru"], "rulesOut": ["adj-i"]},
- {"kanaIn": "て", "kanaOut": "る", "rulesIn": ["iru"], "rulesOut": ["v1"]},
- {"kanaIn": "いて", "kanaOut": "く", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "いで", "kanaOut": "ぐ", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "して", "kanaOut": "す", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "って", "kanaOut": "う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "って", "kanaOut": "つ", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "って", "kanaOut": "る", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "んで", "kanaOut": "ぬ", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "んで", "kanaOut": "ぶ", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "んで", "kanaOut": "む", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "じて", "kanaOut": "ずる", "rulesIn": ["iru"], "rulesOut": ["vz"]},
- {"kanaIn": "して", "kanaOut": "する", "rulesIn": ["iru"], "rulesOut": ["vs"]},
- {"kanaIn": "為て", "kanaOut": "為る", "rulesIn": ["iru"], "rulesOut": ["vs"]},
- {"kanaIn": "きて", "kanaOut": "くる", "rulesIn": ["iru"], "rulesOut": ["vk"]},
- {"kanaIn": "来て", "kanaOut": "来る", "rulesIn": ["iru"], "rulesOut": ["vk"]},
- {"kanaIn": "來て", "kanaOut": "來る", "rulesIn": ["iru"], "rulesOut": ["vk"]},
- {"kanaIn": "いって", "kanaOut": "いく", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "おうて", "kanaOut": "おう", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "こうて", "kanaOut": "こう", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "そうて", "kanaOut": "そう", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "とうて", "kanaOut": "とう", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "行って", "kanaOut": "行く", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "逝って", "kanaOut": "逝く", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "往って", "kanaOut": "往く", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "請うて", "kanaOut": "請う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "乞うて", "kanaOut": "乞う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "恋うて", "kanaOut": "恋う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "問うて", "kanaOut": "問う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "負うて", "kanaOut": "負う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "沿うて", "kanaOut": "沿う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "添うて", "kanaOut": "添う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "副うて", "kanaOut": "副う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "厭うて", "kanaOut": "厭う", "rulesIn": ["iru"], "rulesOut": ["v5"]},
- {"kanaIn": "のたもうて", "kanaOut": "のたまう", "rulesIn": ["iru"], "rulesOut": ["v5"]}
- ],
- "-zu": [
- {"kanaIn": "ず", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "かず", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "がず", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "さず", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "たず", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "なず", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ばず", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "まず", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "らず", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "わず", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぜず", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "せず", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ず", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "こず", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来ず", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來ず", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "-nu": [
- {"kanaIn": "ぬ", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "かぬ", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "がぬ", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "さぬ", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "たぬ", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "なぬ", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ばぬ", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "まぬ", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "らぬ", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "わぬ", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぜぬ", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "せぬ", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ぬ", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "こぬ", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来ぬ", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來ぬ", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "adv": [
- {"kanaIn": "く", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]}
- ],
- "causative": [
- {"kanaIn": "させる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v1"]},
- {"kanaIn": "かせる", "kanaOut": "く", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "がせる", "kanaOut": "ぐ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "させる", "kanaOut": "す", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "たせる", "kanaOut": "つ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "なせる", "kanaOut": "ぬ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ばせる", "kanaOut": "ぶ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ませる", "kanaOut": "む", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "らせる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "わせる", "kanaOut": "う", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "じさせる", "kanaOut": "ずる", "rulesIn": ["v1"], "rulesOut": ["vz"]},
- {"kanaIn": "ぜさせる", "kanaOut": "ずる", "rulesIn": ["v1"], "rulesOut": ["vz"]},
- {"kanaIn": "させる", "kanaOut": "する", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "為せる", "kanaOut": "為る", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "せさせる", "kanaOut": "する", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "為させる", "kanaOut": "為る", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "こさせる", "kanaOut": "くる", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "来させる", "kanaOut": "来る", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "來させる", "kanaOut": "來る", "rulesIn": ["v1"], "rulesOut": ["vk"]}
- ],
- "imperative": [
- {"kanaIn": "ろ", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "よ", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "え", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "け", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "げ", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "せ", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "て", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ね", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "べ", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "め", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "れ", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じろ", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "ぜよ", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しろ", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "せよ", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ろ", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為よ", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "こい", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来い", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來い", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "imperative negative": [
- {"kanaIn": "な", "kanaOut": "", "rulesIn": [], "rulesOut": ["v1", "v5", "vk", "vs", "vz"]}
- ],
- "masu stem": [
- {"kanaIn": "い", "kanaOut": "いる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "え", "kanaOut": "える", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "き", "kanaOut": "きる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "ぎ", "kanaOut": "ぎる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "け", "kanaOut": "ける", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "げ", "kanaOut": "げる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "じ", "kanaOut": "じる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "せ", "kanaOut": "せる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "ぜ", "kanaOut": "ぜる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "ち", "kanaOut": "ちる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "て", "kanaOut": "てる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "で", "kanaOut": "でる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "に", "kanaOut": "にる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "ね", "kanaOut": "ねる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "ひ", "kanaOut": "ひる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "び", "kanaOut": "びる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "へ", "kanaOut": "へる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "べ", "kanaOut": "べる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "み", "kanaOut": "みる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "め", "kanaOut": "める", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "り", "kanaOut": "りる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "れ", "kanaOut": "れる", "rulesIn": [], "rulesOut": ["v1d"]},
- {"kanaIn": "い", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "き", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎ", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "し", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ち", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "に", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "び", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "み", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "り", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "き", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "negative": [
- {"kanaIn": "くない", "kanaOut": "い", "rulesIn": ["adj-i"], "rulesOut": ["adj-i"]},
- {"kanaIn": "ない", "kanaOut": "る", "rulesIn": ["adj-i"], "rulesOut": ["v1"]},
- {"kanaIn": "かない", "kanaOut": "く", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "がない", "kanaOut": "ぐ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "さない", "kanaOut": "す", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "たない", "kanaOut": "つ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "なない", "kanaOut": "ぬ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "ばない", "kanaOut": "ぶ", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "まない", "kanaOut": "む", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "らない", "kanaOut": "る", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "わない", "kanaOut": "う", "rulesIn": ["adj-i"], "rulesOut": ["v5"]},
- {"kanaIn": "じない", "kanaOut": "ずる", "rulesIn": ["adj-i"], "rulesOut": ["vz"]},
- {"kanaIn": "しない", "kanaOut": "する", "rulesIn": ["adj-i"], "rulesOut": ["vs"]},
- {"kanaIn": "為ない", "kanaOut": "為る", "rulesIn": ["adj-i"], "rulesOut": ["vs"]},
- {"kanaIn": "こない", "kanaOut": "くる", "rulesIn": ["adj-i"], "rulesOut": ["vk"]},
- {"kanaIn": "来ない", "kanaOut": "来る", "rulesIn": ["adj-i"], "rulesOut": ["vk"]},
- {"kanaIn": "來ない", "kanaOut": "來る", "rulesIn": ["adj-i"], "rulesOut": ["vk"]}
- ],
- "noun": [
- {"kanaIn": "さ", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]}
- ],
- "passive": [
- {"kanaIn": "かれる", "kanaOut": "く", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "がれる", "kanaOut": "ぐ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "される", "kanaOut": "す", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "たれる", "kanaOut": "つ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "なれる", "kanaOut": "ぬ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ばれる", "kanaOut": "ぶ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "まれる", "kanaOut": "む", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "われる", "kanaOut": "う", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "られる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "じされる", "kanaOut": "ずる", "rulesIn": ["v1"], "rulesOut": ["vz"]},
- {"kanaIn": "ぜされる", "kanaOut": "ずる", "rulesIn": ["v1"], "rulesOut": ["vz"]},
- {"kanaIn": "される", "kanaOut": "する", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "為れる", "kanaOut": "為る", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "こられる", "kanaOut": "くる", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "来られる", "kanaOut": "来る", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "來られる", "kanaOut": "來る", "rulesIn": ["v1"], "rulesOut": ["vk"]}
- ],
- "past": [
- {"kanaIn": "かった", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "た", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いた", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "いだ", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "した", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "った", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "った", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "った", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだ", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだ", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "んだ", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じた", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "した", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為た", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きた", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来た", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來た", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "いった", "kanaOut": "いく", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "おうた", "kanaOut": "おう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "こうた", "kanaOut": "こう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "そうた", "kanaOut": "そう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "とうた", "kanaOut": "とう", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "行った", "kanaOut": "行く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "逝った", "kanaOut": "逝く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "往った", "kanaOut": "往く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "請うた", "kanaOut": "請う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "乞うた", "kanaOut": "乞う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "恋うた", "kanaOut": "恋う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "問うた", "kanaOut": "問う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "負うた", "kanaOut": "負う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "沿うた", "kanaOut": "沿う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "添うた", "kanaOut": "添う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "副うた", "kanaOut": "副う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "厭うた", "kanaOut": "厭う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "のたもうた", "kanaOut": "のたまう", "rulesIn": [], "rulesOut": ["v5"]}
- ],
- "polite": [
- {"kanaIn": "ます", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "います", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "きます", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎます", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "します", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ちます", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "にます", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "びます", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "みます", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ります", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じます", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "します", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ます", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きます", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来ます", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來ます", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "polite negative": [
- {"kanaIn": "くありません", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ません", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いません", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "きません", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎません", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "しません", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ちません", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "にません", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "びません", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "みません", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "りません", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じません", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しません", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ません", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きません", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来ません", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來ません", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "polite past": [
- {"kanaIn": "ました", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いました", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "きました", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎました", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "しました", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ちました", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "にました", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "びました", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "みました", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "りました", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じました", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しました", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ました", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きました", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来ました", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來ました", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "polite past negative": [
- {"kanaIn": "くありませんでした", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ませんでした", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いませんでした", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "きませんでした", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎませんでした", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "しませんでした", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ちませんでした", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "にませんでした", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "びませんでした", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "みませんでした", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "りませんでした", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じませんでした", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しませんでした", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ませんでした", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きませんでした", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来ませんでした", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來ませんでした", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "polite volitional": [
- {"kanaIn": "ましょう", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "いましょう", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "きましょう", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぎましょう", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "しましょう", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ちましょう", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "にましょう", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "びましょう", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "みましょう", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "りましょう", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じましょう", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しましょう", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為ましょう", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "きましょう", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来ましょう", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來ましょう", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "potential": [
- {"kanaIn": "れる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v1", "v5"]},
- {"kanaIn": "える", "kanaOut": "う", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ける", "kanaOut": "く", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "げる", "kanaOut": "ぐ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "せる", "kanaOut": "す", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "てる", "kanaOut": "つ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ねる", "kanaOut": "ぬ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "べる", "kanaOut": "ぶ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "める", "kanaOut": "む", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "できる", "kanaOut": "する", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "出来る", "kanaOut": "する", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "これる", "kanaOut": "くる", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "来れる", "kanaOut": "来る", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "來れる", "kanaOut": "來る", "rulesIn": ["v1"], "rulesOut": ["vk"]}
- ],
- "potential or passive": [
- {"kanaIn": "られる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v1"]},
- {"kanaIn": "ざれる", "kanaOut": "ずる", "rulesIn": ["v1"], "rulesOut": ["vz"]},
- {"kanaIn": "ぜられる", "kanaOut": "ずる", "rulesIn": ["v1"], "rulesOut": ["vz"]},
- {"kanaIn": "せられる", "kanaOut": "する", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "為られる", "kanaOut": "為る", "rulesIn": ["v1"], "rulesOut": ["vs"]},
- {"kanaIn": "こられる", "kanaOut": "くる", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "来られる", "kanaOut": "来る", "rulesIn": ["v1"], "rulesOut": ["vk"]},
- {"kanaIn": "來られる", "kanaOut": "來る", "rulesIn": ["v1"], "rulesOut": ["vk"]}
- ],
- "volitional": [
- {"kanaIn": "よう", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v1"]},
- {"kanaIn": "おう", "kanaOut": "う", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "こう", "kanaOut": "く", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ごう", "kanaOut": "ぐ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "そう", "kanaOut": "す", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "とう", "kanaOut": "つ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "のう", "kanaOut": "ぬ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ぼう", "kanaOut": "ぶ", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "もう", "kanaOut": "む", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "ろう", "kanaOut": "る", "rulesIn": [], "rulesOut": ["v5"]},
- {"kanaIn": "じよう", "kanaOut": "ずる", "rulesIn": [], "rulesOut": ["vz"]},
- {"kanaIn": "しよう", "kanaOut": "する", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "為よう", "kanaOut": "為る", "rulesIn": [], "rulesOut": ["vs"]},
- {"kanaIn": "こよう", "kanaOut": "くる", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "来よう", "kanaOut": "来る", "rulesIn": [], "rulesOut": ["vk"]},
- {"kanaIn": "來よう", "kanaOut": "來る", "rulesIn": [], "rulesOut": ["vk"]}
- ],
- "causative passive": [
- {"kanaIn": "かされる", "kanaOut": "く", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "がされる", "kanaOut": "ぐ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "たされる", "kanaOut": "つ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "なされる", "kanaOut": "ぬ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "ばされる", "kanaOut": "ぶ", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "まされる", "kanaOut": "む", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "らされる", "kanaOut": "る", "rulesIn": ["v1"], "rulesOut": ["v5"]},
- {"kanaIn": "わされる", "kanaOut": "う", "rulesIn": ["v1"], "rulesOut": ["v5"]}
- ],
- "-toku": [
- {"kanaIn": "とく", "kanaOut": "る", "rulesIn": ["v5"], "rulesOut": ["v1"]},
- {"kanaIn": "いとく", "kanaOut": "く", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "いどく", "kanaOut": "ぐ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "しとく", "kanaOut": "す", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っとく", "kanaOut": "う", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っとく", "kanaOut": "つ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "っとく", "kanaOut": "る", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んどく", "kanaOut": "ぬ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んどく", "kanaOut": "ぶ", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "んどく", "kanaOut": "む", "rulesIn": ["v5"], "rulesOut": ["v5"]},
- {"kanaIn": "じとく", "kanaOut": "ずる", "rulesIn": ["v5"], "rulesOut": ["vz"]},
- {"kanaIn": "しとく", "kanaOut": "する", "rulesIn": ["v5"], "rulesOut": ["vs"]},
- {"kanaIn": "為とく", "kanaOut": "為る", "rulesIn": ["v5"], "rulesOut": ["vs"]},
- {"kanaIn": "きとく", "kanaOut": "くる", "rulesIn": ["v5"], "rulesOut": ["vk"]},
- {"kanaIn": "来とく", "kanaOut": "来る", "rulesIn": ["v5"], "rulesOut": ["vk"]},
- {"kanaIn": "來とく", "kanaOut": "來る", "rulesIn": ["v5"], "rulesOut": ["vk"]}
- ],
- "progressive or perfect": [
- {"kanaIn": "ている", "kanaOut": "て", "rulesIn": ["v1"], "rulesOut": ["iru"]},
- {"kanaIn": "ておる", "kanaOut": "て", "rulesIn": ["v5"], "rulesOut": ["iru"]},
- {"kanaIn": "てる", "kanaOut": "て", "rulesIn": ["v1p"], "rulesOut": ["iru"]},
- {"kanaIn": "でいる", "kanaOut": "で", "rulesIn": ["v1"], "rulesOut": ["iru"]},
- {"kanaIn": "でおる", "kanaOut": "で", "rulesIn": ["v5"], "rulesOut": ["iru"]},
- {"kanaIn": "でる", "kanaOut": "で", "rulesIn": ["v1p"], "rulesOut": ["iru"]},
- {"kanaIn": "とる", "kanaOut": "て", "rulesIn": ["v5"], "rulesOut": ["iru"]},
- {"kanaIn": "ないでいる", "kanaOut": "ない", "rulesIn": ["v1"], "rulesOut": ["adj-i"]}
- ],
- "-ki": [
- {"kanaIn": "き", "kanaOut": "い", "rulesIn": [], "rulesOut": ["adj-i"]}
- ],
- "-ge": [
- {"kanaIn": "しげ", "kanaOut": "しい", "rulesIn": [], "rulesOut": ["adj-i"]}
- ],
- "-e": [
- {"kanaIn": "ねえ", "kanaOut": "ない", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "めえ", "kanaOut": "むい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "みい", "kanaOut": "むい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ちぇえ", "kanaOut": "つい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ちい", "kanaOut": "つい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "せえ", "kanaOut": "すい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ええ", "kanaOut": "いい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ええ", "kanaOut": "わい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ええ", "kanaOut": "よい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "いぇえ", "kanaOut": "よい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "うぇえ", "kanaOut": "わい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "けえ", "kanaOut": "かい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "げえ", "kanaOut": "がい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "げえ", "kanaOut": "ごい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "せえ", "kanaOut": "さい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "めえ", "kanaOut": "まい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ぜえ", "kanaOut": "ずい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "っぜえ", "kanaOut": "ずい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "れえ", "kanaOut": "らい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "れえ", "kanaOut": "らい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "ちぇえ", "kanaOut": "ちゃい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "でえ", "kanaOut": "どい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "れえ", "kanaOut": "れい", "rulesIn": [], "rulesOut": ["adj-i"]},
- {"kanaIn": "べえ", "kanaOut": "ばい", "rulesIn": [], "rulesOut": ["adj-i"]}
- ]
-}
diff --git a/ext/data/language/japanese-transforms.json b/ext/data/language/japanese-transforms.json
new file mode 100644
index 00000000..007b1404
--- /dev/null
+++ b/ext/data/language/japanese-transforms.json
@@ -0,0 +1,851 @@
+{
+ "language": "ja",
+ "conditions": {
+ "v1": {
+ "name": "Ichidan verb",
+ "partsOfSpeech": ["v1"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "一段動詞"
+ }
+ ],
+ "subConditions": ["v1d", "v1p"]
+ },
+ "v1d": {
+ "name": "Ichidan verb, dictionary form",
+ "partsOfSpeech": ["v1"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "一段動詞、辞書形"
+ }
+ ]
+ },
+ "v1p": {
+ "name": "Ichidan verb, progressive or perfect form",
+ "partsOfSpeech": ["v1"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "一段動詞、進行形または完了形"
+ }
+ ]
+ },
+ "v5": {
+ "name": "Godan verb",
+ "partsOfSpeech": ["v5"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "五段動詞"
+ }
+ ]
+ },
+ "vk": {
+ "name": "Kuru verb",
+ "partsOfSpeech": ["vk"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "来る動詞"
+ }
+ ]
+ },
+ "vs": {
+ "name": "Suru verb",
+ "partsOfSpeech": ["vs"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "する動詞"
+ }
+ ]
+ },
+ "vz": {
+ "name": "Zuru verb",
+ "partsOfSpeech": ["vz"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "ずる動詞"
+ }
+ ]
+ },
+ "adj-i": {
+ "name": "Adjective with i ending",
+ "partsOfSpeech": ["adj-i"],
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "形容詞"
+ }
+ ]
+ },
+ "iru": {
+ "name": "Intermediate -iru endings for progressive or perfect tense",
+ "partsOfSpeech": []
+ }
+ },
+ "transforms": [
+ {
+ "name": "-ba",
+ "description": "Conditional",
+ "i18n": [
+ {
+ "language": "ja",
+ "name": "ば",
+ "description": "仮定形"
+ }
+ ],
+ "rules": [
+ {"suffixIn": "ければ", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "えば", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "けば", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "げば", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "せば", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "てば", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ねば", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "べば", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "めば", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "れば", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1", "v5", "vk", "vs", "vz"]}
+ ]
+ },
+ {
+ "name": "-chau",
+ "rules": [
+ {"suffixIn": "ちゃう", "suffixOut": "る", "conditionsIn": ["v5"], "conditionsOut": ["v1"]},
+ {"suffixIn": "いじゃう", "suffixOut": "ぐ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "いちゃう", "suffixOut": "く", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "しちゃう", "suffixOut": "す", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちゃう", "suffixOut": "う", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちゃう", "suffixOut": "く", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちゃう", "suffixOut": "つ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちゃう", "suffixOut": "る", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んじゃう", "suffixOut": "ぬ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んじゃう", "suffixOut": "ぶ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んじゃう", "suffixOut": "む", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じちゃう", "suffixOut": "ずる", "conditionsIn": ["v5"], "conditionsOut": ["vz"]},
+ {"suffixIn": "しちゃう", "suffixOut": "する", "conditionsIn": ["v5"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ちゃう", "suffixOut": "為る", "conditionsIn": ["v5"], "conditionsOut": ["vs"]},
+ {"suffixIn": "きちゃう", "suffixOut": "くる", "conditionsIn": ["v5"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ちゃう", "suffixOut": "来る", "conditionsIn": ["v5"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ちゃう", "suffixOut": "來る", "conditionsIn": ["v5"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "-chimau",
+ "rules": [
+ {"suffixIn": "ちまう", "suffixOut": "る", "conditionsIn": ["v5"], "conditionsOut": ["v1"]},
+ {"suffixIn": "いじまう", "suffixOut": "ぐ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "いちまう", "suffixOut": "く", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "しちまう", "suffixOut": "す", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちまう", "suffixOut": "う", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちまう", "suffixOut": "く", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちまう", "suffixOut": "つ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っちまう", "suffixOut": "る", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んじまう", "suffixOut": "ぬ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んじまう", "suffixOut": "ぶ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んじまう", "suffixOut": "む", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じちまう", "suffixOut": "ずる", "conditionsIn": ["v5"], "conditionsOut": ["vz"]},
+ {"suffixIn": "しちまう", "suffixOut": "する", "conditionsIn": ["v5"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ちまう", "suffixOut": "為る", "conditionsIn": ["v5"], "conditionsOut": ["vs"]},
+ {"suffixIn": "きちまう", "suffixOut": "くる", "conditionsIn": ["v5"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ちまう", "suffixOut": "来る", "conditionsIn": ["v5"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ちまう", "suffixOut": "來る", "conditionsIn": ["v5"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "-shimau",
+ "rules": [
+ {"suffixIn": "てしまう", "suffixOut": "て", "conditionsIn": ["v5"], "conditionsOut": ["iru"]},
+ {"suffixIn": "でしまう", "suffixOut": "で", "conditionsIn": ["v5"], "conditionsOut": ["iru"]}
+ ]
+ },
+ {
+ "name": "-nasai",
+ "rules": [
+ {"suffixIn": "なさい", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いなさい", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "きなさい", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎなさい", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "しなさい", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちなさい", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "になさい", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "びなさい", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "みなさい", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "りなさい", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じなさい", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しなさい", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為なさい", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きなさい", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来なさい", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來なさい", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "-sou",
+ "rules": [
+ {"suffixIn": "そう", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "そう", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いそう", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "きそう", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎそう", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "しそう", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちそう", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "にそう", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "びそう", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "みそう", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "りそう", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じそう", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しそう", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為そう", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きそう", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来そう", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來そう", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "-sugiru",
+ "rules": [
+ {"suffixIn": "すぎる", "suffixOut": "い", "conditionsIn": ["v1"], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "すぎる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v1"]},
+ {"suffixIn": "いすぎる", "suffixOut": "う", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "きすぎる", "suffixOut": "く", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎすぎる", "suffixOut": "ぐ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "しすぎる", "suffixOut": "す", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちすぎる", "suffixOut": "つ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "にすぎる", "suffixOut": "ぬ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "びすぎる", "suffixOut": "ぶ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "みすぎる", "suffixOut": "む", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "りすぎる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じすぎる", "suffixOut": "ずる", "conditionsIn": ["v1"], "conditionsOut": ["vz"]},
+ {"suffixIn": "しすぎる", "suffixOut": "する", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為すぎる", "suffixOut": "為る", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "きすぎる", "suffixOut": "くる", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来すぎる", "suffixOut": "来る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來すぎる", "suffixOut": "來る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "-tai",
+ "rules": [
+ {"suffixIn": "たい", "suffixOut": "る", "conditionsIn": ["adj-i"], "conditionsOut": ["v1"]},
+ {"suffixIn": "いたい", "suffixOut": "う", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "きたい", "suffixOut": "く", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎたい", "suffixOut": "ぐ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "したい", "suffixOut": "す", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちたい", "suffixOut": "つ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "にたい", "suffixOut": "ぬ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "びたい", "suffixOut": "ぶ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "みたい", "suffixOut": "む", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "りたい", "suffixOut": "る", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じたい", "suffixOut": "ずる", "conditionsIn": ["adj-i"], "conditionsOut": ["vz"]},
+ {"suffixIn": "したい", "suffixOut": "する", "conditionsIn": ["adj-i"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為たい", "suffixOut": "為る", "conditionsIn": ["adj-i"], "conditionsOut": ["vs"]},
+ {"suffixIn": "きたい", "suffixOut": "くる", "conditionsIn": ["adj-i"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来たい", "suffixOut": "来る", "conditionsIn": ["adj-i"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來たい", "suffixOut": "來る", "conditionsIn": ["adj-i"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "-tara",
+ "rules": [
+ {"suffixIn": "かったら", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "たら", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いたら", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "いだら", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "したら", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ったら", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ったら", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ったら", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだら", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだら", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだら", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じたら", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "したら", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為たら", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きたら", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来たら", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來たら", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "いったら", "suffixOut": "いく", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "おうたら", "suffixOut": "おう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "こうたら", "suffixOut": "こう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "そうたら", "suffixOut": "そう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "とうたら", "suffixOut": "とう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "行ったら", "suffixOut": "行く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "逝ったら", "suffixOut": "逝く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "往ったら", "suffixOut": "往く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "請うたら", "suffixOut": "請う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "乞うたら", "suffixOut": "乞う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "恋うたら", "suffixOut": "恋う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "問うたら", "suffixOut": "問う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "負うたら", "suffixOut": "負う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "沿うたら", "suffixOut": "沿う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "添うたら", "suffixOut": "添う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "副うたら", "suffixOut": "副う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "厭うたら", "suffixOut": "厭う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "のたもうたら", "suffixOut": "のたまう", "conditionsIn": [], "conditionsOut": ["v5"]}
+ ]
+ },
+ {
+ "name": "-tari",
+ "rules": [
+ {"suffixIn": "かったり", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "たり", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いたり", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "いだり", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "したり", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ったり", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ったり", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ったり", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだり", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだり", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだり", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じたり", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "したり", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為たり", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きたり", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来たり", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來たり", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "いったり", "suffixOut": "いく", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "おうたり", "suffixOut": "おう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "こうたり", "suffixOut": "こう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "そうたり", "suffixOut": "そう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "とうたり", "suffixOut": "とう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "行ったり", "suffixOut": "行く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "逝ったり", "suffixOut": "逝く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "往ったり", "suffixOut": "往く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "請うたり", "suffixOut": "請う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "乞うたり", "suffixOut": "乞う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "恋うたり", "suffixOut": "恋う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "問うたり", "suffixOut": "問う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "負うたり", "suffixOut": "負う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "沿うたり", "suffixOut": "沿う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "添うたり", "suffixOut": "添う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "副うたり", "suffixOut": "副う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "厭うたり", "suffixOut": "厭う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "のたもうたり", "suffixOut": "のたまう", "conditionsIn": [], "conditionsOut": ["v5"]}
+ ]
+ },
+ {
+ "name": "-te",
+ "rules": [
+ {"suffixIn": "くて", "suffixOut": "い", "conditionsIn": ["iru"], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "て", "suffixOut": "る", "conditionsIn": ["iru"], "conditionsOut": ["v1"]},
+ {"suffixIn": "いて", "suffixOut": "く", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "いで", "suffixOut": "ぐ", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "して", "suffixOut": "す", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "って", "suffixOut": "う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "って", "suffixOut": "つ", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "って", "suffixOut": "る", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んで", "suffixOut": "ぬ", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んで", "suffixOut": "ぶ", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んで", "suffixOut": "む", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じて", "suffixOut": "ずる", "conditionsIn": ["iru"], "conditionsOut": ["vz"]},
+ {"suffixIn": "して", "suffixOut": "する", "conditionsIn": ["iru"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為て", "suffixOut": "為る", "conditionsIn": ["iru"], "conditionsOut": ["vs"]},
+ {"suffixIn": "きて", "suffixOut": "くる", "conditionsIn": ["iru"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来て", "suffixOut": "来る", "conditionsIn": ["iru"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來て", "suffixOut": "來る", "conditionsIn": ["iru"], "conditionsOut": ["vk"]},
+ {"suffixIn": "いって", "suffixOut": "いく", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "おうて", "suffixOut": "おう", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "こうて", "suffixOut": "こう", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "そうて", "suffixOut": "そう", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "とうて", "suffixOut": "とう", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "行って", "suffixOut": "行く", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "逝って", "suffixOut": "逝く", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "往って", "suffixOut": "往く", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "請うて", "suffixOut": "請う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "乞うて", "suffixOut": "乞う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "恋うて", "suffixOut": "恋う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "問うて", "suffixOut": "問う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "負うて", "suffixOut": "負う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "沿うて", "suffixOut": "沿う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "添うて", "suffixOut": "添う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "副うて", "suffixOut": "副う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "厭うて", "suffixOut": "厭う", "conditionsIn": ["iru"], "conditionsOut": ["v5"]},
+ {"suffixIn": "のたもうて", "suffixOut": "のたまう", "conditionsIn": ["iru"], "conditionsOut": ["v5"]}
+ ]
+ },
+ {
+ "name": "-zu",
+ "rules": [
+ {"suffixIn": "ず", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "かず", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "がず", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "さず", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "たず", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "なず", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ばず", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "まず", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "らず", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "わず", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぜず", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "せず", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ず", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "こず", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ず", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ず", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "-nu",
+ "rules": [
+ {"suffixIn": "ぬ", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "かぬ", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "がぬ", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "さぬ", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "たぬ", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "なぬ", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ばぬ", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "まぬ", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "らぬ", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "わぬ", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぜぬ", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "せぬ", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ぬ", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "こぬ", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ぬ", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ぬ", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "adv",
+ "rules": [
+ {"suffixIn": "く", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]}
+ ]
+ },
+ {
+ "name": "causative",
+ "rules": [
+ {"suffixIn": "させる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v1"]},
+ {"suffixIn": "かせる", "suffixOut": "く", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "がせる", "suffixOut": "ぐ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "させる", "suffixOut": "す", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "たせる", "suffixOut": "つ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "なせる", "suffixOut": "ぬ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ばせる", "suffixOut": "ぶ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ませる", "suffixOut": "む", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "らせる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "わせる", "suffixOut": "う", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じさせる", "suffixOut": "ずる", "conditionsIn": ["v1"], "conditionsOut": ["vz"]},
+ {"suffixIn": "ぜさせる", "suffixOut": "ずる", "conditionsIn": ["v1"], "conditionsOut": ["vz"]},
+ {"suffixIn": "させる", "suffixOut": "する", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為せる", "suffixOut": "為る", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "せさせる", "suffixOut": "する", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為させる", "suffixOut": "為る", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "こさせる", "suffixOut": "くる", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来させる", "suffixOut": "来る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來させる", "suffixOut": "來る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "imperative",
+ "rules": [
+ {"suffixIn": "ろ", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "よ", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "え", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "け", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "げ", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "せ", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "て", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ね", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "べ", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "め", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "れ", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じろ", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "ぜよ", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しろ", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "せよ", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ろ", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為よ", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "こい", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来い", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來い", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "imperative negative",
+ "rules": [
+ {"suffixIn": "な", "suffixOut": "", "conditionsIn": [], "conditionsOut": ["v1", "v5", "vk", "vs", "vz"]}
+ ]
+ },
+ {
+ "name": "masu stem",
+ "rules": [
+ {"suffixIn": "い", "suffixOut": "いる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "え", "suffixOut": "える", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "き", "suffixOut": "きる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "ぎ", "suffixOut": "ぎる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "け", "suffixOut": "ける", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "げ", "suffixOut": "げる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "じ", "suffixOut": "じる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "せ", "suffixOut": "せる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "ぜ", "suffixOut": "ぜる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "ち", "suffixOut": "ちる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "て", "suffixOut": "てる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "で", "suffixOut": "でる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "に", "suffixOut": "にる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "ね", "suffixOut": "ねる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "ひ", "suffixOut": "ひる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "び", "suffixOut": "びる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "へ", "suffixOut": "へる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "べ", "suffixOut": "べる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "み", "suffixOut": "みる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "め", "suffixOut": "める", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "り", "suffixOut": "りる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "れ", "suffixOut": "れる", "conditionsIn": [], "conditionsOut": ["v1d"]},
+ {"suffixIn": "い", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "き", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎ", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "し", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ち", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "に", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "び", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "み", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "り", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "き", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "negative",
+ "rules": [
+ {"suffixIn": "くない", "suffixOut": "い", "conditionsIn": ["adj-i"], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ない", "suffixOut": "る", "conditionsIn": ["adj-i"], "conditionsOut": ["v1"]},
+ {"suffixIn": "かない", "suffixOut": "く", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "がない", "suffixOut": "ぐ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "さない", "suffixOut": "す", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "たない", "suffixOut": "つ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "なない", "suffixOut": "ぬ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ばない", "suffixOut": "ぶ", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "まない", "suffixOut": "む", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "らない", "suffixOut": "る", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "わない", "suffixOut": "う", "conditionsIn": ["adj-i"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じない", "suffixOut": "ずる", "conditionsIn": ["adj-i"], "conditionsOut": ["vz"]},
+ {"suffixIn": "しない", "suffixOut": "する", "conditionsIn": ["adj-i"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ない", "suffixOut": "為る", "conditionsIn": ["adj-i"], "conditionsOut": ["vs"]},
+ {"suffixIn": "こない", "suffixOut": "くる", "conditionsIn": ["adj-i"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ない", "suffixOut": "来る", "conditionsIn": ["adj-i"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ない", "suffixOut": "來る", "conditionsIn": ["adj-i"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "noun",
+ "rules": [
+ {"suffixIn": "さ", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]}
+ ]
+ },
+ {
+ "name": "passive",
+ "rules": [
+ {"suffixIn": "かれる", "suffixOut": "く", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "がれる", "suffixOut": "ぐ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "される", "suffixOut": "す", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "たれる", "suffixOut": "つ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "なれる", "suffixOut": "ぬ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ばれる", "suffixOut": "ぶ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "まれる", "suffixOut": "む", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "われる", "suffixOut": "う", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "られる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じされる", "suffixOut": "ずる", "conditionsIn": ["v1"], "conditionsOut": ["vz"]},
+ {"suffixIn": "ぜされる", "suffixOut": "ずる", "conditionsIn": ["v1"], "conditionsOut": ["vz"]},
+ {"suffixIn": "される", "suffixOut": "する", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為れる", "suffixOut": "為る", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "こられる", "suffixOut": "くる", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来られる", "suffixOut": "来る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來られる", "suffixOut": "來る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "past",
+ "rules": [
+ {"suffixIn": "かった", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "た", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いた", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "いだ", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "した", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "った", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "った", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "った", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだ", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだ", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "んだ", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じた", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "した", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為た", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きた", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来た", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來た", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "いった", "suffixOut": "いく", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "おうた", "suffixOut": "おう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "こうた", "suffixOut": "こう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "そうた", "suffixOut": "そう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "とうた", "suffixOut": "とう", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "行った", "suffixOut": "行く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "逝った", "suffixOut": "逝く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "往った", "suffixOut": "往く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "請うた", "suffixOut": "請う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "乞うた", "suffixOut": "乞う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "恋うた", "suffixOut": "恋う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "問うた", "suffixOut": "問う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "負うた", "suffixOut": "負う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "沿うた", "suffixOut": "沿う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "添うた", "suffixOut": "添う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "副うた", "suffixOut": "副う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "厭うた", "suffixOut": "厭う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "のたもうた", "suffixOut": "のたまう", "conditionsIn": [], "conditionsOut": ["v5"]}
+ ]
+ },
+ {
+ "name": "polite",
+ "rules": [
+ {"suffixIn": "ます", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "います", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "きます", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎます", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "します", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちます", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "にます", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "びます", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "みます", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ります", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じます", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "します", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ます", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きます", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ます", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ます", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "polite negative",
+ "rules": [
+ {"suffixIn": "くありません", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ません", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いません", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "きません", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎません", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "しません", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちません", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "にません", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "びません", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "みません", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "りません", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じません", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しません", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ません", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きません", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ません", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ません", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "polite past",
+ "rules": [
+ {"suffixIn": "ました", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いました", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "きました", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎました", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "しました", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちました", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "にました", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "びました", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "みました", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "りました", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じました", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しました", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ました", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きました", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ました", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ました", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "polite past negative",
+ "rules": [
+ {"suffixIn": "くありませんでした", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ませんでした", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いませんでした", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "きませんでした", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎませんでした", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "しませんでした", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちませんでした", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "にませんでした", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "びませんでした", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "みませんでした", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "りませんでした", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じませんでした", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しませんでした", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ませんでした", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きませんでした", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ませんでした", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ませんでした", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "polite volitional",
+ "rules": [
+ {"suffixIn": "ましょう", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "いましょう", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "きましょう", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぎましょう", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "しましょう", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ちましょう", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "にましょう", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "びましょう", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "みましょう", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "りましょう", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じましょう", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しましょう", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為ましょう", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "きましょう", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来ましょう", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來ましょう", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "potential",
+ "rules": [
+ {"suffixIn": "れる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v1", "v5"]},
+ {"suffixIn": "える", "suffixOut": "う", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ける", "suffixOut": "く", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "げる", "suffixOut": "ぐ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "せる", "suffixOut": "す", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "てる", "suffixOut": "つ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ねる", "suffixOut": "ぬ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "べる", "suffixOut": "ぶ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "める", "suffixOut": "む", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "できる", "suffixOut": "する", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "出来る", "suffixOut": "する", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "これる", "suffixOut": "くる", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来れる", "suffixOut": "来る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來れる", "suffixOut": "來る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "potential or passive",
+ "rules": [
+ {"suffixIn": "られる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v1"]},
+ {"suffixIn": "ざれる", "suffixOut": "ずる", "conditionsIn": ["v1"], "conditionsOut": ["vz"]},
+ {"suffixIn": "ぜられる", "suffixOut": "ずる", "conditionsIn": ["v1"], "conditionsOut": ["vz"]},
+ {"suffixIn": "せられる", "suffixOut": "する", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為られる", "suffixOut": "為る", "conditionsIn": ["v1"], "conditionsOut": ["vs"]},
+ {"suffixIn": "こられる", "suffixOut": "くる", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来られる", "suffixOut": "来る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來られる", "suffixOut": "來る", "conditionsIn": ["v1"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "volitional",
+ "rules": [
+ {"suffixIn": "よう", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v1"]},
+ {"suffixIn": "おう", "suffixOut": "う", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "こう", "suffixOut": "く", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ごう", "suffixOut": "ぐ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "そう", "suffixOut": "す", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "とう", "suffixOut": "つ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "のう", "suffixOut": "ぬ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ぼう", "suffixOut": "ぶ", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "もう", "suffixOut": "む", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "ろう", "suffixOut": "る", "conditionsIn": [], "conditionsOut": ["v5"]},
+ {"suffixIn": "じよう", "suffixOut": "ずる", "conditionsIn": [], "conditionsOut": ["vz"]},
+ {"suffixIn": "しよう", "suffixOut": "する", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "為よう", "suffixOut": "為る", "conditionsIn": [], "conditionsOut": ["vs"]},
+ {"suffixIn": "こよう", "suffixOut": "くる", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "来よう", "suffixOut": "来る", "conditionsIn": [], "conditionsOut": ["vk"]},
+ {"suffixIn": "來よう", "suffixOut": "來る", "conditionsIn": [], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "causative passive",
+ "rules": [
+ {"suffixIn": "かされる", "suffixOut": "く", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "がされる", "suffixOut": "ぐ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "たされる", "suffixOut": "つ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "なされる", "suffixOut": "ぬ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "ばされる", "suffixOut": "ぶ", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "まされる", "suffixOut": "む", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "らされる", "suffixOut": "る", "conditionsIn": ["v1"], "conditionsOut": ["v5"]},
+ {"suffixIn": "わされる", "suffixOut": "う", "conditionsIn": ["v1"], "conditionsOut": ["v5"]}
+ ]
+ },
+ {
+ "name": "-toku",
+ "rules": [
+ {"suffixIn": "とく", "suffixOut": "る", "conditionsIn": ["v5"], "conditionsOut": ["v1"]},
+ {"suffixIn": "いとく", "suffixOut": "く", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "いどく", "suffixOut": "ぐ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "しとく", "suffixOut": "す", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っとく", "suffixOut": "う", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っとく", "suffixOut": "つ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "っとく", "suffixOut": "る", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んどく", "suffixOut": "ぬ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んどく", "suffixOut": "ぶ", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "んどく", "suffixOut": "む", "conditionsIn": ["v5"], "conditionsOut": ["v5"]},
+ {"suffixIn": "じとく", "suffixOut": "ずる", "conditionsIn": ["v5"], "conditionsOut": ["vz"]},
+ {"suffixIn": "しとく", "suffixOut": "する", "conditionsIn": ["v5"], "conditionsOut": ["vs"]},
+ {"suffixIn": "為とく", "suffixOut": "為る", "conditionsIn": ["v5"], "conditionsOut": ["vs"]},
+ {"suffixIn": "きとく", "suffixOut": "くる", "conditionsIn": ["v5"], "conditionsOut": ["vk"]},
+ {"suffixIn": "来とく", "suffixOut": "来る", "conditionsIn": ["v5"], "conditionsOut": ["vk"]},
+ {"suffixIn": "來とく", "suffixOut": "來る", "conditionsIn": ["v5"], "conditionsOut": ["vk"]}
+ ]
+ },
+ {
+ "name": "progressive or perfect",
+ "rules": [
+ {"suffixIn": "ている", "suffixOut": "て", "conditionsIn": ["v1"], "conditionsOut": ["iru"]},
+ {"suffixIn": "ておる", "suffixOut": "て", "conditionsIn": ["v5"], "conditionsOut": ["iru"]},
+ {"suffixIn": "てる", "suffixOut": "て", "conditionsIn": ["v1p"], "conditionsOut": ["iru"]},
+ {"suffixIn": "でいる", "suffixOut": "で", "conditionsIn": ["v1"], "conditionsOut": ["iru"]},
+ {"suffixIn": "でおる", "suffixOut": "で", "conditionsIn": ["v5"], "conditionsOut": ["iru"]},
+ {"suffixIn": "でる", "suffixOut": "で", "conditionsIn": ["v1p"], "conditionsOut": ["iru"]},
+ {"suffixIn": "とる", "suffixOut": "て", "conditionsIn": ["v5"], "conditionsOut": ["iru"]},
+ {"suffixIn": "ないでいる", "suffixOut": "ない", "conditionsIn": ["v1"], "conditionsOut": ["adj-i"]}
+ ]
+ },
+ {
+ "name": "-ki",
+ "rules": [
+ {"suffixIn": "き", "suffixOut": "い", "conditionsIn": [], "conditionsOut": ["adj-i"]}
+ ]
+ },
+ {
+ "name": "-ge",
+ "rules": [
+ {"suffixIn": "しげ", "suffixOut": "しい", "conditionsIn": [], "conditionsOut": ["adj-i"]}
+ ]
+ },
+ {
+ "name": "-e",
+ "rules": [
+ {"suffixIn": "ねえ", "suffixOut": "ない", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "めえ", "suffixOut": "むい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "みい", "suffixOut": "むい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ちぇえ", "suffixOut": "つい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ちい", "suffixOut": "つい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "せえ", "suffixOut": "すい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ええ", "suffixOut": "いい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ええ", "suffixOut": "わい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ええ", "suffixOut": "よい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "いぇえ", "suffixOut": "よい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "うぇえ", "suffixOut": "わい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "けえ", "suffixOut": "かい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "げえ", "suffixOut": "がい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "げえ", "suffixOut": "ごい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "せえ", "suffixOut": "さい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "めえ", "suffixOut": "まい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ぜえ", "suffixOut": "ずい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "っぜえ", "suffixOut": "ずい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "れえ", "suffixOut": "らい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "れえ", "suffixOut": "らい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "ちぇえ", "suffixOut": "ちゃい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "でえ", "suffixOut": "どい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "れえ", "suffixOut": "れい", "conditionsIn": [], "conditionsOut": ["adj-i"]},
+ {"suffixIn": "べえ", "suffixOut": "ばい", "conditionsIn": [], "conditionsOut": ["adj-i"]}
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js
index 74c1370c..0773dc4b 100644
--- a/ext/js/background/backend.js
+++ b/ext/js/background/backend.js
@@ -282,9 +282,9 @@ export class Backend {
log.error(e);
}
- /** @type {import('deinflector').ReasonsRaw} */
- const deinflectionReasons = await this._fetchJson('/data/deinflect.json');
- this._translator.prepare(deinflectionReasons);
+ /** @type {import('language-transformer').LanguageTransformDescriptor} */
+ const descriptor = await this._fetchJson('/data/language/japanese-transforms.json');
+ this._translator.prepare(descriptor);
await this._optionsUtil.prepare();
this._defaultAnkiFieldTemplates = (await this._fetchText('/data/templates/default-anki-field-templates.handlebars')).trim();
diff --git a/ext/js/background/offscreen-proxy.js b/ext/js/background/offscreen-proxy.js
index 555c3abc..80ff31c0 100644
--- a/ext/js/background/offscreen-proxy.js
+++ b/ext/js/background/offscreen-proxy.js
@@ -159,10 +159,10 @@ export class TranslatorProxy {
}
/**
- * @param {import('deinflector').ReasonsRaw} deinflectionReasons
+ * @param {import('language-transformer').LanguageTransformDescriptor} descriptor
*/
- async prepare(deinflectionReasons) {
- await this._offscreen.sendMessagePromise({action: 'translatorPrepareOffscreen', params: {deinflectionReasons}});
+ async prepare(descriptor) {
+ await this._offscreen.sendMessagePromise({action: 'translatorPrepareOffscreen', params: {descriptor}});
}
/**
diff --git a/ext/js/background/offscreen.js b/ext/js/background/offscreen.js
index a0f5592e..ef05508a 100644
--- a/ext/js/background/offscreen.js
+++ b/ext/js/background/offscreen.js
@@ -115,8 +115,8 @@ export class Offscreen {
}
/** @type {import('offscreen').ApiHandler<'translatorPrepareOffscreen'>} */
- _prepareTranslatorHandler({deinflectionReasons}) {
- this._translator.prepare(deinflectionReasons);
+ _prepareTranslatorHandler({descriptor}) {
+ this._translator.prepare(descriptor);
}
/** @type {import('offscreen').ApiHandler<'findKanjiOffscreen'>} */
diff --git a/ext/js/language/deinflector.js b/ext/js/language/deinflector.js
deleted file mode 100644
index b52b7f5b..00000000
--- a/ext/js/language/deinflector.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2023-2024 Yomitan Authors
- * Copyright (C) 2016-2022 Yomichan Authors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
-
-export class Deinflector {
- /* eslint-disable no-multi-spaces */
- /** @type {Map<string, import('translation-internal').DeinflectionRuleFlags>} @readonly */
- static _ruleTypes = new Map([
- ['v1', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b000000011)], // Verb ichidan
- ['v1d', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b000000010)], // Verb ichidan dictionary form
- ['v1p', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b000000001)], // Verb ichidan progressive or perfect
- ['v5', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b000000100)], // Verb godan
- ['vs', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b000001000)], // Verb suru
- ['vk', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b000010000)], // Verb kuru
- ['vz', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b000100000)], // Verb zuru
- ['adj-i', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b001000000)], // Adjective i
- ['iru', /** @type {import('translation-internal').DeinflectionRuleFlags} */ (0b010000000)] // Intermediate -iru endings for progressive or perfect tense
- ]);
- /* eslint-enable no-multi-spaces */
-
- /**
- * @param {import('deinflector').ReasonsRaw} reasons
- * @example
- * const deinflectionReasons = parseJson(
- * readFileSync(path.join('ext/data/deinflect.json')).toString(),
- * );
- * const deinflector = new Deinflector(deinflectionReasons);
- */
- constructor(reasons) {
- /** @type {import('deinflector').Reason[]} */
- this.reasons = Deinflector.normalizeReasons(reasons);
- }
-
- /**
- * Deinflects a Japanese term to all of its possible dictionary forms.
- * @param {string} source The source term to deinflect.
- * @returns {import('translation-internal').Deinflection[]}
- * @example
- * const deinflector = new Deinflector(deinflectionReasons);
- * // [{ term: '食べた', rules: 0, reasons: [] }, { term: '食べる', rules: 1, reasons: ['past'] }, { term: '食ぶ', rules: 2, reasons: ['potential', 'past'] }]
- * console.log(deinflector.deinflect('食べた'));
- */
- deinflect(source) {
- const results = [this._createDeinflection(source, 0, [])];
- for (let i = 0; i < results.length; ++i) {
- const {rules, term, reasons} = results[i];
- for (const [reason, variants] of this.reasons) {
- for (const [kanaIn, kanaOut, rulesIn, rulesOut] of variants) {
- if (
- !Deinflector.rulesMatch(rules, rulesIn) ||
- !term.endsWith(kanaIn) ||
- (term.length - kanaIn.length + kanaOut.length) <= 0
- ) {
- continue;
- }
-
- results.push(this._createDeinflection(
- term.substring(0, term.length - kanaIn.length) + kanaOut,
- rulesOut,
- [reason, ...reasons]
- ));
- }
- }
- }
- return results;
- }
-
- /**
- * @param {string} term
- * @param {import('translation-internal').DeinflectionRuleFlags} rules
- * @param {import('dictionary').InflectionRuleChain} reasons
- * @returns {import('translation-internal').Deinflection}
- */
- _createDeinflection(term, rules, reasons) {
- return {term, rules, reasons};
- }
-
- /**
- * @param {import('deinflector').ReasonsRaw} reasons
- * @returns {import('deinflector').Reason[]}
- */
- static normalizeReasons(reasons) {
- /** @type {import('deinflector').Reason[]} */
- const normalizedReasons = [];
- for (const [reason, reasonInfo] of Object.entries(reasons)) {
- /** @type {import('deinflector').ReasonVariant[]} */
- const variants = [];
- for (const {kanaIn, kanaOut, rulesIn, rulesOut} of reasonInfo) {
- variants.push([
- kanaIn,
- kanaOut,
- this.rulesToRuleFlags(rulesIn),
- this.rulesToRuleFlags(rulesOut)
- ]);
- }
- normalizedReasons.push([reason, variants]);
- }
- return normalizedReasons;
- }
-
- /**
- * @param {string[]} rules
- * @returns {import('translation-internal').DeinflectionRuleFlags}
- */
- static rulesToRuleFlags(rules) {
- const ruleTypes = this._ruleTypes;
- let value = 0;
- for (const rule of rules) {
- const ruleBits = ruleTypes.get(rule);
- if (typeof ruleBits === 'undefined') { continue; }
- value |= ruleBits;
- }
- return value;
- }
-
- /**
- * If `currentRules` is `0`, then `nextRules` is ignored and `true` is returned.
- * Otherwise, there must be at least one shared rule between `currentRules` and `nextRules`.
- * @param {number} currentRules
- * @param {number} nextRules
- * @returns {boolean}
- */
- static rulesMatch(currentRules, nextRules) {
- return currentRules === 0 || (currentRules & nextRules) !== 0;
- }
-}
diff --git a/ext/js/language/language-transformer.js b/ext/js/language/language-transformer.js
new file mode 100644
index 00000000..c9e261ea
--- /dev/null
+++ b/ext/js/language/language-transformer.js
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2024 Yomitan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+export class LanguageTransformer {
+ constructor() {
+ /** @type {number} */
+ this._nextFlagIndex = 0;
+ /** @type {import('language-transformer-internal').Transform[]} */
+ this._transforms = [];
+ /** @type {Map<string, number>} */
+ this._conditionTypeToConditionFlagsMap = new Map();
+ /** @type {Map<string, number>} */
+ this._partOfSpeechToConditionFlagsMap = new Map();
+ }
+
+ /** */
+ clear() {
+ this._nextFlagIndex = 0;
+ this._transforms = [];
+ this._conditionTypeToConditionFlagsMap.clear();
+ this._partOfSpeechToConditionFlagsMap.clear();
+ }
+
+ /**
+ * Note: this function does not currently combine properly with previous descriptors,
+ * they are treated as completely separate collections. This should eventually be changed.
+ * @param {import('language-transformer').LanguageTransformDescriptor} descriptor
+ * @throws {Error}
+ */
+ addDescriptor(descriptor) {
+ const {conditions, transforms} = descriptor;
+ const conditionEntries = Object.entries(conditions);
+ const {conditionFlagsMap, nextFlagIndex} = this._getConditionFlagsMap(conditionEntries, this._nextFlagIndex);
+
+ /** @type {import('language-transformer-internal').Transform[]} */
+ const transforms2 = [];
+ for (let i = 0, ii = transforms.length; i < ii; ++i) {
+ const {name, rules} = transforms[i];
+ /** @type {import('language-transformer-internal').Rule[]} */
+ const rules2 = [];
+ for (let j = 0, jj = rules.length; j < jj; ++j) {
+ const {suffixIn, suffixOut, conditionsIn, conditionsOut} = rules[j];
+ const conditionFlagsIn = this._getConditionFlags(conditionFlagsMap, conditionsIn);
+ if (conditionFlagsIn === null) { throw new Error(`Invalid conditionsIn for transform[${i}].rules[${j}]`); }
+ const conditionFlagsOut = this._getConditionFlags(conditionFlagsMap, conditionsOut);
+ if (conditionFlagsOut === null) { throw new Error(`Invalid conditionsOut for transform[${i}].rules[${j}]`); }
+ rules2.push({
+ suffixIn,
+ suffixOut,
+ conditionsIn: conditionFlagsIn,
+ conditionsOut: conditionFlagsOut
+ });
+ }
+ transforms2.push({name, rules: rules2});
+ }
+
+ this._nextFlagIndex = nextFlagIndex;
+ for (const transform of transforms2) {
+ this._transforms.push(transform);
+ }
+
+ for (const [type, condition] of conditionEntries) {
+ const flags = conditionFlagsMap.get(type);
+ if (typeof flags === 'undefined') { continue; } // This case should never happen
+ this._conditionTypeToConditionFlagsMap.set(type, flags);
+ for (const partOfSpeech of condition.partsOfSpeech) {
+ this._partOfSpeechToConditionFlagsMap.set(partOfSpeech, this.getConditionFlagsFromPartOfSpeech(partOfSpeech) | flags);
+ }
+ }
+ }
+
+ /**
+ * @param {string} partOfSpeech
+ * @returns {number}
+ */
+ getConditionFlagsFromPartOfSpeech(partOfSpeech) {
+ const conditionFlags = this._partOfSpeechToConditionFlagsMap.get(partOfSpeech);
+ return typeof conditionFlags !== 'undefined' ? conditionFlags : 0;
+ }
+
+ /**
+ * @param {string[]} partsOfSpeech
+ * @returns {number}
+ */
+ getConditionFlagsFromPartsOfSpeech(partsOfSpeech) {
+ let result = 0;
+ for (const partOfSpeech of partsOfSpeech) {
+ result |= this.getConditionFlagsFromPartOfSpeech(partOfSpeech);
+ }
+ return result;
+ }
+
+ /**
+ * @param {string} conditionType
+ * @returns {number}
+ */
+ getConditionFlagsFromConditionType(conditionType) {
+ const conditionFlags = this._conditionTypeToConditionFlagsMap.get(conditionType);
+ return typeof conditionFlags !== 'undefined' ? conditionFlags : 0;
+ }
+
+ /**
+ * @param {string[]} conditionTypes
+ * @returns {number}
+ */
+ getConditionFlagsFromConditionTypes(conditionTypes) {
+ let result = 0;
+ for (const conditionType of conditionTypes) {
+ result |= this.getConditionFlagsFromConditionType(conditionType);
+ }
+ return result;
+ }
+
+ /**
+ * @param {string} sourceText
+ * @returns {import('language-transformer-internal').TransformedText[]}
+ */
+ transform(sourceText) {
+ const results = [this._createTransformedText(sourceText, 0, [])];
+ for (let i = 0; i < results.length; ++i) {
+ const {text, conditions, trace} = results[i];
+ for (const {name, rules} of this._transforms) {
+ for (let j = 0, jj = rules.length; j < jj; ++j) {
+ const rule = rules[j];
+ if (!LanguageTransformer.conditionsMatch(conditions, rule.conditionsIn)) { continue; }
+ const {suffixIn, suffixOut} = rule;
+ if (!text.endsWith(suffixIn) || (text.length - suffixIn.length + suffixOut.length) <= 0) { continue; }
+ results.push(this._createTransformedText(
+ text.substring(0, text.length - suffixIn.length) + suffixOut,
+ rule.conditionsOut,
+ this._extendTrace(trace, {transform: name, ruleIndex: j})
+ ));
+ }
+ }
+ }
+ return results;
+ }
+
+ /**
+ * @param {import('language-transformer').ConditionMapEntries} conditions
+ * @param {number} nextFlagIndex
+ * @returns {{conditionFlagsMap: Map<string, number>, nextFlagIndex: number}}
+ * @throws {Error}
+ */
+ _getConditionFlagsMap(conditions, nextFlagIndex) {
+ /** @type {Map<string, number>} */
+ const conditionFlagsMap = new Map();
+ /** @type {import('language-transformer').ConditionMapEntries} */
+ let targets = conditions;
+ while (targets.length > 0) {
+ const nextTargets = [];
+ for (const target of targets) {
+ const [type, condition] = target;
+ const {subConditions} = condition;
+ let flags = 0;
+ if (typeof subConditions === 'undefined') {
+ if (nextFlagIndex >= 32) {
+ // Flags greater than or equal to 32 don't work because JavaScript only supports up to 32-bit integer operations
+ throw new Error('Maximum number of conditions was exceeded');
+ }
+ flags = 1 << nextFlagIndex;
+ ++nextFlagIndex;
+ } else {
+ const multiFlags = this._getConditionFlags(conditionFlagsMap, subConditions);
+ if (multiFlags === null) {
+ nextTargets.push(target);
+ continue;
+ } else {
+ flags = multiFlags;
+ }
+ }
+ conditionFlagsMap.set(type, flags);
+ }
+ if (nextTargets.length === targets.length) {
+ // Cycle in subRule declaration
+ throw new Error('Maximum number of conditions was exceeded');
+ }
+ targets = nextTargets;
+ }
+ return {conditionFlagsMap, nextFlagIndex};
+ }
+
+ /**
+ * @param {Map<string, number>} conditionFlagsMap
+ * @param {string[]} conditionTypes
+ * @returns {?number}
+ */
+ _getConditionFlags(conditionFlagsMap, conditionTypes) {
+ let flags = 0;
+ for (const conditionType of conditionTypes) {
+ const flags2 = conditionFlagsMap.get(conditionType);
+ if (typeof flags2 === 'undefined') { return null; }
+ flags |= flags2;
+ }
+ return flags;
+ }
+
+ /**
+ * @param {string} text
+ * @param {number} conditions
+ * @param {import('language-transformer-internal').Trace} trace
+ * @returns {import('language-transformer-internal').TransformedText}
+ */
+ _createTransformedText(text, conditions, trace) {
+ return {text, conditions, trace};
+ }
+
+ /**
+ * @param {import('language-transformer-internal').Trace} trace
+ * @param {import('language-transformer-internal').TraceFrame} newFrame
+ * @returns {import('language-transformer-internal').Trace}
+ */
+ _extendTrace(trace, newFrame) {
+ const newTrace = [newFrame];
+ for (const {transform, ruleIndex} of trace) {
+ newTrace.push({transform, ruleIndex});
+ }
+ return newTrace;
+ }
+
+ /**
+ * If `currentConditions` is `0`, then `nextConditions` is ignored and `true` is returned.
+ * Otherwise, there must be at least one shared condition between `currentConditions` and `nextConditions`.
+ * @param {number} currentConditions
+ * @param {number} nextConditions
+ * @returns {boolean}
+ */
+ static conditionsMatch(currentConditions, nextConditions) {
+ return currentConditions === 0 || (currentConditions & nextConditions) !== 0;
+ }
+}
diff --git a/ext/js/language/translator.js b/ext/js/language/translator.js
index 66eeb69f..9d2f18e0 100644
--- a/ext/js/language/translator.js
+++ b/ext/js/language/translator.js
@@ -18,9 +18,9 @@
import {RegexUtil} from '../general/regex-util.js';
import {TextSourceMap} from '../general/text-source-map.js';
-import {Deinflector} from './deinflector.js';
import {convertAlphabeticToKana} from './japanese-wanakana.js';
import {collapseEmphaticSequences, convertHalfWidthKanaToFullWidth, convertHiraganaToKatakana, convertKatakanaToHiragana, convertNumericToFullWidth, isCodePointJapanese} from './japanese.js';
+import {LanguageTransformer} from './language-transformer.js';
/**
* Class which finds term and kanji dictionary entries for text.
@@ -33,8 +33,8 @@ export class Translator {
constructor({database}) {
/** @type {import('../dictionary/dictionary-database.js').DictionaryDatabase} */
this._database = database;
- /** @type {?Deinflector} */
- this._deinflector = null;
+ /** @type {LanguageTransformer} */
+ this._languageTransformer = new LanguageTransformer();
/** @type {import('translator').DictionaryTagCache} */
this._tagCache = new Map();
/** @type {Intl.Collator} */
@@ -44,12 +44,11 @@ export class Translator {
}
/**
- * Initializes the instance for use. The public API should not be used until
- * this function has been called.
- * @param {import('deinflector').ReasonsRaw} deinflectionReasons The raw deinflections reasons data that the Deinflector uses.
+ * Initializes the instance for use. The public API should not be used until this function has been called.
+ * @param {import('language-transformer').LanguageTransformDescriptor} descriptor
*/
- prepare(deinflectionReasons) {
- this._deinflector = new Deinflector(deinflectionReasons);
+ prepare(descriptor) {
+ this._languageTransformer.addDescriptor(descriptor);
}
/**
@@ -407,10 +406,9 @@ export class Translator {
const entryDictionary = /** @type {import('translation').FindTermDictionary} */ (enabledDictionaryMap.get(databaseEntry.dictionary));
const {partsOfSpeechFilter} = entryDictionary;
- const definitionRules = Deinflector.rulesToRuleFlags(databaseEntry.rules);
+ const definitionConditions = this._languageTransformer.getConditionFlagsFromPartsOfSpeech(databaseEntry.rules);
for (const deinflection of uniqueDeinflectionArrays[databaseEntry.index]) {
- const deinflectionRules = deinflection.rules;
- if (!partsOfSpeechFilter || Deinflector.rulesMatch(deinflectionRules, definitionRules)) {
+ if (!partsOfSpeechFilter || LanguageTransformer.conditionsMatch(deinflection.conditions, definitionConditions)) {
deinflection.databaseEntries.push(databaseEntry);
}
}
@@ -473,13 +471,13 @@ export class Translator {
if (used.has(source)) { break; }
used.add(source);
const rawSource = sourceMap.source.substring(0, sourceMap.getSourceLength(i));
- for (const {term, rules, reasons} of /** @type {Deinflector} */ (this._deinflector).deinflect(source)) {
+ for (const {text: transformedText, conditions, trace} of this._languageTransformer.transform(source)) {
/** @type {import('dictionary').InflectionRuleChainCandidate} */
const inflectionRuleChainCandidate = {
source: 'algorithm',
- inflectionRules: reasons
+ inflectionRules: trace.map((frame) => frame.transform)
};
- deinflections.push(this._createDeinflection(rawSource, source, term, rules, [inflectionRuleChainCandidate]));
+ deinflections.push(this._createDeinflection(rawSource, source, transformedText, conditions, [inflectionRuleChainCandidate]));
}
}
}
@@ -570,12 +568,12 @@ export class Translator {
* @param {string} originalText
* @param {string} transformedText
* @param {string} deinflectedText
- * @param {import('translation-internal').DeinflectionRuleFlags} rules
+ * @param {number} conditions
* @param {import('dictionary').InflectionRuleChainCandidate[]} inflectionRuleChainCandidates
* @returns {import('translation-internal').DatabaseDeinflection}
*/
- _createDeinflection(originalText, transformedText, deinflectedText, rules, inflectionRuleChainCandidates) {
- return {originalText, transformedText, deinflectedText, rules, inflectionRuleChainCandidates, databaseEntries: []};
+ _createDeinflection(originalText, transformedText, deinflectedText, conditions, inflectionRuleChainCandidates) {
+ return {originalText, transformedText, deinflectedText, conditions, inflectionRuleChainCandidates, databaseEntries: []};
}
// Term dictionary entry grouping
diff --git a/test/data/json.json b/test/data/json.json
index 83b1b4e0..fe7df57d 100644
--- a/test/data/json.json
+++ b/test/data/json.json
@@ -30,11 +30,6 @@
"type": "ManifestConfig"
},
{
- "path": "ext/data/deinflect.json",
- "typeFile": "types/ext/deinflector.d.ts",
- "type": "ReasonsRaw"
- },
- {
"path": "ext/data/pronunciation-style.json",
"typeFile": "types/ext/css-style-applier.d.ts",
"type": "RawStyleData"
@@ -95,6 +90,11 @@
"type": "AjvSchema"
},
{
+ "path": "ext/data/language/japanese-transforms.json",
+ "typeFile": "types/ext/language-transformer.d.ts",
+ "type": "LanguageTransformDescriptor"
+ },
+ {
"path": "test/data/translator-test-inputs.json",
"typeFile": "types/test/translator.d.ts",
"type": "TranslatorTestInputs",
diff --git a/test/fixtures/translator-test.js b/test/fixtures/translator-test.js
index 6562931c..58247b70 100644
--- a/test/fixtures/translator-test.js
+++ b/test/fixtures/translator-test.js
@@ -32,7 +32,7 @@ import {DictionaryImporterMediaLoader} from '../mocks/dictionary-importer-media-
import {createDomTest} from './dom-test.js';
const extDir = join(dirname(fileURLToPath(import.meta.url)), '../../ext');
-const deinflectionReasonsPath = join(extDir, 'data/deinflect.json');
+const languageTransformDescriptorPath = join(extDir, 'data/language/japanese-transforms.json');
vi.stubGlobal('indexedDB', indexedDB);
vi.stubGlobal('IDBKeyRange', IDBKeyRange);
@@ -65,8 +65,8 @@ async function createTranslatorContext(dictionaryDirectory, dictionaryName) {
// Setup translator
const translator = new Translator({database: dictionaryDatabase});
- /** @type {import('deinflector').ReasonsRaw} */
- const deinflectionReasons = parseJson(readFileSync(deinflectionReasonsPath, {encoding: 'utf8'}));
+ /** @type {import('language-transformer').LanguageTransformDescriptor} */
+ const deinflectionReasons = parseJson(readFileSync(languageTransformDescriptorPath, {encoding: 'utf8'}));
translator.prepare(deinflectionReasons);
// Assign properties
diff --git a/test/deinflection-cycles.test.js b/test/language-transformer-cycles.test.js
index a010d7a3..76bee83e 100644
--- a/test/deinflection-cycles.test.js
+++ b/test/language-transformer-cycles.test.js
@@ -20,19 +20,19 @@ import {join, dirname as pathDirname} from 'path';
import {fileURLToPath} from 'url';
import {describe, test} from 'vitest';
import {parseJson} from '../dev/json.js';
-import {Deinflector} from '../ext/js/language/deinflector.js';
+import {LanguageTransformer} from '../ext/js/language/language-transformer.js';
class DeinflectionNode {
/**
* @param {string} text
- * @param {import('deinflector').ReasonTypeRaw[]} ruleNames
+ * @param {string[]} ruleNames
* @param {?RuleNode} ruleNode
* @param {?DeinflectionNode} previous
*/
constructor(text, ruleNames, ruleNode, previous) {
/** @type {string} */
this.text = text;
- /** @type {import('deinflector').ReasonTypeRaw[]} */
+ /** @type {string[]} */
this.ruleNames = ruleNames;
/** @type {?RuleNode} */
this.ruleNode = ruleNode;
@@ -79,12 +79,12 @@ class DeinflectionNode {
class RuleNode {
/**
* @param {string} groupName
- * @param {import('deinflector').ReasonRaw} rule
+ * @param {import('language-transformer').Rule} rule
*/
constructor(groupName, rule) {
/** @type {string} */
this.groupName = groupName;
- /** @type {import('deinflector').ReasonRaw} */
+ /** @type {import('language-transformer').Rule} */
this.rule = rule;
}
}
@@ -107,13 +107,15 @@ describe('Deinflection data', () => {
test('Check for cycles', ({expect}) => {
const dirname = pathDirname(fileURLToPath(import.meta.url));
- /** @type {import('deinflector').ReasonsRaw} */
- const deinflectionReasons = parseJson(readFileSync(join(dirname, '../ext/data/deinflect.json'), {encoding: 'utf8'}));
+ /** @type {import('language-transformer').LanguageTransformDescriptor} */
+ const descriptor = parseJson(readFileSync(join(dirname, '../ext/data/language/japanese-transforms.json'), {encoding: 'utf8'}));
+ const languageTransformer = new LanguageTransformer();
+ languageTransformer.addDescriptor(descriptor);
/** @type {RuleNode[]} */
const ruleNodes = [];
- for (const [groupName, reasonInfo] of Object.entries(deinflectionReasons)) {
- for (const rule of reasonInfo) {
+ for (const [groupName, reasonInfo] of Object.entries(descriptor.transforms)) {
+ for (const rule of reasonInfo.rules) {
ruleNodes.push(new RuleNode(groupName, rule));
}
}
@@ -121,24 +123,27 @@ describe('Deinflection data', () => {
/** @type {DeinflectionNode[]} */
const deinflectionNodes = [];
for (const ruleNode of ruleNodes) {
- deinflectionNodes.push(new DeinflectionNode(`?${ruleNode.rule.kanaIn}`, [], null, null));
+ deinflectionNodes.push(new DeinflectionNode(`?${ruleNode.rule.suffixIn}`, [], null, null));
}
for (let i = 0; i < deinflectionNodes.length; ++i) {
const deinflectionNode = deinflectionNodes[i];
const {text, ruleNames} = deinflectionNode;
for (const ruleNode of ruleNodes) {
- const {kanaIn, kanaOut, rulesIn, rulesOut} = ruleNode.rule;
+ const {suffixIn, suffixOut, conditionsIn, conditionsOut} = ruleNode.rule;
if (
- !Deinflector.rulesMatch(Deinflector.rulesToRuleFlags(ruleNames), Deinflector.rulesToRuleFlags(rulesIn)) ||
- !text.endsWith(kanaIn) ||
- (text.length - kanaIn.length + kanaOut.length) <= 0
+ !LanguageTransformer.conditionsMatch(
+ languageTransformer.getConditionFlagsFromConditionTypes(ruleNames),
+ languageTransformer.getConditionFlagsFromConditionTypes(conditionsIn)
+ ) ||
+ !text.endsWith(suffixIn) ||
+ (text.length - suffixIn.length + suffixOut.length) <= 0
) {
continue;
}
const newDeinflectionNode = new DeinflectionNode(
- text.substring(0, text.length - kanaIn.length) + kanaOut,
- rulesOut,
+ text.substring(0, text.length - suffixIn.length) + suffixOut,
+ conditionsOut,
ruleNode,
deinflectionNode
);
@@ -150,7 +155,7 @@ describe('Deinflection data', () => {
stack.push(
item.ruleNode === null ?
`${item.text} (start)` :
- `${item.text} (${item.ruleNode.groupName}, ${item.ruleNode.rule.rulesIn.join(',')}=>${item.ruleNode.rule.rulesOut.join(',')}, ${item.ruleNode.rule.kanaIn}=>${item.ruleNode.rule.kanaOut})`
+ `${item.text} (${item.ruleNode.groupName}, ${item.ruleNode.rule.conditionsIn.join(',')}=>${item.ruleNode.rule.conditionsOut.join(',')}, ${item.ruleNode.rule.suffixIn}=>${item.ruleNode.rule.suffixOut})`
);
}
const message = `Cycle detected:\n ${stack.join('\n ')}`;
diff --git a/test/deinflector.test.js b/test/language-transformer.test.js
index 71eb9349..b99c1bef 100644
--- a/test/deinflector.test.js
+++ b/test/language-transformer.test.js
@@ -21,37 +21,41 @@ import {fileURLToPath} from 'node:url';
import path from 'path';
import {describe, expect, test} from 'vitest';
import {parseJson} from '../dev/json.js';
-import {Deinflector} from '../ext/js/language/deinflector.js';
+import {LanguageTransformer} from '../ext/js/language/language-transformer.js';
const dirname = path.dirname(fileURLToPath(import.meta.url));
/**
- * @param {Deinflector} deinflector
+ * @param {LanguageTransformer} languageTransformer
* @param {string} source
* @param {string} expectedTerm
- * @param {string|null} expectedRule
+ * @param {string|null} expectedConditionName
* @param {string[]|null} expectedReasons
* @returns {{has: false, reasons: null, rules: null}|{has: true, reasons: string[], rules: number}}
*/
-function hasTermReasons(deinflector, source, expectedTerm, expectedRule, expectedReasons) {
- for (const {term, reasons, rules} of deinflector.deinflect(source)) {
- if (term !== expectedTerm) { continue; }
- if (expectedRule !== null) {
- const expectedFlags = Deinflector.rulesToRuleFlags([expectedRule]);
- if (!Deinflector.rulesMatch(rules, expectedFlags)) { continue; }
+function hasTermReasons(languageTransformer, source, expectedTerm, expectedConditionName, expectedReasons) {
+ for (const {text, conditions, trace} of languageTransformer.transform(source)) {
+ if (text !== expectedTerm) { continue; }
+ if (expectedConditionName !== null) {
+ const expectedConditions = languageTransformer.getConditionFlagsFromConditionType(expectedConditionName);
+ if (!LanguageTransformer.conditionsMatch(conditions, expectedConditions)) { continue; }
}
let okay = true;
if (expectedReasons !== null) {
- if (reasons.length !== expectedReasons.length) { continue; }
+ if (trace.length !== expectedReasons.length) { continue; }
for (let i = 0, ii = expectedReasons.length; i < ii; ++i) {
- if (expectedReasons[i] !== reasons[i]) {
+ if (expectedReasons[i] !== trace[i].transform) {
okay = false;
break;
}
}
}
if (okay) {
- return {has: true, reasons, rules};
+ return {
+ has: true,
+ reasons: trace.map((frame) => frame.transform),
+ rules: conditions
+ };
}
}
return {has: false, reasons: null, rules: null};
@@ -1010,15 +1014,16 @@ function testDeinflections() {
];
/* eslint-enable no-multi-spaces */
- /** @type {import('deinflector').ReasonsRaw} */
- const deinflectionReasons = parseJson(fs.readFileSync(path.join(dirname, '..', 'ext', 'data/deinflect.json'), {encoding: 'utf8'}));
- const deinflector = new Deinflector(deinflectionReasons);
+ /** @type {import('language-transformer').LanguageTransformDescriptor} */
+ const descriptor = parseJson(fs.readFileSync(path.join(dirname, '..', 'ext', 'data/language/japanese-transforms.json'), {encoding: 'utf8'}));
+ const languageTransformer = new LanguageTransformer();
+ languageTransformer.addDescriptor(descriptor);
describe('deinflections', () => {
// for (const {valid, tests} of data) {
describe.each(data)('$category', ({valid, tests}) => {
for (const {source, term, rule, reasons} of tests) {
- const {has} = hasTermReasons(deinflector, source, term, rule, reasons);
+ const {has} = hasTermReasons(languageTransformer, source, term, rule, reasons);
let message = `${source} ${valid ? 'has' : 'does not have'} term candidate ${JSON.stringify(term)}`;
if (typeof rule !== 'undefined') {
message += ` with rule ${JSON.stringify(rule)}`;
diff --git a/types/ext/deinflector.d.ts b/types/ext/language-transformer-internal.d.ts
index 18d0f04a..cb0899e9 100644
--- a/types/ext/deinflector.d.ts
+++ b/types/ext/language-transformer-internal.d.ts
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023-2024 Yomitan Authors
+ * Copyright (C) 2024 Yomitan Authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -15,29 +15,27 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import type * as TranslationInternal from './translation-internal';
-
-export type ReasonTypeRaw = 'v1' | 'v1d' | 'v1p' | 'v5' | 'vs' | 'vk' | 'vz' | 'adj-i' | 'iru';
+export type Transform = {
+ name: string;
+ rules: Rule[];
+};
-export type ReasonsRaw = {
- [reason: string]: ReasonRaw[];
+export type Rule = {
+ suffixIn: string;
+ suffixOut: string;
+ conditionsIn: number;
+ conditionsOut: number;
};
-export type ReasonRaw = {
- kanaIn: string;
- kanaOut: string;
- rulesIn: ReasonTypeRaw[];
- rulesOut: ReasonTypeRaw[];
+export type TransformedText = {
+ text: string;
+ conditions: number;
+ trace: Trace;
};
-export type ReasonVariant = [
- kanaIn: string,
- kanaOut: string,
- rulesIn: TranslationInternal.DeinflectionRuleFlags,
- rulesOut: TranslationInternal.DeinflectionRuleFlags,
-];
+export type Trace = TraceFrame[];
-export type Reason = [
- reason: string,
- variants: ReasonVariant[],
-];
+export type TraceFrame = {
+ transform: string;
+ ruleIndex: number;
+};
diff --git a/types/ext/language-transformer.d.ts b/types/ext/language-transformer.d.ts
new file mode 100644
index 00000000..08c7a3dc
--- /dev/null
+++ b/types/ext/language-transformer.d.ts
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 Yomitan Authors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ */
+
+export type LanguageTransformDescriptor = {
+ language: string;
+ conditions: ConditionMapObject;
+ transforms: Transform[];
+};
+
+export type ConditionMapObject = {
+ [type: string]: Condition;
+};
+
+export type ConditionMapEntry = [type: string, condition: Condition];
+
+export type ConditionMapEntries = ConditionMapEntry[];
+
+export type Condition = {
+ name: string;
+ partsOfSpeech: string[];
+ i18n?: RuleI18n[];
+ subConditions?: string[];
+};
+
+export type RuleI18n = {
+ language: string;
+ name: string;
+};
+
+export type Transform = {
+ name: string;
+ description?: string;
+ i18n?: TransformI18n[];
+ rules: Rule[];
+};
+
+export type TransformI18n = {
+ language: string;
+ name: string;
+ description?: string;
+};
+
+export type Rule = {
+ suffixIn: string;
+ suffixOut: string;
+ conditionsIn: string[];
+ conditionsOut: string[];
+};
diff --git a/types/ext/offscreen.d.ts b/types/ext/offscreen.d.ts
index a721c1b9..443e0b64 100644
--- a/types/ext/offscreen.d.ts
+++ b/types/ext/offscreen.d.ts
@@ -15,7 +15,6 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-import type * as Deinflector from './deinflector';
import type * as Dictionary from './dictionary';
import type * as DictionaryDatabase from './dictionary-database';
import type * as DictionaryImporter from './dictionary-importer';
@@ -30,6 +29,7 @@ import type {
ApiReturn as BaseApiReturn,
ApiNames as BaseApiNames,
} from './api-map';
+import type {LanguageTransformDescriptor} from './language-transformer';
type ApiSurface = {
databasePrepareOffscreen: {
@@ -52,7 +52,7 @@ type ApiSurface = {
};
translatorPrepareOffscreen: {
params: {
- deinflectionReasons: Deinflector.ReasonsRaw;
+ descriptor: LanguageTransformDescriptor;
};
return: void;
};
diff --git a/types/ext/translation-internal.d.ts b/types/ext/translation-internal.d.ts
index ada611d9..82704c54 100644
--- a/types/ext/translation-internal.d.ts
+++ b/types/ext/translation-internal.d.ts
@@ -39,28 +39,11 @@ export type TextDeinflectionOptionsArrays = [
emphatic: [collapseEmphatic: boolean, collapseEmphaticFull: boolean][],
];
-export enum DeinflectionRuleFlags {
- None = 0x0,
- VerbIchidan = 0b00000001,
- VerbGodan = 0b00000010,
- VerbSuru = 0b00000100,
- VerbKuru = 0b00001000,
- VerbZuru = 0b00010000,
- AdjectiveI = 0b00100000,
- IruEndingIntermediate = 0b01000000,
-}
-
-export type Deinflection = {
- term: string;
- rules: DeinflectionRuleFlags;
- reasons: Dictionary.InflectionRuleChain;
-};
-
export type DatabaseDeinflection = {
originalText: string;
transformedText: string;
deinflectedText: string;
- rules: DeinflectionRuleFlags;
+ conditions: number;
inflectionRuleChainCandidates: Dictionary.InflectionRuleChainCandidate[];
databaseEntries: DictionaryDatabase.TermEntry[];
};