Skip to content

Instantly share code, notes, and snippets.

@JLChnToZ
Last active May 27, 2022 11:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JLChnToZ/66ecb3decaf3bcdaa6df08a2e1738e41 to your computer and use it in GitHub Desktop.
Save JLChnToZ/66ecb3decaf3bcdaa6df08a2e1738e41 to your computer and use it in GitHub Desktop.
A user script that will transliterates all Latin characters to Cyrillic. Just for fun.
// ==UserScript==
// @name Cyrillic?
// @namespace JLChnToZ
// @grant none
// @version 1.0
// @author -
// @description Transliterates all Latin characters to Cyrillic.
// ==/UserScript==
(() => {
const transliterate = ((latin, cyrillic) => {
latin = latin.split('.');
cyrillic = cyrillic.split('.');
const toCyrillic = new Map();
const toLatin = new Map();
for (let i = 0, l = Math.min(latin.length, cyrillic.length); i < l; i++) {
if (!toCyrillic.has(latin[i])) toCyrillic.set(latin[i], cyrillic[i]);
if (!toLatin.has(cyrillic[i])) toLatin.set(cyrillic[i], latin[i]);
}
return [toCyrillic, toLatin].map(mapping => str => {
let result = '';
for (const c of str) result += mapping.get(c) || c;
return result;
});
})(
'A.Ä.Ạ̈.Ă.Ā.Æ.Á.Å.B.V.G.G̀.Ǵ.Ġ.Ğ.Ḥ.D.Đ.E.Ĕ.Ë.Ê.Ž.Ž̦.Ž̧.Z̄.Z̆.Z.Z̈.Ź.Ẑ.I.Ī.Í.Î.J.Ì.Ï.Ǐ.J̌.J́.K.Ḱ.Ḳ.K̂.Ǩ.K̄.K̦.Ķ.K̀.Q.L.L̂.L̦.Ļ.M.N.N̂.N̦.Ņ.Ṇ.Ṅ.Ǹ.Ń.' +
'Ň.N̄.O.Ö.Ô.Ő.Ọ̈.Ò.Ó.Ō.Œ.P.Ṕ.P̀.R.S.Ș.Ş.S̀.T.Ć.T̀.Ť.Ț.Ţ.U.Ü.Ū.Ŭ.Ű.Ú.Ụ̈.Ụ̄.Ù.U̇.W.F.H.H̦.Ḩ.C.C̄.D̂.Č.C̦.Ç.C̣.C̈.Ĉ.C̀.C̆.C̨̆.Š.Ŝ.ʺ.Y.Ÿ.Ȳ.ʹ.È.A̋.À.Û.Û̄.' +
'Â.G̀.Ě.Ǎ.F̀.Ỳ.‡.ʼ.ˮ.a.ä.ạ̈.ă.ā.æ.á.å.b.v.g.g̀.ǵ.ġ.ğ.ḥ.d.đ.e.ĕ.ë.ê.ž.ž̦.ž̧.z̄.z̆.z.z̈.ź.ẑ.i.ī.í.î.j.ì.ï.ǐ.ǰ.j́.k.ḱ.ḳ.k̂.ǩ.k̄.k̦.ķ.k̀.q.l.l̂.l̦.ļ.' +
'm.n.n̂.n̦.ņ.ṇ.ṅ.ǹ.ń.ň.n̄.o.ö.ô.ő.ọ̈.ò.ó.ō.œ.p.ṕ.p̀.r.s.ș.ş.s̀.t.ć.t̀.ť.ț.ţ.u.ü.ū.ŭ.ű.ú.ụ̈.ụ̄.ù.u̇.w.f.h.h̦.ḩ.c.c̄.d̂.č.c̦.ç.c̣.c̈.ĉ.c̀.c̆.c̨̆.š.ŝ.ŝ.' +
'y.ÿ.ȳ.ȳ.è.a̋.à.û.û̄.â.g̀.ě.ǎ.f̀.ỳ',
'А.Ӓ.Ӓ̄.Ӑ.А̄.Ӕ.А́.А̊.Б.В.Г.Ґ.Ѓ.Ғ.Ҕ.Һ.Д.Ђ.Е.Ӗ.Ё.Є.Ж.Җ.Җ.Ӝ.Ӂ.З.Ӟ.Ӡ.Ѕ.И.Ӣ.И́.Ӥ.Й.І.Ї.І̄.Ј.Ј̵.К.Ќ.Ӄ.Ҝ.Ҡ.Ҟ.Қ.Қ.К̨.Ԛ.Л.Љ.Ԡ.Ԡ.М.Н.Њ.Ң.Ң.Ӊ.Ҥ.Ԋ.Ԣ.' +
'Ӈ.Н̄.О.Ӧ.Ө.Ӫ.Ӧ̄.Ҩ.О́.О̄.Œ.П.Ҧ.Ԥ.Р.С.Ҫ.Ҫ.С̀.Т.Ћ.Ԏ.Т̌.Ҭ.Ҭ.У.Ӱ.Ӯ.Ў.Ӳ.У́.Ӱ̄.Ӱ̄.Ү.Ұ.Ԝ.Ф.Х.Ҳ.Ҳ.Ц.Ҵ.Џ.Ч.Ҷ.Ҷ.Ӌ.Ӵ.Ҹ.Ч̀.Ҽ.Ҿ.Ш.Щ.Ъ.Ы.Ӹ.Ы̄.Ь.Э.Ә.Ӛ.Ю.Ю̄.' +
'Я.Ґ.Ѣ.Ѫ.Ѳ.Ѵ.Ӏ.ʼ.ˮ.а.ӓ.ӓ̄.ӑ.а̄.ӕ.а́.а̊.б.в.г.ґ.ѓ.ғ.ҕ.һ.д.ђ.е.ӗ.ё.є.ж.җ.җ.ӝ.ӂ.з.ӟ.ӡ.ѕ.и.ӣ.и́.ӥ.й.і.ї.і̄.ј.ј̵.к.ќ.ӄ.ҝ.ҡ.ҟ.қ.қ.к̨.ԛ.л.љ.ԡ.ԡ.' +
'м.н.њ.ң.ң.ӊ.ҥ.ԋ.ԣ.ӈ.н̄.о.ӧ.ө.ӫ.о̄̈.ҩ.о́.о̄.œ.п.ҧ.ԥ.р.с.ҫ.ҫ.с̀.т.ћ.ԏ.т̌.ҭ.ҭ.у.ӱ.ӯ.ў.ӳ.у́.ӱ̄.ӱ̄.ү.ұ.ԝ.ф.х.ҳ.ҳ.ц.ҵ.џ.ч.ҷ.ҷ.ӌ.ӵ.ҹ.ч̀.ҽ.ҿ.ш.щ.ъ.' +
'ы.ӹ.ы̄.ь.э.ә.ӛ.ю.ю̄.я.ґ.ѣ.ѫ.ѳ.ѵ',
)[0];
const queue = new Map();
const processedNodes = new WeakSet();
const observedNodes = new WeakSet();
const observer = new MutationObserver(changes => setTimeout(processChanges, 100, changes));
function observe(target) {
if (observedNodes.has(target)) return;
observedNodes.add(target);
processNode(target);
applyNodes();
observer.observe(target, {
childList: true,
subtree: true,
characterData: true,
});
}
function processChanges(changes) {
for (const { type, target, addedNodes } of changes) {
switch (type) {
case 'characterData': processNode(target); break;
case 'childList': addedNodes.forEach(processNode); break;
}
}
applyNodes();
}
function processNode(currentNode, inTree) {
if (processedNodes.has(currentNode)) return;
if (!(currentNode instanceof Text)) {
if (inTree === true) return;
const nodeIterator = document.createNodeIterator(currentNode, NodeFilter.SHOW_TEXT);
while (currentNode = nodeIterator.nextNode()) processNode(currentNode, true);
return;
}
const { wholeText } = currentNode;
const trimmedSrc = wholeText.trim();
if (!trimmedSrc) return;
const text = transliterate(wholeText);
if (trimmedSrc !== text.trim()) queue.set(currentNode, text);
}
function applyNodes() {
for (const [oldNode, value] of queue) {
if (processedNodes.has(oldNode)) continue;
processedNodes.add(oldNode);
try {
if (oldNode instanceof Text) oldNode.nodeValue = value;
} catch (e) {
console.error(e);
try {
const { parentNode } = oldNode;
if (!parentNode) continue;
const newNode = (parentNode.ownerDocument || parentNode).createTextNode(value);
processedNodes.add(newNode);
const nextNode = oldNode.nextSibling;
parentNode.removeChild(oldNode);
parentNode.insertBefore(newNode, nextNode);
} catch (e) {
console.error(e);
}
}
}
queue.clear();
}
if (document.readyState !== 'loading') setTimeout(observe, 1000, document.body);
else document.addEventListener('readystatechange', () => setTimeout(observe, 1000, document.body));
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment