위키백과 다국어 보기

비교와 언어 학습을 위해 위키백과 항목을 두 개(또는 그 이상?)의 언어로 나란히 표시합니다.

// ==UserScript==
// @name             Wikipedia multi language view
// @name:en          Wikipedia multi language view
// @name:zh          Wikipedia 多语言浏览
// @name:ja          ウィキペディアの多言語表示
// @name:de          Wikipedia Mehrsprachige Ansicht
// @name:fr          Vue multilingue de Wikipédia
// @name:es          Vista multilingüe de Wikipedia
// @name:ru          Многоязычный вид Википедии
// @name:it          Visualizzazione multilingue di Wikipedia
// @name:ko          위키백과 다국어 보기
// @name:pt          Visualização multilíngue da Wikipédia
// @name:ar          عرض ويكيبيديا متعدد اللغات
// @name:vi          Chế độ xem đa ngôn ngữ của Wikipedia
// @name:pl          Wielojęzyczny widok Wikipedii
// @name:uk          Багатомовний перегляд Вікіпедії
// @name:nl          Meertalige weergave van Wikipedia
// @name:sv          Flerspråkig vy av Wikipedia
// @name:id          Tampilan multibahasa Wikipedia
// @name:fi          Monikielinen Wikipedia-näkymä
// @name:no          Flerspråklig visning av Wikipedia
// @namespace        https://userscript.snomiao.com/
// @author           [email protected]
// @version          0.0.8
// @description      View a Wikipedia entry with two (or more?) languages side by side for comparison and language learning.
// @description:zh   以并列多语言视角浏览维基百科
// @description:ja   比較と語学学習のために、ウィキペディアの記事を2つ(またはそれ以上?)の言語で並べて表示します。
// @description:de   Vergleichen und Sprachen lernen: Wikipedia-Einträge in zwei (oder mehr?) Sprachen nebeneinander anzeigen.
// @description:fr   Affichez un article de Wikipédia dans deux (ou plusieurs ?) langues côte à côte pour la comparaison et l'apprentissage des langues.
// @description:es   Ver una entrada de Wikipedia en dos (¿o más?) idiomas lado a lado para comparar y aprender idiomas.
// @description:ru   Просмотр статьи Википедии на двух (или более?) языках рядом для сравнения и изучения языков.
// @description:it   Visualizza un articolo di Wikipedia in due (o più?) lingue affiancate per il confronto e l'apprendimento delle lingue.
// @description:ko   비교와 언어 학습을 위해 위키백과 항목을 두 개(또는 그 이상?)의 언어로 나란히 표시합니다.
// @description:pt   Visualize uma entrada da Wikipédia em dois (ou mais?) idiomas lado a lado para comparação e aprendizado de idiomas.
// @description:ar   عرض مقالة ويكيبيديا بلغة (أو أكثر؟) جنبًا إلى جنب للمقارنة وتعلم اللغات.
// @description:vi   Xem một bài viết trên Wikipedia bằng hai (hoặc nhiều hơn?) ngôn ngữ song song để so sánh và học ngôn ngữ.
// @description:pl   Wyświetl wpis Wikipedii w dwóch (lub więcej?) językach obok siebie w celu porównania i nauki języków.
// @description:uk   Перегляд статті Вікіпедії двома (або більше?) мовами поруч для порівняння та вивчення мов.
// @description:nl   Bekijk een Wikipedia-artikel in twee (of meer?) talen naast elkaar voor vergelijking en taalleren.
// @description:sv   Visa en Wikipedia-post på två (eller fler?) språk sida vid sida för jämförelse och språkinlärning.
// @description:id   Lihat entri Wikipedia dalam dua (atau lebih?) bahasa berdampingan untuk perbandingan dan pembelajaran bahasa.
// @description:fi   Näytä Wikipedia-artikkeli kahdella (tai useammalla?) kielellä rinnakkain vertailua ja kielten oppimista varten.
// @description:no   Vis en Wikipedia-artikkel på to (eller flere?) språk side om side for sammenligning og språklæring.
// @match            https://*.wikipedia.org/wiki/*
// @match            https://zh.wikipedia.org/zh-*/*
// @grant            none
// @run-at           document-start
// @license          MIT
// @supportURL       https://github.com/snomiao/multilang-wiki/issues
// @contributionURL  https://snomiao.com/donate
// ==/UserScript==
//
// ref:
// @downloadURL-old  https://raw.githubusercontent.com/snomiao/userscript.js/main/src/wiki-multilang.user.js
// [javascript - Resize Cross Domain Iframe Height - Stack Overflow]( https://stackoverflow.com/questions/22086722/resize-cross-domain-iframe-height )
//
// 2025-05-29 udpate: add more languages, support more than 2 columns

