diff options
Diffstat (limited to 'ext/bg/js')
| -rw-r--r-- | ext/bg/js/handlebars.js | 2 | ||||
| -rw-r--r-- | ext/bg/js/options.js | 8 | ||||
| -rw-r--r-- | ext/bg/js/search.js | 2 | ||||
| -rw-r--r-- | ext/bg/js/settings/main.js | 12 | ||||
| -rw-r--r-- | ext/bg/js/translator.js | 138 | 
5 files changed, 131 insertions, 31 deletions
| diff --git a/ext/bg/js/handlebars.js b/ext/bg/js/handlebars.js index 6d1581be..62f89ee4 100644 --- a/ext/bg/js/handlebars.js +++ b/ext/bg/js/handlebars.js @@ -61,7 +61,7 @@ function handlebarsFuriganaPlain(options) {  function handlebarsKanjiLinks(options) {      let result = '';      for (const c of options.fn(this)) { -        if (jpIsKanji(c)) { +        if (jpIsCharCodeKanji(c.charCodeAt(0))) {              result += `<a href="#" class="kanji-link">${c}</a>`;          } else {              result += c; diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index c2da76b1..120b34af 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -319,6 +319,14 @@ function profileOptionsCreateDefaults() {              enableOnSearchPage: true          }, +        translation: { +            convertHalfWidthCharacters: 'false', +            convertNumericCharacters: 'false', +            convertAlphabeticCharacters: 'false', +            convertHiraganaToKatakana: 'false', +            convertKatakanaToHiragana: 'variant' +        }, +          dictionaries: {},          parsing: { diff --git a/ext/bg/js/search.js b/ext/bg/js/search.js index 673f066b..f5c641a8 100644 --- a/ext/bg/js/search.js +++ b/ext/bg/js/search.js @@ -265,7 +265,7 @@ class DisplaySearch extends Display {                  text !== this.clipboardPreviousText              ) {                  this.clipboardPreviousText = text; -                if (jpIsJapaneseText(text)) { +                if (jpIsStringPartiallyJapanese(text)) {                      this.setQuery(this.isWanakanaEnabled() ? window.wanakana.toKana(text) : text);                      window.history.pushState(null, '', `${window.location.pathname}?query=${encodeURIComponent(text)}`);                      this.onSearchQueryUpdated(this.query.value, true); diff --git a/ext/bg/js/settings/main.js b/ext/bg/js/settings/main.js index bed57f7d..b2ac82f9 100644 --- a/ext/bg/js/settings/main.js +++ b/ext/bg/js/settings/main.js @@ -72,6 +72,12 @@ async function formRead(options) {      options.scanning.modifier = $('#scan-modifier-key').val();      options.scanning.popupNestingMaxDepth = parseInt($('#popup-nesting-max-depth').val(), 10); +    options.translation.convertHalfWidthCharacters = $('#translation-convert-half-width-characters').val(); +    options.translation.convertNumericCharacters = $('#translation-convert-numeric-characters').val(); +    options.translation.convertAlphabeticCharacters = $('#translation-convert-alphabetic-characters').val(); +    options.translation.convertHiraganaToKatakana = $('#translation-convert-hiragana-to-katakana').val(); +    options.translation.convertKatakanaToHiragana = $('#translation-convert-katakana-to-hiragana').val(); +      options.parsing.enableScanningParser = $('#parsing-scan-enable').prop('checked');      options.parsing.enableMecabParser = $('#parsing-mecab-enable').prop('checked');      options.parsing.termSpacing = $('#parsing-term-spacing').prop('checked'); @@ -141,6 +147,12 @@ async function formWrite(options) {      $('#scan-modifier-key').val(options.scanning.modifier);      $('#popup-nesting-max-depth').val(options.scanning.popupNestingMaxDepth); +    $('#translation-convert-half-width-characters').val(options.translation.convertHalfWidthCharacters); +    $('#translation-convert-numeric-characters').val(options.translation.convertNumericCharacters); +    $('#translation-convert-alphabetic-characters').val(options.translation.convertAlphabeticCharacters); +    $('#translation-convert-hiragana-to-katakana').val(options.translation.convertHiraganaToKatakana); +    $('#translation-convert-katakana-to-hiragana').val(options.translation.convertKatakanaToHiragana); +      $('#parsing-scan-enable').prop('checked', options.parsing.enableScanningParser);      $('#parsing-mecab-enable').prop('checked', options.parsing.enableMecabParser);      $('#parsing-reading-mode').val(options.parsing.readingMode); diff --git a/ext/bg/js/translator.js b/ext/bg/js/translator.js index b6e9604d..0f89111f 100644 --- a/ext/bg/js/translator.js +++ b/ext/bg/js/translator.js @@ -151,7 +151,7 @@ class Translator {      async findTermsGrouped(text, details, options) {          const dictionaries = dictEnabledSet(options);          const titles = Object.keys(dictionaries); -        const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); +        const [definitions, length] = await this.findTermsInternal(text, dictionaries, details, options);          const definitionsGrouped = dictTermsGroup(definitions, dictionaries);          await this.buildTermFrequencies(definitionsGrouped, titles); @@ -169,7 +169,7 @@ class Translator {          const dictionaries = dictEnabledSet(options);          const secondarySearchTitles = Object.keys(options.dictionaries).filter((dict) => options.dictionaries[dict].allowSecondarySearches);          const titles = Object.keys(dictionaries); -        const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); +        const [definitions, length] = await this.findTermsInternal(text, dictionaries, details, options);          const {sequencedDefinitions, defaultDefinitions} = await this.getSequencedDefinitions(definitions, options.general.mainDictionary);          const definitionsMerged = [];          const mergedByTermIndices = new Set(); @@ -206,26 +206,24 @@ class Translator {      async findTermsSplit(text, details, options) {          const dictionaries = dictEnabledSet(options);          const titles = Object.keys(dictionaries); -        const [definitions, length] = await this.findTermsInternal(text, dictionaries, options.scanning.alphanumeric, details); +        const [definitions, length] = await this.findTermsInternal(text, dictionaries, details, options);          await this.buildTermFrequencies(definitions, titles);          return [definitions, length];      } -    async findTermsInternal(text, dictionaries, alphanumeric, details) { -        if (!alphanumeric && text.length > 0) { -            const c = text[0]; -            if (!jpIsKana(c) && !jpIsKanji(c)) { -                return [[], 0]; -            } +    async findTermsInternal(text, dictionaries, details, options) { +        text = Translator.getSearchableText(text, options); +        if (text.length === 0) { +            return [[], 0];          }          const titles = Object.keys(dictionaries);          const deinflections = (              details.wildcard ?              await this.findTermWildcard(text, titles, details.wildcard) : -            await this.findTermDeinflections(text, titles) +            await this.findTermDeinflections(text, titles, options)          );          let definitions = []; @@ -240,6 +238,7 @@ class Translator {                  definitions.push({                      source: deinflection.source, +                    rawSource: deinflection.rawSource,                      reasons: deinflection.reasons,                      score: definition.score,                      id: definition.id, @@ -260,7 +259,7 @@ class Translator {          let length = 0;          for (const definition of definitions) { -            length = Math.max(length, definition.source.length); +            length = Math.max(length, definition.rawSource.length);          }          return [definitions, length]; @@ -274,6 +273,7 @@ class Translator {          return [{              source: text, +            rawSource: text,              term: text,              rules: 0,              definitions, @@ -281,9 +281,8 @@ class Translator {          }];      } -    async findTermDeinflections(text, titles) { -        const text2 = jpKatakanaToHiragana(text); -        const deinflections = (text === text2 ? this.getDeinflections(text) : this.getDeinflections2(text, text2)); +    async findTermDeinflections(text, titles, options) { +        const deinflections = this.getAllDeinflections(text, options);          if (deinflections.length === 0) {              return []; @@ -321,30 +320,77 @@ class Translator {          return deinflections.filter((e) => e.definitions.length > 0);      } -    getDeinflections(text) { +    getAllDeinflections(text, options) { +        const translationOptions = options.translation; +        const textOptionVariantArray = [ +            Translator.getTextOptionEntryVariants(translationOptions.convertHalfWidthCharacters), +            Translator.getTextOptionEntryVariants(translationOptions.convertNumericCharacters), +            Translator.getTextOptionEntryVariants(translationOptions.convertAlphabeticCharacters), +            Translator.getTextOptionEntryVariants(translationOptions.convertHiraganaToKatakana), +            Translator.getTextOptionEntryVariants(translationOptions.convertKatakanaToHiragana) +        ]; +          const deinflections = []; +        const used = new Set(); +        for (const [halfWidth, numeric, alphabetic, katakana, hiragana] of Translator.getArrayVariants(textOptionVariantArray)) { +            let text2 = text; +            let sourceMapping = null; +            if (halfWidth) { +                if (sourceMapping === null) { sourceMapping = Translator.createTextSourceMapping(text2); } +                text2 = jpConvertHalfWidthKanaToFullWidth(text2, sourceMapping); +            } +            if (numeric) { +                text2 = jpConvertNumericTofullWidth(text2); +            } +            if (alphabetic) { +                if (sourceMapping === null) { sourceMapping = Translator.createTextSourceMapping(text2); } +                text2 = jpConvertAlphabeticToKana(text2, sourceMapping); +            } +            if (katakana) { +                text2 = jpHiraganaToKatakana(text2); +            } +            if (hiragana) { +                text2 = jpKatakanaToHiragana(text2); +            } -        for (let i = text.length; i > 0; --i) { -            const textSubstring = text.substring(0, i); -            deinflections.push(...this.deinflector.deinflect(textSubstring)); +            for (let i = text2.length; i > 0; --i) { +                const text2Substring = text2.substring(0, i); +                if (used.has(text2Substring)) { break; } +                used.add(text2Substring); +                for (const deinflection of this.deinflector.deinflect(text2Substring)) { +                    deinflection.rawSource = Translator.getDeinflectionRawSource(text, i, sourceMapping); +                    deinflections.push(deinflection); +                } +            }          } -          return deinflections;      } -    getDeinflections2(text1, text2) { -        const deinflections = []; +    static getTextOptionEntryVariants(value) { +        switch (value) { +            case 'true': return [true]; +            case 'variant': return [false, true]; +            default: return [false]; +        } +    } -        for (let i = text1.length; i > 0; --i) { -            const text1Substring = text1.substring(0, i); -            const text2Substring = text2.substring(0, i); -            deinflections.push(...this.deinflector.deinflect(text1Substring)); -            if (text1Substring !== text2Substring) { -                deinflections.push(...this.deinflector.deinflect(text2Substring)); -            } +    static getDeinflectionRawSource(source, length, sourceMapping) { +        if (sourceMapping === null) { +            return source.substring(0, length);          } -        return deinflections; +        let result = ''; +        let index = 0; +        for (let i = 0; i < length; ++i) { +            const c = sourceMapping[i]; +            result += source.substring(index, index + c); +            index += c; +        } +        return result; +    } + +    static createTextSourceMapping(text) { +        return new Array(text.length).fill(1);      }      async findKanji(text, options) { @@ -527,4 +573,38 @@ class Translator {          const pos = name.indexOf(':');          return (pos >= 0 ? name.substring(0, pos) : name);      } + +    static *getArrayVariants(arrayVariants) { +        const ii = arrayVariants.length; + +        let total = 1; +        for (let i = 0; i < ii; ++i) { +            total *= arrayVariants[i].length; +        } + +        for (let a = 0; a < total; ++a) { +            const variant = []; +            let index = a; +            for (let i = 0; i < ii; ++i) { +                const entryVariants = arrayVariants[i]; +                variant.push(entryVariants[index % entryVariants.length]); +                index = Math.floor(index / entryVariants.length); +            } +            yield variant; +        } +    } + +    static getSearchableText(text, options) { +        if (!options.scanning.alphanumeric) { +            const ii = text.length; +            for (let i = 0; i < ii; ++i) { +                if (!jpIsCharCodeJapanese(text.charCodeAt(i))) { +                    text = text.substring(0, i); +                    break; +                } +            } +        } + +        return text; +    }  } |