Superscript Pinyin for Chinese Characters with API

Adds superscript pinyin to all Chinese characters on a webpage using an external API with accurate processing and placement. Includes a toggle shortcut. Uses superscript to show the pinyin next to the character. Toggles on and off with ctrl + shift + p. Defaults to off. Perfectly reversible.

Versión del día 20/08/2024. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Superscript Pinyin for Chinese Characters with API
// @namespace    http://tampermonkey.net/
// @version      2.6
// @description  Adds superscript pinyin to all Chinese characters on a webpage using an external API with accurate processing and placement. Includes a toggle shortcut. Uses superscript to show the pinyin next to the character. Toggles on and off with ctrl + shift + p. Defaults to off. Perfectly reversible.
// @author       Louis
// @match        *://*/*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // Cache for storing pinyin results to avoid duplicate API calls
    const pinyinCache = new Map(Object.entries({'的':'de','一':'yī','是':'shì','不':'bù','了':'le','在':'zài','人':'rén','有':'yǒu','我':'wǒ','他':'tā','这':'zhè','个':'gè','们':'men','中':'zhōng','来':'lái','上':'shàng','大':'dà','为':'wèi','和':'hé','国':'guó','地':'de','到':'dào','以':'yǐ','说':'shuō','时':'shí','要':'yào','就':'jiù','出':'chū','会':'huì','可':'kě','也':'yě','你':'nǐ','对':'duì','生':'shēng','能':'néng','而':'ér','子':'zi','那':'nà','得':'dé','于':'yú','着':'zhe','下':'xià','自':'zì','之':'zhī','年':'nián','过':'guò','发':'fā','后':'hòu','作':'zuò','里':'lǐ','用':'yòng','道':'dào','行':'xíng','所':'suǒ','然':'rán','家':'jiā','种':'zhǒng','事':'shì','成':'chéng','方':'fāng','多':'duō','经':'jīng','么':'me','去':'qù','法':'fǎ','学':'xué','如':'rú','都':'dōu','同':'tóng','现':'xiàn','当':'dāng','没':'méi','动':'dòng','面':'miàn','起':'qǐ','看':'kàn','定':'dìng','天':'tiān','分':'fēn','还':'hái','进':'jìn','好':'hǎo','小':'xiǎo','部':'bù','其':'qí','些':'xiē','主':'zhǔ','样':'yàng','理':'lǐ','心':'xīn','她':'tā','本':'běn','前':'qián','开':'kāi','但':'dàn','因':'yīn','只':'zhǐ','从':'cóng','想':'xiǎng','实':'shí','日':'rì','军':'jūn','者':'zhě','意':'yì','无':'wú','力':'lì','它':'tā','与':'yǔ','长':'zhǎng','把':'bǎ','机':'jī','十':'shí','民':'mín','第':'dì','公':'gōng','此':'cǐ','已':'yǐ','工':'gōng','使':'shǐ','情':'qíng','明':'míng','性':'xìng','知':'zhī','全':'quán','三':'sān','又':'yòu','关':'guān','点':'diǎn','正':'zhèng','业':'yè','外':'wài','将':'jiāng','两':'liǎng','高':'gāo','间':'jiān','由':'yóu','问':'wèn','很':'hěn','最':'zuì','重':'zhòng','并':'bìng','物':'wù','手':'shǒu','应':'yīng','战':'zhàn','向':'xiàng','头':'tóu','文':'wén','体':'tǐ','政':'zhèng','美':'měi','相':'xiāng','见':'jiàn','被':'bèi','利':'lì','什':'shén','二':'èr','等':'děng','产':'chǎn','或':'huò','新':'xīn','己':'jǐ','制':'zhì','身':'shēn','果':'guǒ','加':'jiā','西':'xī','斯':'sī','月':'yuè','话':'huà','合':'hé','回':'huí','特':'tè','代':'dài','内':'nèi','信':'xìn','表':'biǎo','化':'huà','老':'lǎo','给':'gěi','世':'shì','位':'wèi','次':'cì','度':'dù','门':'mén','任':'rèn','常':'cháng','先':'xiān','海':'hǎi','通':'tōng','教':'jiào','儿':'ér','原':'yuán','东':'dōng','声':'shēng','提':'tí','立':'lì','及':'jí','比':'bǐ','员':'yuán','解':'jiě','水':'shuǐ','名':'míng','真':'zhēn','论':'lùn','处':'chù','走':'zǒu','义':'yì','各':'gè','入':'rù','几':'jǐ','口':'kǒu','认':'rèn','条':'tiáo','平':'píng','系':'xì','气':'qì','题':'tí','活':'huó','尔':'ěr','更':'gèng','别':'bié','打':'dǎ','女':'nǚ','变':'biàn','四':'sì','神':'shén','总':'zǒng','何':'hé','电':'diàn','数':'shù','安':'ān','少':'shǎo','报':'bào','才':'cái','结':'jié','反':'fǎn','受':'shòu','目':'mù','太':'tài','量':'liàng','再':'zài','感':'gǎn','建':'jiàn','务':'wù','做':'zuò','接':'jiē','必':'bì','场':'chǎng','件':'jiàn','计':'jì','管':'guǎn','期':'qī','市':'shì','直':'zhí','德':'dé','资':'zī','命':'mìng','山':'shān','金':'jīn','指':'zhǐ','克':'kè','许':'xǔ','统':'tǒng','区':'qū','保':'bǎo','至':'zhì','队':'duì','形':'xíng','社':'shè','便':'biàn','空':'kōng','决':'jué','治':'zhì','展':'zhǎn','马':'mǎ','科':'kē','司':'sī','五':'wǔ','基':'jī','眼':'yǎn','书':'shū','非':'fēi','则':'zé','听':'tīng','白':'bái','却':'què','界':'jiè','达':'dá','光':'guāng','放':'fàng','强':'qiáng','即':'jí','像':'xiàng','难':'nán','且':'qiě','权':'quán','思':'sī','王':'wáng','象':'xiàng','完':'wán','设':'shè','式':'shì','色':'sè','路':'lù','记':'jì','南':'nán','品':'pǐn','住':'zhù','告':'gào','类':'lèi','求':'qiú','据':'jù','程':'chéng','北':'běi','边':'biān','死':'sǐ','张':'zhāng','该':'gāi','交':'jiāo','规':'guī','万':'wàn','取':'qǔ','拉':'lā','格':'gé','望':'wàng','觉':'jué','术':'shù','领':'lǐng','共':'gòng','确':'què','传':'chuán','师':'shī','观':'guān','清':'qīng','今':'jīn','切':'qiè','院':'yuàn','让':'ràng','识':'shí','候':'hòu','带':'dài','导':'dǎo','争':'zhēng','运':'yùn','笑':'xiào','飞':'fēi','风':'fēng','步':'bù','改':'gǎi','收':'shōu','根':'gēn','干':'gàn','造':'zào','言':'yán','联':'lián','持':'chí','组':'zǔ','每':'měi','济':'jì','车':'chē','亲':'qīn','极':'jí','林':'lín','服':'fú','快':'kuài','办':'bàn','议':'yì','往':'wǎng','元':'yuán','英':'yīng','士':'shì','证':'zhèng','近':'jìn','失':'shī','转':'zhuǎn','夫':'fū','令':'lìng','准':'zhǔn','布':'bù','始':'shǐ','怎':'zěn','呢':'ne','存':'cún','未':'wèi','远':'yuǎn','叫':'jiào','台':'tái','单':'dān','影':'yǐng','具':'jù','罗':'luō','字':'zì','爱':'ài','击':'jī','流':'liú','备':'bèi','兵':'bīng','连':'lián','调':'diào','深':'shēn','商':'shāng','算':'suàn','质':'zhì','团':'tuán','集':'jí','百':'bǎi','需':'xū','价':'jià','花':'huā','党':'dǎng','华':'huá','城':'chéng','石':'shí','级':'jí','整':'zhěng','府':'fǔ','离':'lí','况':'kuàng','亚':'yà','请':'qǐng','技':'jì','际':'jì','约':'yuē','示':'shì','复':'fù','病':'bìng','息':'xī','究':'jiū','线':'xiàn','似':'shì','官':'guān','火':'huǒ','断':'duàn','精':'jīng','满':'mǎn','支':'zhī','视':'shì','消':'xiāo','越':'yuè','器':'qì','容':'róng','照':'zhào','须':'xū','九':'jiǔ','增':'zēng','研':'yán','写':'xiě','称':'chēng','企':'qǐ','八':'bā','功':'gōng','吗':'ma','包':'bāo','片':'piàn','史':'shǐ','委':'wěi','乎':'hū','查':'chá','轻':'qīng','易':'yì','早':'zǎo','曾':'céng','除':'chú','农':'nóng','找':'zhǎo','装':'zhuāng','广':'guǎng','显':'xiǎn','吧':'ba','阿':'ā','李':'lǐ','标':'biāo','谈':'tán','吃':'chī','图':'tú','念':'niàn','六':'liù','引':'yǐn','历':'lì','首':'shǒu','医':'yī','局':'jú','突':'tū','专':'zhuān','费':'fèi','号':'hào','尽':'jǐn','另':'lìng','周':'zhōu','较':'jiào','注':'zhù','语':'yǔ','仅':'jǐn','考':'kǎo','落':'luò','青':'qīng','随':'suí','选':'xuǎn','列':'liè','武':'wǔ','红':'hóng','响':'xiǎng','虽':'suī','推':'tuī','势':'shì','参':'cān','希':'xī','古':'gǔ','众':'zhòng','构':'gòu','房':'fáng','半':'bàn','节':'jié','土':'tǔ','投':'tóu','某':'mǒu','案':'àn','黑':'hēi','维':'wéi','革':'gé','划':'huà','敌':'dí','致':'zhì','陈':'chén','律':'lǜ','足':'zú','态':'tài','护':'hù','七':'qī','兴':'xìng','派':'pài','孩':'hái','验':'yàn','责':'zé','营':'yíng','星':'xīng','够':'gòu','章':'zhāng','音':'yīn','跟':'gēn','志':'zhì','底':'dǐ','站':'zhàn','严':'yán','巴':'bā','例':'lì','防':'fáng','族':'zú','供':'gōng','效':'xiào','续':'xù','施':'shī','留':'liú','讲':'jiǎng','型':'xíng','料':'liào','终':'zhōng','答':'dá','紧':'jǐn','黄':'huáng','绝':'jué','奇':'qí','察':'chá','母':'mǔ','京':'jīng','段':'duàn','依':'yī','批':'pī','群':'qún','项':'xiàng','故':'gù','按':'àn','河':'hé','米':'mǐ','围':'wéi','江':'jiāng','织':'zhī','害':'hài','斗':'dòu','双':'shuāng','境':'jìng','客':'kè','纪':'jì','采':'cǎi','举':'jǔ','杀':'shā','攻':'gōng','父':'fù','苏':'sū','密':'mì','低':'dī','朝':'cháo','友':'yǒu','诉':'sù','止':'zhǐ','细':'xì','愿':'yuàn','千':'qiān','值':'zhí','仍':'réng','男':'nán','钱':'qián','破':'pò','网':'wǎng','热':'rè','助':'zhù','倒':'dào','育':'yù','属':'shǔ','坐':'zuò','帝':'dì','限':'xiàn','船':'chuán','脸':'liǎn','职':'zhí','速':'sù','刻':'kè','乐':'lè','否':'fǒu','刚':'gāng','威':'wēi','毛':'máo','状':'zhuàng','率':'lǜ','甚':'shén','独':'dú','球':'qiú','般':'bān','普':'pǔ','怕':'pà','弹':'dàn','校':'xiào','苦':'kǔ','创':'chuàng','假':'jiǎ','久':'jiǔ','错':'cuò','承':'chéng','印':'yìn','晚':'wǎn','兰':'lán','试':'shì','股':'gǔ','拿':'ná','脑':'nǎo','预':'yù','谁':'shuí','益':'yì','阳':'yáng','若':'ruò','哪':'nǎ','微':'wēi','尼':'ní','继':'jì','送':'sòng','急':'jí','血':'xuè','惊':'jīng','伤':'shāng','素':'sù','药':'yào','适':'shì','波':'bō','夜':'yè','省':'shěng','初':'chū','喜':'xǐ','卫':'wèi','源':'yuán','食':'shí','险':'xiǎn','待':'dài','述':'shù','陆':'lù','习':'xí','置':'zhì','居':'jū','劳':'láo','财':'cái','环':'huán','排':'pái','福':'fú','纳':'nà','欢':'huān','雷':'léi','警':'jǐng','获':'huò','模':'mó','充':'chōng','负':'fù','云':'yún','停':'tíng','木':'mù','游':'yóu','龙':'lóng','树':'shù','疑':'yí','层':'céng','冷':'lěng','洲':'zhōu','冲':'chōng','射':'shè','略':'lüè','范':'fàn','竟':'jìng','句':'jù','室':'shì','异':'yì','激':'jī','汉':'hàn','村':'cūn','哈':'hā','策':'cè','演':'yǎn','简':'jiǎn','卡':'kǎ','罪':'zuì','判':'pàn','担':'dān','州':'zhōu','静':'jìng','退':'tuì','既':'jì','衣':'yī','您':'nín','宗':'zōng','积':'jī','余':'yú','痛':'tòng','检':'jiǎn','差':'chà','富':'fù','灵':'líng','协':'xié','角':'jiǎo','占':'zhàn','配':'pèi','征':'zhēng','修':'xiū','皮':'pí','挥':'huī','胜':'shèng','降':'jiàng','阶':'jiē','审':'shěn','沉':'chén','坚':'jiān','善':'shàn','妈':'mā','刘':'liú','读':'dú','啊':'a','超':'chāo','免':'miǎn','压':'yā','银':'yín','买':'mǎi','皇':'huáng','养':'yǎng','伊':'yī','怀':'huái','执':'zhí','副':'fù','乱':'luàn','抗':'kàng','犯':'fàn','追':'zhuī','帮':'bāng','宣':'xuān','佛':'fú','岁':'suì','航':'háng','优':'yōu','怪':'guài','香':'xiāng','著':'zhe','田':'tián','铁':'tiě','控':'kòng','税':'shuì','左':'zuǒ','右':'yòu','份':'fèn','穿':'chuān','艺':'yì','背':'bèi','阵':'zhèn','草':'cǎo','脚':'jiǎo','概':'gài','恶':'è','块':'kuài','顿':'dùn','敢':'gǎn','守':'shǒu','酒':'jiǔ','岛':'dǎo','托':'tuō','央':'yāng','户':'hù','烈':'liè','洋':'yáng','哥':'gē','索':'suǒ','胡':'hú','款':'kuǎn','靠':'kào','评':'píng','版':'bǎn','宝':'bǎo','座':'zuò','释':'shì','景':'jǐng','顾':'gù','弟':'dì','登':'dēng','货':'huò','互':'hù','付':'fù','伯':'bó','慢':'màn','欧':'ōu','换':'huàn','闻':'wén','危':'wēi','忙':'máng','核':'hé','暗':'àn','姐':'jiě','介':'jiè','坏':'huài','讨':'tǎo','丽':'lì','良':'liáng','序':'xù','升':'shēng','监':'jiān','临':'lín','亮':'liàng','露':'lù','永':'yǒng','呼':'hū','味':'wèi','野':'yě','架':'jià','域':'yù','沙':'shā','掉':'diào','括':'kuò','舰':'jiàn','鱼':'yú','杂':'zá','误':'wù','湾':'wān','吉':'jí','减':'jiǎn','编':'biān','楚':'chǔ','肯':'kěn','测':'cè','败':'bài','屋':'wū','跑':'pǎo','梦':'mèng','散':'sàn','温':'wēn','困':'kùn','剑':'jiàn','渐':'jiàn','封':'fēng','救':'jiù','贵':'guì','枪':'qiāng','缺':'quē','楼':'lóu','县':'xiàn','尚':'shàng','毫':'háo','移':'yí','娘':'niáng','朋':'péng','画':'huà','班':'bān','智':'zhì','亦':'yì','耳':'ěr','恩':'ēn','短':'duǎn','掌':'zhǎng','恐':'kǒng','遗':'yí','固':'gù','席':'xí','松':'sōng','秘':'mì','谢':'xiè','鲁':'lǔ','遇':'yù','康':'kāng','虑':'lǜ','幸':'xìng','均':'jūn','销':'xiāo','钟':'zhōng','诗':'shī','藏':'cáng','赶':'gǎn','剧':'jù','票':'piào','损':'sǔn','忽':'hū','巨':'jù','炮':'pào','旧':'jiù','端':'duān','探':'tàn','湖':'hú','录':'lù','叶':'yè','春':'chūn','乡':'xiāng','附':'fù','吸':'xī','予':'yǔ','礼':'lǐ','港':'gǎng','雨':'yǔ','呀':'ya','板':'bǎn','庭':'tíng','妇':'fù','归':'guī','睛':'jīng','饭':'fàn','额':'é','含':'hán','顺':'shùn','输':'shū','摇':'yáo','招':'zhāo','婚':'hūn','脱':'tuō','补':'bǔ','谓':'wèi','督':'dū','毒':'dú','油':'yóu','疗':'liáo','旅':'lǚ','泽':'zé','材':'cái','灭':'miè','逐':'zhú','莫':'mò','笔':'bǐ','亡':'wáng','鲜':'xiān','词':'cí','圣':'shèng','择':'zé','寻':'xún','厂':'chǎng','睡':'shuì','博':'bó','勒':'lēi','烟':'yān','授':'shòu','诺':'nuò','伦':'lún','岸':'àn','奥':'ào','唐':'táng','卖':'mài','俄':'é','炸':'zhà','载':'zài','洛':'luò','健':'jiàn','堂':'táng','旁':'páng','宫':'gōng','喝':'hē','借':'jiè','君':'jūn','禁':'jìn','阴':'yīn','园':'yuán','谋':'móu','宋':'sòng','避':'bì','抓':'zhuā','荣':'róng','姑':'gū','孙':'sūn','逃':'táo','牙':'yá','束':'shù','跳':'tiào','顶':'dǐng'}));

    // Variable to track whether pinyin superscript is enabled or disabled
    let pinyinEnabled = false;
    let mutationObserver = null;

    // Expanded cache with common Chinese characters and their pinyin
    const initialCache = {};

    // Pre-fill the cache with initial data
    Object.entries(initialCache).forEach(([char, pinyin]) => pinyinCache.set(char, pinyin));

    // Function to make a request to the pinyin API
    async function fetchPinyin(char) {
        if (pinyinCache.has(char)) {
            return pinyinCache.get(char);
        }

        try {
            const response = await fetch(`https://12.yvelin.net/pinyin.php?text=${encodeURIComponent(char)}`);
            const result = await response.json();
            const pinyin = result && result.pinyin ? result.pinyin : '';
            pinyinCache.set(char, pinyin);
            return pinyin;
        } catch (e) {
            console.error(`Failed to fetch pinyin for character: "${char}"`, e);
            return '';
        }
    }

    // Function to apply pinyin superscripts to a given text node
    async function applyPinyin(node) {
        if (node.nodeType === Node.TEXT_NODE) {
            const text = node.textContent;
            const parent = node.parentNode;
            const fragment = document.createDocumentFragment();

            let currentIndex = 0;

            while (currentIndex < text.length) {
                const char = text[currentIndex];
                if (/[\u4e00-\u9fff]/.test(char)) { // Check if the character is Chinese
                    const pinyin = await fetchPinyin(char);

                    // Split the text node and insert the original character and its pinyin as <sup>
                    const charNode = document.createTextNode(char);
                    const supNode = document.createElement('sup');
                    supNode.textContent = pinyin;
                    supNode.setAttribute('data-custom-pinyin-superscript', 'true'); // Set the custom attribute

                    fragment.appendChild(charNode);
                    fragment.appendChild(supNode);
                } else {
                    fragment.appendChild(document.createTextNode(char));
                }
                currentIndex++;
            }

            // Replace the original text node with the fragment
            parent.replaceChild(fragment, node);
        }
    }

    // Function to handle text nodes within an element
    async function processElement(element) {
        const walker = document.createTreeWalker(element, NodeFilter.SHOW_TEXT, null, false);
        const nodes = [];
        while (walker.nextNode()) {
            nodes.push(walker.currentNode);
        }

        for (const node of nodes) {
            await applyPinyin(node);
        }
    }

    // Function to enable or disable the pinyin display
    async function togglePinyin() {
        if (pinyinEnabled) {
            // Remove all <sup> elements with the data attribute
            const superscripts = document.querySelectorAll('sup[data-custom-pinyin-superscript]');
            superscripts.forEach(sup => {
                const parent = sup.parentNode;
                if (parent) {
                    parent.removeChild(sup); // Remove the superscript pinyin
                }
            });
            pinyinEnabled = false;
        } else {
            await processElement(document.body);
            pinyinEnabled = true;

            // Observe for changes to dynamically added content
            mutationObserver = new MutationObserver(async mutations => {
                for (const mutation of mutations) {
                    if (mutation.type === 'childList') {
                        for (const node of mutation.addedNodes) {
                            if (node.nodeType === Node.ELEMENT_NODE) {
                                await processElement(node);
                            }
                        }
                    }
                }
            });
            mutationObserver.observe(document.body, { childList: true, subtree: true });
        }
    }

    // Add CSS for pinyin display (optional, you can style it differently)
    function addCSS() {
        const style = document.createElement('style');
        style.textContent = `
            sup[data-custom-pinyin-superscript] {
                font-size: 0.8em;
                vertical-align: super;
                color: #888;
            }
        `;
        document.head.appendChild(style);
    }

    // Initialize CSS
    addCSS();

    // Listen for keyboard shortcut to toggle pinyin
    document.addEventListener('keydown', (event) => {
        if (event.ctrlKey && event.shiftKey && event.key === 'P') {
            event.preventDefault();
            togglePinyin();
        }
    });

})();