diff options
| -rw-r--r-- | ext/mixed/js/display-generator.js | 38 | ||||
| -rw-r--r-- | ext/mixed/js/japanese.js | 26 | ||||
| -rw-r--r-- | test/test-japanese.js | 55 | 
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();  } |