aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/css/display-pronunciation.css6
-rw-r--r--ext/js/display/pronunciation-generator.js25
-rw-r--r--ext/js/language/japanese-util.js20
3 files changed, 44 insertions, 7 deletions
diff --git a/ext/css/display-pronunciation.css b/ext/css/display-pronunciation.css
index 4ea15baf..e26c5952 100644
--- a/ext/css/display-pronunciation.css
+++ b/ext/css/display-pronunciation.css
@@ -77,6 +77,12 @@
box-sizing: border-box;
z-index: 1;
}
+.pitch-accent-character-nasal-diacritic {
+ position: absolute;
+ width: 0;
+ height: 0;
+ opacity: 0;
+}
.pitch-accent-position::before {
content: ' [';
diff --git a/ext/js/display/pronunciation-generator.js b/ext/js/display/pronunciation-generator.js
index eb5eb035..13e3db3e 100644
--- a/ext/js/display/pronunciation-generator.js
+++ b/ext/js/display/pronunciation-generator.js
@@ -35,16 +35,14 @@ class PronunciationGenerator {
const n1 = document.createElement('span');
n1.className = 'pitch-accent-character';
-
- const n2 = document.createElement('span');
- n2.className = 'pitch-accent-character-inner';
-
- n1.appendChild(n2);
-
n1.dataset.position = `${i}`;
n1.dataset.pitch = highPitch ? 'high' : 'low';
n1.dataset.pitchNext = highPitchNext ? 'high' : 'low';
+
+ const n2 = document.createElement('span');
+ n2.className = 'pitch-accent-character-inner';
n2.textContent = mora;
+ n1.appendChild(n2);
if (devoice) {
n1.dataset.devoice = 'true';
@@ -54,7 +52,13 @@ class PronunciationGenerator {
}
if (nasal) {
n1.dataset.nasal = 'true';
- const n3 = document.createElement('span');
+ n1.dataset.originalText = mora;
+ n2.textContent = this._getPlainMora(mora);
+ let n3 = document.createElement('span');
+ n3.className = 'pitch-accent-character-nasal-diacritic';
+ n3.textContent = '\u309a'; // Combining handakuten
+ n1.appendChild(n3);
+ n3 = document.createElement('span');
n3.className = 'pitch-accent-character-nasal-indicator';
n1.appendChild(n3);
}
@@ -142,4 +146,11 @@ class PronunciationGenerator {
node.setAttribute('r', radius);
return node;
}
+
+ _getPlainMora(mora) {
+ const first = mora[0];
+ const info = this._japaneseUtil.getKanaDiacriticInfo(first);
+ if (info === null) { return mora; }
+ return `${info.character}${mora.substring(1)}`;
+ }
}
diff --git a/ext/js/language/japanese-util.js b/ext/js/language/japanese-util.js
index 9d7ad0d8..c7f79751 100644
--- a/ext/js/language/japanese-util.js
+++ b/ext/js/language/japanese-util.js
@@ -154,6 +154,21 @@ const JapaneseUtil = (() => {
return map;
})();
+ const DIACRITIC_MAPPING = (() => {
+ const kana = 'うゔ-かが-きぎ-くぐ-けげ-こご-さざ-しじ-すず-せぜ-そぞ-ただ-ちぢ-つづ-てで-とど-はばぱひびぴふぶぷへべぺほぼぽワヷ-ヰヸ-ウヴ-ヱヹ-ヲヺ-カガ-キギ-クグ-ケゲ-コゴ-サザ-シジ-スズ-セゼ-ソゾ-タダ-チヂ-ツヅ-テデ-トド-ハバパヒビピフブプヘベペホボポ';
+ const map = new Map();
+ for (let i = 0, ii = kana.length; i < ii; i += 3) {
+ const character = kana[i];
+ const dakuten = kana[i + 1];
+ const handakuten = kana[i + 2];
+ map.set(dakuten, {character, type: 'dakuten'});
+ if (handakuten !== '-') {
+ map.set(handakuten, {character, type: 'handakuten'});
+ }
+ }
+ return map;
+ })();
+
function isCodePointInRange(codePoint, [min, max]) {
return (codePoint >= min && codePoint <= max);
@@ -417,6 +432,11 @@ const JapaneseUtil = (() => {
return this._wanakana !== null;
}
+ getKanaDiacriticInfo(character) {
+ const info = DIACRITIC_MAPPING.get(character);
+ return typeof info !== 'undefined' ? {character: info.character, type: info.type} : null;
+ }
+
// Furigana distribution
distributeFurigana(term, reading) {