diff --git a/ext/bg/js/dictionary.js b/ext/bg/js/dictionary.js
index 2a80e2d0..6aed52f4 100644
--- a/ext/bg/js/dictionary.js
+++ b/ext/bg/js/dictionary.js
@@ -137,7 +137,8 @@ function dictTermsGroup(definitions, dictionaries) {
reading: firstDef.reading,
reasons: firstDef.reasons,
score: groupDefs.reduce((p, v) => v.score > p ? v.score : p, Number.MIN_SAFE_INTEGER),
- source: firstDef.source
+ source: firstDef.source,
+ furigana: firstDef.furigana
});
}
diff --git a/ext/bg/js/templates.js b/ext/bg/js/templates.js
index 7e05015a..35a7beb1 100644
--- a/ext/bg/js/templates.js
+++ b/ext/bg/js/templates.js
@@ -7,19 +7,19 @@ templates['dictionary.html'] = template({"1":function(container,depth0,helpers,p
return "
";
-},"44":function(container,depth0,helpers,partials,data) {
+},"50":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(45, data, 0),"inverse":container.program(51, data, 0),"data":data})) != null ? stack1 : "");
-},"45":function(container,depth0,helpers,partials,data) {
- var stack1;
-
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(46, data, 0),"inverse":container.program(49, data, 0),"data":data})) != null ? stack1 : "");
-},"46":function(container,depth0,helpers,partials,data) {
- var stack1;
-
- return "
"
- + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(47, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
- + "
";
-},"47":function(container,depth0,helpers,partials,data) {
- return "
"
- + container.escapeExpression(container.lambda(depth0, depth0))
- + "";
-},"49":function(container,depth0,helpers,partials,data) {
- var stack1;
-
- return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(51, data, 0),"inverse":container.program(57, data, 0),"data":data})) != null ? stack1 : "");
},"51":function(container,depth0,helpers,partials,data) {
var stack1;
- return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["0"] : stack1), depth0));
-},"53":function(container,depth0,helpers,partials,data,blockParams,depths) {
- var stack1;
-
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.group : depth0),{"name":"if","hash":{},"fn":container.program(54, data, 0, blockParams, depths),"inverse":container.program(64, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
-},"54":function(container,depth0,helpers,partials,data,blockParams,depths) {
- var stack1;
-
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(55, data, 0, blockParams, depths),"inverse":container.program(62, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
-},"55":function(container,depth0,helpers,partials,data,blockParams,depths) {
- var stack1;
-
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(56, data, 0, blockParams, depths),"inverse":container.program(59, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
-},"56":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(52, data, 0),"inverse":container.program(55, data, 0),"data":data})) != null ? stack1 : "");
+},"52":function(container,depth0,helpers,partials,data) {
var stack1;
return "
"
- + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(57, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(53, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ "
";
-},"57":function(container,depth0,helpers,partials,data,blockParams,depths) {
+},"53":function(container,depth0,helpers,partials,data) {
+ return "
"
+ + container.escapeExpression(container.lambda(depth0, depth0))
+ + "";
+},"55":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"57":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.glossary : stack1)) != null ? stack1["0"] : stack1), depth0));
+},"59":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.group : depth0),{"name":"if","hash":{},"fn":container.program(60, data, 0, blockParams, depths),"inverse":container.program(70, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
+},"60":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["1"] : stack1),{"name":"if","hash":{},"fn":container.program(61, data, 0, blockParams, depths),"inverse":container.program(68, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
+},"61":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(62, data, 0, blockParams, depths),"inverse":container.program(65, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
+},"62":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ var stack1;
+
+ return "
"
+ + ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(63, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "")
+ + "
";
+},"63":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return "
"
+ ((stack1 = container.invokePartial(partials["glossary-single"],depth0,{"name":"glossary-single","hash":{"brief":(depths[1] != null ? depths[1].brief : depths[1]),"html":(depths[1] != null ? depths[1].html : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "")
+ "";
-},"59":function(container,depth0,helpers,partials,data,blockParams,depths) {
+},"65":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
- return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(60, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
-},"60":function(container,depth0,helpers,partials,data,blockParams,depths) {
+ return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1),{"name":"each","hash":{},"fn":container.program(66, data, 0, blockParams, depths),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"66":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
return " * "
+ ((stack1 = container.invokePartial(partials["glossary-single"],depth0,{"name":"glossary-single","hash":{"brief":(depths[1] != null ? depths[1].brief : depths[1]),"html":(depths[1] != null ? depths[1].html : depths[1])},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
-},"62":function(container,depth0,helpers,partials,data) {
- var stack1;
-
- return ((stack1 = container.invokePartial(partials["glossary-single"],((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["0"] : stack1),{"name":"glossary-single","hash":{"brief":(depth0 != null ? depth0.brief : depth0),"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
-},"64":function(container,depth0,helpers,partials,data) {
- var stack1;
-
- return ((stack1 = container.invokePartial(partials["glossary-single"],(depth0 != null ? depth0.definition : depth0),{"name":"glossary-single","hash":{"brief":(depth0 != null ? depth0.brief : depth0),"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
-},"66":function(container,depth0,helpers,partials,data) {
- return "
";
},"68":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = container.invokePartial(partials.glossary,depth0,{"name":"glossary","hash":{"brief":true},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
+ return ((stack1 = container.invokePartial(partials["glossary-single"],((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.definitions : stack1)) != null ? stack1["0"] : stack1),{"name":"glossary-single","hash":{"brief":(depth0 != null ? depth0.brief : depth0),"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"70":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.kunyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+ return ((stack1 = container.invokePartial(partials["glossary-single"],(depth0 != null ? depth0.definition : depth0),{"name":"glossary-single","hash":{"brief":(depth0 != null ? depth0.brief : depth0),"html":(depth0 != null ? depth0.html : depth0)},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"72":function(container,depth0,helpers,partials,data) {
- var stack1;
-
- return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.onyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+ return "";
},"74":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.modeTermKana : depth0),{"name":"unless","hash":{},"fn":container.program(30, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+ return ((stack1 = container.invokePartial(partials.glossary,depth0,{"name":"glossary","hash":{"brief":true},"data":data,"helpers":helpers,"partials":partials,"decorators":container.decorators})) != null ? stack1 : "");
},"76":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(77, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
-},"77":function(container,depth0,helpers,partials,data) {
+ return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.kunyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"78":function(container,depth0,helpers,partials,data) {
var stack1;
- return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.sentence : stack1), depth0));
-},"79":function(container,depth0,helpers,partials,data) {
- var stack1;
-
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(80, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+ return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.onyomi : stack1),{"name":"each","hash":{},"fn":container.program(20, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"80":function(container,depth0,helpers,partials,data) {
var stack1;
- return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.prefix : stack1), depth0));
+ return ((stack1 = helpers.unless.call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.modeTermKana : depth0),{"name":"unless","hash":{},"fn":container.program(30, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
},"82":function(container,depth0,helpers,partials,data) {
var stack1;
@@ -266,7 +269,7 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti
},"83":function(container,depth0,helpers,partials,data) {
var stack1;
- return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.body : stack1), depth0));
+ return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.sentence : stack1), depth0));
},"85":function(container,depth0,helpers,partials,data) {
var stack1;
@@ -274,16 +277,32 @@ templates['fields.html'] = template({"1":function(container,depth0,helpers,parti
},"86":function(container,depth0,helpers,partials,data) {
var stack1;
- return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.suffix : stack1), depth0));
+ return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.prefix : stack1), depth0));
},"88":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.tags : stack1),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
-},"90":function(container,depth0,helpers,partials,data) {
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(89, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"89":function(container,depth0,helpers,partials,data) {
var stack1;
- return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(91, data, 0),"inverse":container.program(93, data, 0),"data":data})) != null ? stack1 : "");
+ return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.body : stack1), depth0));
},"91":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1),{"name":"if","hash":{},"fn":container.program(92, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"92":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return container.escapeExpression(container.lambda(((stack1 = ((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.cloze : stack1)) != null ? stack1.suffix : stack1), depth0));
+},"94":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return ((stack1 = helpers.each.call(depth0 != null ? depth0 : (container.nullContext || {}),((stack1 = (depth0 != null ? depth0.definition : depth0)) != null ? stack1.tags : stack1),{"name":"each","hash":{},"fn":container.program(5, data, 0),"inverse":container.noop,"data":data})) != null ? stack1 : "");
+},"96":function(container,depth0,helpers,partials,data) {
+ var stack1;
+
+ return ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.html : depth0),{"name":"if","hash":{},"fn":container.program(97, data, 0),"inverse":container.program(99, data, 0),"data":data})) != null ? stack1 : "");
+},"97":function(container,depth0,helpers,partials,data) {
var stack1, alias1=container.lambda, alias2=container.escapeExpression;
return "No results found.
\n";
+ return "No results found.
\r\n";
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
- return "\n"
+ return "\r\n"
+ ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(21, data, 0, blockParams, depths),"inverse":container.program(25, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
@@ -435,19 +454,19 @@ templates['kanji.html'] = template({"1":function(container,depth0,helpers,partia
templates['model.html'] = template({"1":function(container,depth0,helpers,partials,data) {
return " No results found.
\n";
+ return "No results found.
\r\n";
},"compiler":[7,">= 4.0.0"],"main":function(container,depth0,helpers,partials,data,blockParams,depths) {
var stack1;
- return "\n\n"
+ return "\r\n\r\n"
+ ((stack1 = helpers["if"].call(depth0 != null ? depth0 : (container.nullContext || {}),(depth0 != null ? depth0.definitions : depth0),{"name":"if","hash":{},"fn":container.program(37, data, 0, blockParams, depths),"inverse":container.program(41, data, 0, blockParams, depths),"data":data})) != null ? stack1 : "");
},"main_d": function(fn, props, container, depth0, data, blockParams, depths) {
diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js
index 1be485c7..daed3109 100644
--- a/ext/bg/js/translator.js
+++ b/ext/bg/js/translator.js
@@ -71,7 +71,8 @@ class Translator {
expression: definition.expression,
reading: definition.reading,
glossary: definition.glossary,
- tags: dictTagsSort(tags)
+ tags: dictTagsSort(tags),
+ furigana: distributeFurigana(definition.expression, definition.reading)
});
}
}
diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js
index c11e955b..a8f72059 100644
--- a/ext/mixed/js/japanese.js
+++ b/ext/mixed/js/japanese.js
@@ -38,3 +38,81 @@ function jpKatakanaToHiragana(text) {
return result;
}
+
+function distributeFurigana(word, reading) {
+ reading = reading || wanakana.toHiragana(word);
+ function span(str, pred) {
+ let i = 0;
+ while (i < str.length && pred(str[i])) {
+ i++;
+ }
+ return [str.substring(0, i), str.substring(i)];
+ }
+ const isKanji = c => jpIsKanji(c) ||
+ c == "\u3005"; /* kurikaeshi */
+ const isKana = c => jpIsKana(c) ||
+ c == "\u30fc"; /* chouonpu */
+ function parse(word) {
+ const res = [];
+ while (word.length > 0) {
+ const c = word.charAt(0);
+ if (isKana(c)) {
+ const [text, rest] = span(word, isKana);
+ res.push({ type: "kana", text });
+ word = rest;
+ } else if (isKanji(c)) {
+ const [text, rest] = span(word, isKanji);
+ res.push({ type: "kanji", text });
+ word = rest;
+ } else return null;
+ }
+ return res;
+ }
+
+ let fallback = () => [{ text: word, furigana: reading }];
+ let parts = parse(word);
+ if (parts == null) return fallback();
+ let parti = 0;
+ let readingi = 0;
+ let res = [];
+ let current = null;
+ function backtrack() {
+ parti--;
+ const prev = res.pop();
+ current = prev.furigana;
+ }
+ while (parti < parts.length) {
+ const part = parts[parti];
+ switch (part.type) {
+ case 'kana':
+ if (reading.startsWith(wanakana.toHiragana(part.text), readingi)) {
+ if (parti == parts.length - 1 && readingi != reading.length - part.text.length) {
+ backtrack();
+ } else {
+ readingi += part.text.length;
+ res.push({ text: part.text });
+ parti++;
+ }
+ } else backtrack();
+ break;
+ case "kanji":
+ current = current || "";
+ if (parti == parts.length - 1) {
+ // last part, consume all
+ current += reading.substring(readingi);
+ } else {
+ const nextText = parts[parti + 1].text;
+ let end = reading.indexOf(nextText, readingi + 1); // consume at least one character
+ if (end == -1) {
+ return fallback();
+ }
+ current += reading.substring(readingi, end);
+ readingi = end;
+ }
+ res.push({ text: part.text, furigana: current });
+ current = null;
+ parti++;
+ }
+ }
+ return res;
+}
diff --git a/tmpl/fields.html b/tmpl/fields.html
index 944a43e6..8bd94dc0 100644
--- a/tmpl/fields.html
+++ b/tmpl/fields.html
@@ -44,9 +44,19 @@
{{#*inline "furigana"}}
{{~#if html~}}
- {{~#if definition.reading}}