// const Langs = ['en', 'ja', 'zh', 'de', 'fr', 'es', 'ru', 'it', 'ko', 'pt', 'ar', 'vi', 'pl', 'uk', 'nl', 'sv', 'id', 'fi', 'no', 'tr', 'cs', 'da', 'he', 'hu', 'ro', 'th']
const langs = ["en", "fr", "ja", "zh"]; // modify this to your preferred languages, will be used to load the 2nd language iframe

function main() {
    // hide sidebars
    setTimeout(() => {
        [
            ...document.body.querySelectorAll(
                "#sidebarCollapse,.vector-pinnable-header-unpin-button"
            ),
        ]
            .filter((e) => e?.checkVisibility?.())
            .map((e) => e?.click?.());
    }, 1e3);
}
main();

if (location.hash.match("#langIfr")) {
    // iframe code send height
    const sendHeight = () =>
        parent.postMessage?.(
            {
                langIfr: {
                    height: document.body.scrollHeight,
                    lang: location.hash.match?.(/#langIfr-(..)/)?.[1],
                },
            },
            "*"
        );
    window.addEventListener("resize", sendHeight, false);
    window.addEventListener("load", sendHeight, false);

    sendHeight();
    document.head.appendChild(createHtmlElement('<base target="_parent" />'));
} else {
    // parent code recv iframe's height
    const msgHandler = (e) => {
        const setHeight = ({ height, lang }) =>
            height &&
            lang &&
            document
                .querySelector?.(`.langIfr[lang=${lang}]`)
                ?.setAttribute("height", height);
        setHeight(e.data?.langIfr);
    };
    window.addEventListener("message", msgHandler, false);
    // load iframe
    const langLnksGet = () =>
        Object.fromEntries(
            [...document.querySelectorAll("a.interlanguage-link-target")]
                .map((e) => ({
                    lang: e.getAttribute("lang"),
                    href: e.href,
                    language: e.textContent,
                }))
                .map((e) => [e.lang, e])
        );
    const columns = (document.body.clientWidth / 800) | 0;
    console.log("multilang-wiki: " + columns + " columns");
    const exlangFrameLoad = () => {
        const langLnks = langLnksGet();
        const avaliableLangs = langs
            .filter((lang) => langLnks[lang])
            .filter((lang, i) => i < columns);
        console.log("Avaliable languages: " + avaliableLangs);

        const width = (100 / (avaliableLangs.length + 1)).toFixed(2) + "vw";
        const langIframeLoad = (lang = "en") => {
            if (!langLnks[lang]) return null;
            const count = [...document.querySelectorAll(".langIfr")].length;
            document.body.setAttribute(
                "style",
                `width: ${width}; overflow-x: hidden`
            );
            document.body.querySelector(`.langIfr[lang=${lang}]`)?.remove();
            const langIfr = createHtmlElement(`
              <iframe
                class="langIfr"
                lang="${lang}"
                src="${langLnks[lang].href + "#langIfr-" + lang}"
                style="border: none; position:absolute; left: calc(${
                    1 + count
                } * ${width}); top: 0vh; width: ${width}; min-height: 100vh"
                allow="fullscreen"
              ></iframe>`);
            document.body.appendChild(langIfr);
            return langIfr;
        };

        // the load 2st language for current page

        avaliableLangs.forEach((lang) => langIframeLoad(lang));

        // langs.find(lang => langIframeLoad(lang))
    };
    window.addEventListener("load", exlangFrameLoad, false);
}

function createHtmlElement(innerHTML = "<span>hello</span>") {
    return Object.assign(document.createElement("div"), { innerHTML })
        .children[0];
}