Move Japanese utility functions out of display-generator.js
This commit is contained in:
parent
cbc7e2646d
commit
0d80fcdf86
@ -305,7 +305,7 @@ class DisplayGenerator {
|
|||||||
|
|
||||||
createPitch(details) {
|
createPitch(details) {
|
||||||
const {expressions, reading, position, tags} = 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');
|
const node = this._templateHandler.instantiate('term-pitch-accent');
|
||||||
|
|
||||||
@ -324,8 +324,8 @@ class DisplayGenerator {
|
|||||||
n = node.querySelector('.term-pitch-accent-characters');
|
n = node.querySelector('.term-pitch-accent-characters');
|
||||||
for (let i = 0, ii = morae.length; i < ii; ++i) {
|
for (let i = 0, ii = morae.length; i < ii; ++i) {
|
||||||
const mora = morae[i];
|
const mora = morae[i];
|
||||||
const highPitch = DisplayGenerator._jpIsMoraPitchHigh(i, position);
|
const highPitch = jp.isMoraPitchHigh(i, position);
|
||||||
const highPitchNext = DisplayGenerator._jpIsMoraPitchHigh(i + 1, position);
|
const highPitchNext = jp.isMoraPitchHigh(i + 1, position);
|
||||||
|
|
||||||
const n1 = this._templateHandler.instantiate('term-pitch-accent-character');
|
const n1 = this._templateHandler.instantiate('term-pitch-accent-character');
|
||||||
const n2 = n1.querySelector('.term-pitch-accent-character-inner');
|
const n2 = n1.querySelector('.term-pitch-accent-character-inner');
|
||||||
@ -358,8 +358,8 @@ class DisplayGenerator {
|
|||||||
|
|
||||||
const pathPoints = [];
|
const pathPoints = [];
|
||||||
for (let i = 0; i < ii; ++i) {
|
for (let i = 0; i < ii; ++i) {
|
||||||
const highPitch = DisplayGenerator._jpIsMoraPitchHigh(i, position);
|
const highPitch = jp.isMoraPitchHigh(i, position);
|
||||||
const highPitchNext = DisplayGenerator._jpIsMoraPitchHigh(i + 1, position);
|
const highPitchNext = jp.isMoraPitchHigh(i + 1, position);
|
||||||
const graphic = (highPitch && !highPitchNext ? '#term-pitch-accent-graph-dot-downstep' : '#term-pitch-accent-graph-dot');
|
const graphic = (highPitch && !highPitchNext ? '#term-pitch-accent-graph-dot-downstep' : '#term-pitch-accent-graph-dot');
|
||||||
const x = `${i * 50 + 25}`;
|
const x = `${i * 50 + 25}`;
|
||||||
const y = highPitch ? '25' : '75';
|
const y = highPitch ? '25' : '75';
|
||||||
@ -376,7 +376,7 @@ class DisplayGenerator {
|
|||||||
|
|
||||||
pathPoints.splice(0, ii - 1);
|
pathPoints.splice(0, ii - 1);
|
||||||
{
|
{
|
||||||
const highPitch = DisplayGenerator._jpIsMoraPitchHigh(ii, position);
|
const highPitch = jp.isMoraPitchHigh(ii, position);
|
||||||
const x = `${ii * 50 + 25}`;
|
const x = `${ii * 50 + 25}`;
|
||||||
const y = highPitch ? '25' : '75';
|
const y = highPitch ? '25' : '75';
|
||||||
const use = document.createElementNS(svgns, 'use');
|
const use = document.createElementNS(svgns, 'use');
|
||||||
@ -532,30 +532,4 @@ class DisplayGenerator {
|
|||||||
|
|
||||||
return true;
|
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();
|
|
||||||
|
@ -64,6 +64,8 @@ const jp = (() => {
|
|||||||
[0xffe0, 0xffee] // Currency markers
|
[0xffe0, 0xffee] // Currency markers
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const SMALL_KANA_SET = new Set(Array.from('ぁぃぅぇぉゃゅょゎァィゥェォャュョヮ'));
|
||||||
|
|
||||||
|
|
||||||
// Character code testing functions
|
// 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
|
// Exports
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -119,6 +141,8 @@ const jp = (() => {
|
|||||||
isCodePointKana,
|
isCodePointKana,
|
||||||
isCodePointJapanese,
|
isCodePointJapanese,
|
||||||
isStringEntirelyKana,
|
isStringEntirelyKana,
|
||||||
isStringPartiallyJapanese
|
isStringPartiallyJapanese,
|
||||||
|
isMoraPitchHigh,
|
||||||
|
getKanaMorae
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
@ -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() {
|
function main() {
|
||||||
testIsCodePointKanji();
|
testIsCodePointKanji();
|
||||||
@ -408,6 +461,8 @@ function main() {
|
|||||||
testConvertAlphabeticToKana();
|
testConvertAlphabeticToKana();
|
||||||
testDistributeFurigana();
|
testDistributeFurigana();
|
||||||
testDistributeFuriganaInflected();
|
testDistributeFuriganaInflected();
|
||||||
|
testIsMoraPitchHigh();
|
||||||
|
testGetKanaMorae();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user