summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-03-28 10:47:02 -0400
committertoasted-nutbread <toasted-nutbread@users.noreply.github.com>2020-03-28 10:47:02 -0400
commit0d80fcdf86745da133e4510eeea809a4eeafe120 (patch)
tree07c55c136223a8a1c913a0d2380ba3d1ee3c6665
parentcbc7e2646d2ce34f1aff7ca2b737fdb2db690c40 (diff)
Move Japanese utility functions out of display-generator.js
-rw-r--r--ext/mixed/js/display-generator.js38
-rw-r--r--ext/mixed/js/japanese.js26
-rw-r--r--test/test-japanese.js55
3 files changed, 86 insertions, 33 deletions
diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js
index 326f3f54..90361328 100644
--- a/ext/mixed/js/display-generator.js
+++ b/ext/mixed/js/display-generator.js
@@ -305,7 +305,7 @@ class DisplayGenerator {
createPitch(details) {
const {expressions, reading, position, tags} = details;
- const morae = DisplayGenerator._jpGetKanaMorae(reading);
+ const morae = jp.getKanaMorae(reading);
const node = this._templateHandler.instantiate('term-pitch-accent');
@@ -324,8 +324,8 @@ class DisplayGenerator {
n = node.querySelector('.term-pitch-accent-characters');
for (let i = 0, ii = morae.length; i < ii; ++i) {
const mora = morae[i];
- const highPitch = DisplayGenerator._jpIsMoraPitchHigh(i, position);
- const highPitchNext = DisplayGenerator._jpIsMoraPitchHigh(i + 1, position);
+ const highPitch = jp.isMoraPitchHigh(i, position);
+ const highPitchNext = jp.isMoraPitchHigh(i + 1, position);
const n1 = this._templateHandler.instantiate('term-pitch-accent-character');
const n2 = n1.querySelector('.term-pitch-accent-character-inner');
@@ -358,8 +358,8 @@ class DisplayGenerator {
const pathPoints = [];
for (let i = 0; i < ii; ++i) {
- const highPitch = DisplayGenerator._jpIsMoraPitchHigh(i, position);
- const highPitchNext = DisplayGenerator._jpIsMoraPitchHigh(i + 1, position);
+ const highPitch = jp.isMoraPitchHigh(i, position);
+ const highPitchNext = jp.isMoraPitchHigh(i + 1, position);
const graphic = (highPitch && !highPitchNext ? '#term-pitch-accent-graph-dot-downstep' : '#term-pitch-accent-graph-dot');
const x = `${i * 50 + 25}`;
const y = highPitch ? '25' : '75';
@@ -376,7 +376,7 @@ class DisplayGenerator {
pathPoints.splice(0, ii - 1);
{
- const highPitch = DisplayGenerator._jpIsMoraPitchHigh(ii, position);
+ const highPitch = jp.isMoraPitchHigh(ii, position);
const x = `${ii * 50 + 25}`;
const y = highPitch ? '25' : '75';
const use = document.createElementNS(svgns, 'use');
@@ -532,30 +532,4 @@ class DisplayGenerator {
return true;
}
-
- static _jpGetKanaMorae(text) {
- // This function splits Japanese kana reading into its individual mora
- // components. It is assumed that the text is well-formed.
- const smallKanaSet = DisplayGenerator._smallKanaSet;
- const morae = [];
- let i;
- for (const c of text) {
- if (smallKanaSet.has(c) && (i = morae.length) > 0) {
- morae[i - 1] += c;
- } else {
- morae.push(c);
- }
- }
- return morae;
- }
-
- static _jpCreateSmallKanaSet() {
- return new Set(Array.from('ぁぃぅぇぉゃゅょゎァィゥェォャュョヮ'));
- }
-
- static _jpIsMoraPitchHigh(moraIndex, pitchAccentPosition) {
- return pitchAccentPosition === 0 ? (moraIndex > 0) : (moraIndex < pitchAccentPosition);
- }
}
-
-DisplayGenerator._smallKanaSet = DisplayGenerator._jpCreateSmallKanaSet();
diff --git a/ext/mixed/js/japanese.js b/ext/mixed/js/japanese.js
index 61a247b2..e6b9a8a0 100644
--- a/ext/mixed/js/japanese.js
+++ b/ext/mixed/js/japanese.js
@@ -64,6 +64,8 @@ const jp = (() => {
[0xffe0, 0xffee] // Currency markers
];
+ const SMALL_KANA_SET = new Set(Array.from('ぁぃぅぇぉゃゅょゎァィゥェォャュョヮ'));
+
// Character code testing functions
@@ -112,6 +114,26 @@ const jp = (() => {
}
+ // Mora functions
+
+ function isMoraPitchHigh(moraIndex, pitchAccentPosition) {
+ return pitchAccentPosition === 0 ? (moraIndex > 0) : (moraIndex < pitchAccentPosition);
+ }
+
+ function getKanaMorae(text) {
+ const morae = [];
+ let i;
+ for (const c of text) {
+ if (SMALL_KANA_SET.has(c) && (i = morae.length) > 0) {
+ morae[i - 1] += c;
+ } else {
+ morae.push(c);
+ }
+ }
+ return morae;
+ }
+
+
// Exports
return {
@@ -119,6 +141,8 @@ const jp = (() => {
isCodePointKana,
isCodePointJapanese,
isStringEntirelyKana,
- isStringPartiallyJapanese
+ isStringPartiallyJapanese,
+ isMoraPitchHigh,
+ getKanaMorae
};
})();
diff --git a/test/test-japanese.js b/test/test-japanese.js
index c5d220e7..eab632bf 100644
--- a/test/test-japanese.js
+++ b/test/test-japanese.js
@@ -392,6 +392,59 @@ function testDistributeFuriganaInflected() {
}
}
+function testIsMoraPitchHigh() {
+ const data = [
+ [[0, 0], false],
+ [[1, 0], true],
+ [[2, 0], true],
+ [[3, 0], true],
+
+ [[0, 1], true],
+ [[1, 1], false],
+ [[2, 1], false],
+ [[3, 1], false],
+
+ [[0, 2], true],
+ [[1, 2], true],
+ [[2, 2], false],
+ [[3, 2], false],
+
+ [[0, 3], true],
+ [[1, 3], true],
+ [[2, 3], true],
+ [[3, 3], false],
+
+ [[0, 4], true],
+ [[1, 4], true],
+ [[2, 4], true],
+ [[3, 4], true]
+ ];
+
+ for (const [[moraIndex, pitchAccentPosition], expected] of data) {
+ const actual = jp.isMoraPitchHigh(moraIndex, pitchAccentPosition);
+ assert.strictEqual(actual, expected);
+ }
+}
+
+function testGetKanaMorae() {
+ const data = [
+ ['かこ', ['か', 'こ']],
+ ['かっこ', ['か', 'っ', 'こ']],
+ ['カコ', ['カ', 'コ']],
+ ['カッコ', ['カ', 'ッ', 'コ']],
+ ['コート', ['コ', 'ー', 'ト']],
+ ['ちゃんと', ['ちゃ', 'ん', 'と']],
+ ['とうきょう', ['と', 'う', 'きょ', 'う']],
+ ['ぎゅう', ['ぎゅ', 'う']],
+ ['ディスコ', ['ディ', 'ス', 'コ']]
+ ];
+
+ for (const [text, expected] of data) {
+ const actual = jp.getKanaMorae(text);
+ vm.assert.deepStrictEqual(actual, expected);
+ }
+}
+
function main() {
testIsCodePointKanji();
@@ -408,6 +461,8 @@ function main() {
testConvertAlphabeticToKana();
testDistributeFurigana();
testDistributeFuriganaInflected();
+ testIsMoraPitchHigh();
+ testGetKanaMorae();
}