JapaneseUtil normalization (#1076)

* Use JapaneseUtil as a class which is manually instantiated

* Use alias function for toKana
This commit is contained in:
toasted-nutbread 2020-11-29 13:09:02 -05:00 committed by GitHub
parent a8cd03cbec
commit 34451ebf71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 72 additions and 48 deletions

View File

@ -17,11 +17,11 @@
/* global /* global
* SimpleDOMParser * SimpleDOMParser
* jp
*/ */
class AudioDownloader { class AudioDownloader {
constructor({requestBuilder}) { constructor({japaneseUtil, requestBuilder}) {
this._japaneseUtil = japaneseUtil;
this._requestBuilder = requestBuilder; this._requestBuilder = requestBuilder;
this._getInfoHandlers = new Map([ this._getInfoHandlers = new Map([
['jpod101', this._getInfoJpod101.bind(this)], ['jpod101', this._getInfoJpod101.bind(this)],
@ -89,7 +89,7 @@ class AudioDownloader {
let kana = reading; let kana = reading;
let kanji = expression; let kanji = expression;
if (!kana && jp.isStringEntirelyKana(kanji)) { if (!kana && this._japaneseUtil.isStringEntirelyKana(kanji)) {
kana = kanji; kana = kanji;
kanji = null; kanji = null;
} }

View File

@ -22,6 +22,7 @@
* ClipboardReader * ClipboardReader
* DictionaryDatabase * DictionaryDatabase
* Environment * Environment
* JapaneseUtil
* JsonSchemaValidator * JsonSchemaValidator
* Mecab * Mecab
* MediaUtility * MediaUtility
@ -30,14 +31,18 @@
* ProfileConditions * ProfileConditions
* RequestBuilder * RequestBuilder
* Translator * Translator
* jp * wanakana
*/ */
class Backend { class Backend {
constructor() { constructor() {
this._japaneseUtil = new JapaneseUtil(wanakana);
this._environment = new Environment(); this._environment = new Environment();
this._dictionaryDatabase = new DictionaryDatabase(); this._dictionaryDatabase = new DictionaryDatabase();
this._translator = new Translator(this._dictionaryDatabase); this._translator = new Translator({
japaneseUtil: this._japaneseUtil,
database: this._dictionaryDatabase
});
this._anki = new AnkiConnect(); this._anki = new AnkiConnect();
this._mecab = new Mecab(); this._mecab = new Mecab();
this._mediaUtility = new MediaUtility(); this._mediaUtility = new MediaUtility();
@ -48,6 +53,7 @@ class Backend {
mediaUtility: this._mediaUtility mediaUtility: this._mediaUtility
}); });
this._clipboardMonitor = new ClipboardMonitor({ this._clipboardMonitor = new ClipboardMonitor({
japaneseUtil: this._japaneseUtil,
clipboardReader: this._clipboardReader clipboardReader: this._clipboardReader
}); });
this._options = null; this._options = null;
@ -57,6 +63,7 @@ class Backend {
this._defaultAnkiFieldTemplates = null; this._defaultAnkiFieldTemplates = null;
this._requestBuilder = new RequestBuilder(); this._requestBuilder = new RequestBuilder();
this._audioDownloader = new AudioDownloader({ this._audioDownloader = new AudioDownloader({
japaneseUtil: this._japaneseUtil,
requestBuilder: this._requestBuilder requestBuilder: this._requestBuilder
}); });
this._optionsUtil = new OptionsUtil(); this._optionsUtil = new OptionsUtil();
@ -952,6 +959,7 @@ class Backend {
} }
async _textParseScanning(text, options) { async _textParseScanning(text, options) {
const jp = this._japaneseUtil;
const {scanning: {length: scanningLength}, parsing: {readingMode}} = options; const {scanning: {length: scanningLength}, parsing: {readingMode}} = options;
const findTermsOptions = this._getTranslatorFindTermsOptions({wildcard: null}, options); const findTermsOptions = this._getTranslatorFindTermsOptions({wildcard: null}, options);
const results = []; const results = [];
@ -981,6 +989,7 @@ class Backend {
} }
async _textParseMecab(text, options) { async _textParseMecab(text, options) {
const jp = this._japaneseUtil;
const {parsing: {readingMode}} = options; const {parsing: {readingMode}} = options;
const results = []; const results = [];
const rawResults = await this._mecab.parseText(text); const rawResults = await this._mecab.parseText(text);

View File

@ -15,18 +15,15 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
/* global
* jp
*/
class ClipboardMonitor extends EventDispatcher { class ClipboardMonitor extends EventDispatcher {
constructor({clipboardReader}) { constructor({japaneseUtil, clipboardReader}) {
super(); super();
this._japaneseUtil = japaneseUtil;
this._clipboardReader = clipboardReader;
this._timerId = null; this._timerId = null;
this._timerToken = null; this._timerToken = null;
this._interval = 250; this._interval = 250;
this._previousText = null; this._previousText = null;
this._clipboardReader = clipboardReader;
} }
start() { start() {
@ -53,7 +50,7 @@ class ClipboardMonitor extends EventDispatcher {
text !== this._previousText text !== this._previousText
) { ) {
this._previousText = text; this._previousText = text;
if (jp.isStringPartiallyJapanese(text)) { if (this._japaneseUtil.isStringPartiallyJapanese(text)) {
this.trigger('change', {text}); this.trigger('change', {text});
} }
} }

View File

@ -17,7 +17,9 @@
/* global /* global
* DisplaySearch * DisplaySearch
* JapaneseUtil
* api * api
* wanakana
*/ */
(async () => { (async () => {
@ -25,7 +27,8 @@
api.forwardLogsToBackend(); api.forwardLogsToBackend();
await yomichan.backendReady(); await yomichan.backendReady();
const displaySearch = new DisplaySearch(); const japaneseUtil = new JapaneseUtil(wanakana);
const displaySearch = new DisplaySearch(japaneseUtil);
await displaySearch.prepare(); await displaySearch.prepare();
document.documentElement.dataset.loaded = 'true'; document.documentElement.dataset.loaded = 'true';

View File

@ -24,8 +24,8 @@
*/ */
class DisplaySearch extends Display { class DisplaySearch extends Display {
constructor() { constructor(japaneseUtil) {
super('search'); super('search', japaneseUtil);
this._searchButton = document.querySelector('#search-button'); this._searchButton = document.querySelector('#search-button');
this._queryInput = document.querySelector('#search-textbox'); this._queryInput = document.querySelector('#search-textbox');
this._introElement = document.querySelector('#intro'); this._introElement = document.querySelector('#intro');
@ -38,6 +38,7 @@ class DisplaySearch extends Display {
this._introAnimationTimer = null; this._introAnimationTimer = null;
this._clipboardMonitorEnabled = false; this._clipboardMonitorEnabled = false;
this._clipboardMonitor = new ClipboardMonitor({ this._clipboardMonitor = new ClipboardMonitor({
japaneseUtil,
clipboardReader: { clipboardReader: {
getText: async () => (await api.clipboardGet()) getText: async () => (await api.clipboardGet())
} }
@ -129,7 +130,7 @@ class DisplaySearch extends Display {
postProcessQuery(query) { postProcessQuery(query) {
if (this._wanakanaEnabled) { if (this._wanakanaEnabled) {
try { try {
query = wanakana.toKana(query); query = this._japaneseUtil.convertToKana(query);
} catch (e) { } catch (e) {
// NOP // NOP
} }

View File

@ -21,7 +21,10 @@
(async () => { (async () => {
try { try {
const displayGenerator = new DisplayGenerator({mediaLoader: null}); const displayGenerator = new DisplayGenerator({
japaneseUtil: null,
mediaLoader: null
});
await displayGenerator.prepare(); await displayGenerator.prepare();
displayGenerator.preparePitchAccents(); displayGenerator.preparePitchAccents();
} catch (e) { } catch (e) {

View File

@ -16,12 +16,14 @@
*/ */
/* globals /* globals
* JapaneseUtil
* TemplateRenderer * TemplateRenderer
* TemplateRendererFrameApi * TemplateRendererFrameApi
*/ */
(() => { (() => {
const templateRenderer = new TemplateRenderer(); const japaneseUtil = new JapaneseUtil(null);
const templateRenderer = new TemplateRenderer(japaneseUtil);
const api = new TemplateRendererFrameApi(templateRenderer); const api = new TemplateRendererFrameApi(templateRenderer);
api.prepare(); api.prepare();
})(); })();

View File

@ -17,11 +17,11 @@
/* global /* global
* Handlebars * Handlebars
* jp
*/ */
class TemplateRenderer { class TemplateRenderer {
constructor() { constructor(japaneseUtil) {
this._japaneseUtil = japaneseUtil;
this._cache = new Map(); this._cache = new Map();
this._cacheMaxSize = 5; this._cacheMaxSize = 5;
this._helpersRegistered = false; this._helpersRegistered = false;
@ -119,7 +119,7 @@ class TemplateRenderer {
_furigana(context, ...args) { _furigana(context, ...args) {
const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args); const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args);
const segs = jp.distributeFurigana(expression, reading); const segs = this._japaneseUtil.distributeFurigana(expression, reading);
let result = ''; let result = '';
for (const seg of segs) { for (const seg of segs) {
@ -135,7 +135,7 @@ class TemplateRenderer {
_furiganaPlain(context, ...args) { _furiganaPlain(context, ...args) {
const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args); const {expression, reading} = this._getFuriganaExpressionAndReading(context, ...args);
const segs = jp.distributeFurigana(expression, reading); const segs = this._japaneseUtil.distributeFurigana(expression, reading);
let result = ''; let result = '';
for (const seg of segs) { for (const seg of segs) {
@ -161,6 +161,7 @@ class TemplateRenderer {
} }
_kanjiLinks(context, options) { _kanjiLinks(context, options) {
const jp = this._japaneseUtil;
let result = ''; let result = '';
for (const c of options.fn(context)) { for (const c of options.fn(context)) {
if (jp.isCodePointKanji(c.codePointAt(0))) { if (jp.isCodePointKanji(c.codePointAt(0))) {
@ -385,10 +386,10 @@ class TemplateRenderer {
} }
_isMoraPitchHigh(context, index, position) { _isMoraPitchHigh(context, index, position) {
return jp.isMoraPitchHigh(index, position); return this._japaneseUtil.isMoraPitchHigh(index, position);
} }
_getKanaMorae(context, text) { _getKanaMorae(context, text) {
return jp.getKanaMorae(`${text}`); return this._japaneseUtil.getKanaMorae(`${text}`);
} }
} }

View File

@ -18,7 +18,6 @@
/* global /* global
* Deinflector * Deinflector
* TextSourceMap * TextSourceMap
* jp
*/ */
/** /**
@ -29,7 +28,8 @@ class Translator {
* Creates a new Translator instance. * Creates a new Translator instance.
* @param database An instance of DictionaryDatabase. * @param database An instance of DictionaryDatabase.
*/ */
constructor(database) { constructor({japaneseUtil, database}) {
this._japaneseUtil = japaneseUtil;
this._database = database; this._database = database;
this._deinflector = null; this._deinflector = null;
this._tagCache = new Map(); this._tagCache = new Map();
@ -318,6 +318,7 @@ class Translator {
collapseEmphaticOptions collapseEmphaticOptions
]; ];
const jp = this._japaneseUtil;
const deinflections = []; const deinflections = [];
const used = new Set(); const used = new Set();
for (const [halfWidth, numeric, alphabetic, katakana, hiragana, [collapseEmphatic, collapseEmphaticFull]] of this._getArrayVariants(textOptionVariantArray)) { for (const [halfWidth, numeric, alphabetic, katakana, hiragana, [collapseEmphatic, collapseEmphaticFull]] of this._getArrayVariants(textOptionVariantArray)) {
@ -846,6 +847,7 @@ class Translator {
return text; return text;
} }
const jp = this._japaneseUtil;
let newText = ''; let newText = '';
for (const c of text) { for (const c of text) {
if (!jp.isCodePointJapanese(c.codePointAt(0))) { if (!jp.isCodePointJapanese(c.codePointAt(0))) {
@ -1031,7 +1033,7 @@ class Translator {
this._sortTags(definitionTagsExpanded); this._sortTags(definitionTagsExpanded);
this._sortTags(termTagsExpanded); this._sortTags(termTagsExpanded);
const furiganaSegments = jp.distributeFurigana(expression, reading); const furiganaSegments = this._japaneseUtil.distributeFurigana(expression, reading);
const termDetailsList = [this._createTermDetails(sourceTerm, expression, reading, furiganaSegments, termTagsExpanded)]; const termDetailsList = [this._createTermDetails(sourceTerm, expression, reading, furiganaSegments, termTagsExpanded)];
const sourceTermExactMatchCount = (sourceTerm === expression ? 1 : 0); const sourceTermExactMatchCount = (sourceTerm === expression ? 1 : 0);

View File

@ -17,6 +17,7 @@
/* global /* global
* Display * Display
* JapaneseUtil
* api * api
*/ */
@ -25,7 +26,8 @@
api.forwardLogsToBackend(); api.forwardLogsToBackend();
await yomichan.backendReady(); await yomichan.backendReady();
const display = new Display('popup'); const japaneseUtil = new JapaneseUtil(null);
const display = new Display('popup', japaneseUtil);
await display.prepare(); await display.prepare();
display.initializeState(); display.initializeState();

View File

@ -19,11 +19,11 @@
* DictionaryDataUtil * DictionaryDataUtil
* HtmlTemplateCollection * HtmlTemplateCollection
* api * api
* jp
*/ */
class DisplayGenerator { class DisplayGenerator {
constructor({mediaLoader}) { constructor({japaneseUtil, mediaLoader}) {
this._japaneseUtil = japaneseUtil;
this._mediaLoader = mediaLoader; this._mediaLoader = mediaLoader;
this._templates = null; this._templates = null;
this._termPitchAccentStaticTemplateIsSetup = false; this._termPitchAccentStaticTemplateIsSetup = false;
@ -354,6 +354,7 @@ class DisplayGenerator {
} }
_createPitch(details) { _createPitch(details) {
const jp = this._japaneseUtil;
const {reading, position, tags, exclusiveExpressions, exclusiveReadings} = details; const {reading, position, tags, exclusiveExpressions, exclusiveReadings} = details;
const morae = jp.getKanaMorae(reading); const morae = jp.getKanaMorae(reading);
@ -417,6 +418,7 @@ class DisplayGenerator {
} }
_populatePitchGraph(svg, position, morae) { _populatePitchGraph(svg, position, morae) {
const jp = this._japaneseUtil;
const svgns = svg.getAttribute('xmlns'); const svgns = svg.getAttribute('xmlns');
const ii = morae.length; const ii = morae.length;
svg.setAttribute('viewBox', `0 0 ${50 * (ii + 1)} 100`); svg.setAttribute('viewBox', `0 0 ${50 * (ii + 1)} 100`);
@ -475,6 +477,7 @@ class DisplayGenerator {
} }
_appendKanjiLinks(container, text) { _appendKanjiLinks(container, text) {
const jp = this._japaneseUtil;
let part = ''; let part = '';
for (const c of text) { for (const c of text) {
if (jp.isCodePointKanji(c.codePointAt(0))) { if (jp.isCodePointKanji(c.codePointAt(0))) {

View File

@ -34,9 +34,10 @@
*/ */
class Display extends EventDispatcher { class Display extends EventDispatcher {
constructor(pageType) { constructor(pageType, japaneseUtil) {
super(); super();
this._pageType = pageType; this._pageType = pageType;
this._japaneseUtil = japaneseUtil;
this._container = document.querySelector('#definitions'); this._container = document.querySelector('#definitions');
this._definitions = []; this._definitions = [];
this._optionsContext = {depth: 0, url: window.location.href}; this._optionsContext = {depth: 0, url: window.location.href};
@ -53,7 +54,10 @@ class Display extends EventDispatcher {
this._autoPlayAudioTimer = null; this._autoPlayAudioTimer = null;
this._autoPlayAudioDelay = 400; this._autoPlayAudioDelay = 400;
this._mediaLoader = new MediaLoader(); this._mediaLoader = new MediaLoader();
this._displayGenerator = new DisplayGenerator({mediaLoader: this._mediaLoader}); this._displayGenerator = new DisplayGenerator({
japaneseUtil,
mediaLoader: this._mediaLoader
});
this._hotkeys = new Map(); this._hotkeys = new Map();
this._actions = new Map(); this._actions = new Map();
this._messageHandlers = new Map(); this._messageHandlers = new Map();
@ -177,6 +181,10 @@ class Display extends EventDispatcher {
return this._mode; return this._mode;
} }
get japaneseUtil() {
return this._japaneseUtil;
}
async prepare() { async prepare() {
// State setup // State setup
const {documentElement} = document; const {documentElement} = document;

View File

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
const jp = (() => { const JapaneseUtil = (() => {
const ITERATION_MARK_CODE_POINT = 0x3005; const ITERATION_MARK_CODE_POINT = 0x3005;
const HIRAGANA_SMALL_TSU_CODE_POINT = 0x3063; const HIRAGANA_SMALL_TSU_CODE_POINT = 0x3063;
const KATAKANA_SMALL_TSU_CODE_POINT = 0x30c3; const KATAKANA_SMALL_TSU_CODE_POINT = 0x30c3;
@ -179,19 +179,8 @@ const jp = (() => {
} }
} }
function getWanakana() {
try {
if (typeof wanakana !== 'undefined') {
// eslint-disable-next-line no-undef
return wanakana;
}
} catch (e) {
// NOP
}
return null;
}
// eslint-disable-next-line no-shadow
class JapaneseUtil { class JapaneseUtil {
constructor(wanakana=null) { constructor(wanakana=null) {
this._wanakana = wanakana; this._wanakana = wanakana;
@ -258,6 +247,10 @@ const jp = (() => {
// Conversion functions // Conversion functions
convertToKana(text) {
return this._getWanakana().toKana(text);
}
convertKatakanaToHiragana(text) { convertKatakanaToHiragana(text) {
let result = ''; let result = '';
const offset = (HIRAGANA_CONVERSION_RANGE[0] - KATAKANA_CONVERSION_RANGE[0]); const offset = (HIRAGANA_CONVERSION_RANGE[0] - KATAKANA_CONVERSION_RANGE[0]);
@ -591,5 +584,5 @@ const jp = (() => {
} }
return new JapaneseUtil(getWanakana()); return JapaneseUtil;
})(); })();

View File

@ -25,8 +25,8 @@ vm.execute([
'mixed/js/japanese.js', 'mixed/js/japanese.js',
'bg/js/text-source-map.js' 'bg/js/text-source-map.js'
]); ]);
const jp = vm.get('jp'); const [JapaneseUtil, TextSourceMap, wanakana] = vm.get(['JapaneseUtil', 'TextSourceMap', 'wanakana']);
const TextSourceMap = vm.get('TextSourceMap'); const jp = new JapaneseUtil(wanakana);
function testIsCodePointKanji() { function testIsCodePointKanji() {