Monday, January 30, 2023

Improvement to Chinese words separator's Parallel Text highlighting for Safari

Translated words that are split apart are now all highlighted

More details: https://www.anicehumble.com/2023/01/browsers-translation-mechanism.html

https://juejin.cn/post/7025868886914400293

Friday, January 27, 2023

Browsers translation mechanism

Safari can translate across tag boundaries. The phrase 先开发 (先 = first, 开发 = develop. in English is develop first), is split and the subject is placed between the the words that were split, i.e., develop something something here first



Chrome can only translate tag by tag. Each one of its translation is contained in the same tag the source language are contained in originally


Safari's advantage is that it can re-arrange the translation across tags, making the translation sound more natural than Chrome. Chinese words separator app highlighter granularity is by phrase, it stops at commas and periods, each phrase/sentence is contained in a tag

Chrome's advantage, though sounding unnatural English, is that you can get a feel of the grammar of Chinese language and how its sentence is structured


Chinese words separator for Safari

Chinese words separator for Chrome

Friday, July 1, 2022

Preventing accidental alert and console.log on production

Use this regular expression to find stray console.log and alert:
^[^\/]\s+console\.log
^[^\/]\s+alert

Saturday, June 11, 2022

Multiple nots is knotty to read

Simplifying multiple nots:
const isVariant = e.match(VARIANT_TESTER);
const matchingFirstHanzi = isVariant?.[2];
const matchingSecondHanzi = isVariant?.[4];

// knotty read:
// const needToShow
//     = !isVariant || (matchingFirstHanzi !== hanzi && matchingSecondHanzi !== hanzi);

// De-Morgan'd, easy to read:
// const needToHide = isVariant && (matchingFirstHanzi === hanzi || matchingSecondHanzi === hanzi);

const needToHide = isVariant && [matchingFirstHanzi, matchingSecondHanzi].includes(hanzi);
const needToShow = !needToHide;

Thursday, November 18, 2021

Horizontal scrollbar on textarea when text exceeds textarea's width

This works on Chrome:
white-space: nowrap;

However, the above does not work on Safari. In Safari, use this instead:
white-space: pre;
overflow-x: auto;
word-wrap: normal;

https://stackoverflow.com/questions/657795/how-to-remove-word-wrap-from-textarea/25556711#25556711

Sunday, November 14, 2021

Split keep function. Lookbehind, match, loop

Common code:
function escapeRegExp(text) {
    return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
}
Lookbehind:
String.prototype.splitKeep = function (tokens) {
    const escaped = escapeRegExp(tokens);
    return this.split(new RegExp(`(?=[${escaped}])|(?<=[${escaped}])`, "g"));
};
Match. Safari does not support lookbehind, use match approach:
String.prototype.splitKeep = function (tokens) {
    const tokensEscaped = tokens
        .split("")
        .map((s) => escapeRegExp(s))
        .join("|");

    const wordMatch = `[^${escapeRegExp(tokens)}]+`;
    return this.match(new RegExp(tokensEscaped + "|" + wordMatch, "g"));
};
Loop-based approach:
String.prototype.splitKeep = function (tokens) {
    let toPush = "";
    const splitList = [];
    for (const c of this) {
        if (tokens.includes(c)) {
            if (toPush.length > 0) {
                splitList.push(toPush);
            }
            splitList.push(c);
            toPush = "";
            continue;
        }

        toPush += c;
    }

    if (toPush.length > 0) {
        splitList.push(toPush);
    }

    return splitList;
};
Benchmark code:
console.time("test");
for (let i = 0; i < 10000; ++i) {
    "pin1yin1".splitKeep("12345 ");
}
console.timeEnd("test");
Results:
% node splitkeep-lookbehind.js
test: 19.35ms
% node splitkeep-lookbehind.js
test: 18.951ms
% node splitkeep-match.js       
test: 54.635ms
% node splitkeep-match.js
test: 51.998ms
% node splitkeep-loop.js 
test: 14.647ms
% node splitkeep-loop.js
test: 13.035ms

Saturday, October 2, 2021

Magic of 1s and 0s

Instead of this:

const VARIANT_CHAR = /variant of \p{Script=Han}/u;

// 'variant of chineseCharacterHere' sorts last
sort((a, b) =>
    VARIANT_CHAR.test(a.definitions.join(' ')) 
    && VARIANT_CHAR.test(b.definitions.join(' ')) ?
        0
    : VARIANT_CHAR.test(a.definitions.join(' ')) ?
        1
    : VARIANT_CHAR.test(b.definitions.join(' ')) ?
        -1
    :
        0
)  

Just do this:

const VARIANT_CHAR = /variant of \p{Script=Han}/u;

// 'variant of chineseCharacterHere' sorts last
sort((a, b) =>
    VARIANT_CHAR.test(a.definitions.join(' ')) 
    -
    VARIANT_CHAR.test(b.definitions.join(' '))
)