User:Nikki/LexemeTranslations.js
Jump to navigation
Jump to search
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/**
* This script shows translations for a lexeme.
* The translations are inferred from statements on senses,
* such as P5137 (item for this sense).
*
* To use it, add the following line to your common.js:
* mw.loader.load("//www.wikidata.org/w/index.php?title=User:Nikki/LexemeTranslations.js&action=raw&ctype=text/javascript");
*
* License: CC0
*/
// jshint esversion: 6
(function () {
"use strict";
let translations = {
en: {
"translations": "Translations",
"synonyms": "Synonyms",
"colon": ": ",
"comma": ", ",
"slash": "/",
},
bn: {
"translations": "অনুবাদ",
"synonyms": "সমার্থক"
},
de: {
"translations": "Übersetzungen",
"synonyms": "Synonyme",
},
eo: {
"translations": "Tradukoj",
"synonyms": "Samsencaĵoj",
},
ja: {
"translations": "翻訳",
"synonyms": "類義語",
"colon": ":",
"comma": "、",
},
nb: {
"translations": "Oversettelser",
"synonyms": "Synonymer",
},
nn: {
"translations": "Omsetjingar",
"synonyms": "Synonym",
},
pa: {
"translations": "ਤਰਜਮੇ",
"synonyms": "ਸਮਾਨਾਰਥੀ",
},
pnb: {
"translations": "ترجمے",
"synonyms": "سمان ارتھی",
"comma": "، ",
},
};
mw.util.addCSS(`
.userjs-lexemetranslations {
border: 1px solid lightgrey;
clear: both;
}
.userjs-lexemetranslations h4 {
background: #f8f8f8;
color: dimgrey;
margin: 0;
padding: 0.3em;
}
.userjs-lexemetranslations ul {
list-style: none;
list-style-type: none;
margin: 0;
padding: 0.3em;
}
.userjs-lexemetranslations .translations ul {
column-width: 15em;
}
.userjs-lexemetranslations .translations ul li {
break-inside: avoid;
}
.userjs-lexemetranslations .loc {
color: dimgrey;
}
.userjs-lexemetranslations .sgn .lexemes {
display: flex;
flex-direction: row;
flex-wrap: wrap;
gap: 1em;
}
.userjs-lexemetranslations .sgn .lexemes bdi {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
.ltr .userjs-lexemetranslations .sgn .lexemes > bdi + bdi {
border-left: 3px solid lightgrey;
padding-left: 1em;
}
.rtl .userjs-lexemetranslations .sgn .lexemes > bdi + bdi {
border-right: 3px solid lightgrey;
padding-right: 1em;
}
.userjs-lexemetranslations .sgn .signwriting:hover {
filter: brightness(1.5);
}
`);
// see https://www.wikidata.org/wiki/User:Nikki/ExMusica.js
let langs = [...new Set([
mw.language.getFallbackLanguageChain().shift(),
mw.language.getFallbackLanguageChain().slice(1, -1),
mw.config.get("wgULSBabelLanguages") || [],
mw.config.get("wgULSAcceptLanguageList") || [],
"en"
].flat().map(function (x) { return x.toLowerCase(); }))].join(",");
// Languages where pronunciation can be displayed as ruby text
const ruby = {
"ja": "ja-hira",
"mvi": "mvi-hira",
"ojp": "ojp-hira",
"rys": "rys-hira",
"ryu": "ryu-hira",
"yoi": "yoi-hira",
"yox": "yox-hira",
};
// Languages which ULS doesn't know are sign languages
const signlanguages = [
"bfi", "fsl", "gsg", "pks",
"mis-x-q29525", // Auslan (asf)
"mis-x-q36668", // Austrian (asq)
"mis-x-q35768", // Catalan (csc)
"mis-x-q5201809", // Czech (cse)
"mis-x-q2201099", // Dutch (dse)
"mis-x-q2605298", // Danish (dsl)
"mis-x-q33225", // Finnish (fse)
"mis-x-q5450448", // Finland-Swedish (fss)
"mis-x-q3915462", // Hausa (hsl)
"mis-x-q113754817", // Indian (ins)
"mis-x-q35601", // Japanese (jsl)
"mis-x-q3073428", // Korean (kvk)
"mis-x-q6744816", // Maltese (mdl)
"mis-x-q3915511", // Mexican (mfs)
"mis-x-q1781613", // Norwegian (nsl)
"mis-x-q36239", // NZSL (nzs)
"mis-x-q3915194", // Polish (pso)
"mis-x-q3915472", // Portuguese (psr)
"mis-x-q3322093", // South African (sfs)
"mis-x-q35150", // DSGS (sgg)
"mis-x-q3100814", // Spanish (ssp)
"mis-x-q12953483", // Swiss French (ssr)
"mis-x-q2107617", // Flemish (vgt)
"mis-x-q20523999", // Slovenian (ysl-SI)
"mis-x-q113195519", // Kosovar (ysl-XK)
"mis-x-q123465950" // Bengali
];
let langnames = {};
function sort_language_names(a, b) {
return langnames[a].toLowerCase().localeCompare(langnames[b].toLowerCase());
}
function fetch_translations(e) {
if (!e.language) return; // not a lexeme
let eid = e.id;
let query = `
select ?s ?s1 ?lemma ?lang ?langLabel ?loc ?locLabel ?cc {
values ?p { wdt:P5137 wdt:P6271 wdt:P9970 }
wd:${ eid } ontolex:sense ?s.
?s ?p ?item.
?s1 ?p ?item.
?l ontolex:sense ?s1;
wikibase:lemma ?lemma;
dct:language ?lang.
filter (?l != wd:${ eid }).
optional {
?s1 wdt:P6084 ?loc.
optional { ?loc wdt:P297 ?cc }
}
service wikibase:label { bd:serviceParam wikibase:language "${ langs }" }
}
`;
$.getJSON("https://query.wikidata.org/sparql?format=json&query=" + encodeURI(query), function (data) {
let senses = {};
for (let e of data.results.bindings) {
let sid = e.s.value.replace(/.*-/, "");
let langid = e.lang.value.replace(/.*\//, "");
langnames[langid] = e.langLabel.value;
if (!senses[sid])
senses[sid] = [];
if (!senses[sid][langid])
senses[sid][langid] = [];
if (!senses[sid][langid][e.s1.value])
senses[sid][langid][e.s1.value] = [];
let exists = false;
for (let sense of senses[sid][langid][e.s1.value]) {
if (sense.lemma === e.lemma.value && sense.lang === e.lemma["xml:lang"]) {
if (e.loc) {
let loc_label = e.locLabel ? e.locLabel.value : e.loc.value.replace(/.*\//, "");
let loc_lang = e.locLabel ? e.locLabel["xml:lang"] : "und";
sense.loc.push({ name: e.locLabel.value, lang: e.locLabel["xml:lang"] });
}
exists = true;
}
}
if (!exists) {
let sense = {
lemma: e.lemma.value,
lang: e.lemma["xml:lang"],
loc: [],
}
if (e.locLabel) {
sense.loc.push({ name: e.locLabel.value, lang: e.locLabel["xml:lang"] });
}
senses[sid][langid][e.s1.value].push(sense);
}
}
for (let sid of Object.keys(senses).sort()) {
let output = [];
let synonyms = [];
let output_sgn = [];
for (let langid of Object.keys(senses[sid]).sort(sort_language_names)) {
let langname = langnames[langid];
let row = [];
let is_sgn = false;
for (let sense of Object.keys(senses[sid][langid]).sort(function (a, b) {
return senses[sid][langid][a][0].lemma.toLowerCase().localeCompare(senses[sid][langid][b][0].lemma.toLowerCase());
})) {
let lemmas = senses[sid][langid][sense].sort(function (a, b) { return a.lang.localeCompare(b.lang) }).map(function (x) {
let el = document.createElement("bdi");
el.lang = mw.language.bcp47(x.lang);
el.textContent = x.lemma;
if (
ruby.hasOwnProperty(x.lang)
&& senses[sid][langid][sense].length >= 2
&& senses[sid][langid][sense][1].lang === ruby[x.lang]
) {
el.innerHTML = `<ruby>${x.lemma}<rt>${senses[sid][langid][sense][1].lemma}</ruby>`;
} else if (
ruby.hasOwnProperty(senses[sid][langid][sense][0].lang)
&& x.lang === ruby[ senses[sid][langid][sense][0].lang ]) {
// TODO: figure out how this code actually works
return;
}
if (
($.uls.data.getScript(x.lang) === "Sgnw" || signlanguages.includes(x.lang))
&& el.textContent.match(/^[A-Za-z0-9 ]+$/)
) {
el.innerHTML = process_signwriting(el.textContent);
is_sgn = true;
}
return el.outerHTML;
}).filter(x => x).join($.i18n("slash"));
let loc = "";
if (senses[sid][langid][sense][0].loc.length > 0) {
loc = ` <span class="loc">(${ senses[sid][langid][sense][0].loc.map(x => `<span lang="${ x.lang }" dir="auto">${ x.name }</span>`).join($.i18n("comma")) })</span>`;
}
let url = sense.replace(/.*\/entity\/(L[1-9][0-9]*)-(S[1-9][0-9]*)/, "/wiki/Lexeme:$1#$2");
row.push(`<bdi><a href="${url}">${lemmas}</a></bdi>${loc}`);
}
if (e.language === langid) {
let v = `<li>${ row.join($.i18n("comma")) }</li>`;
synonyms.push(v);
} else if (is_sgn) {
let v = `<li><span class="langname"><bdi>${ langname }</bdi>${ $.i18n("colon") }</span><span class="lexemes">${ row.join("") }</span></li>`;
output_sgn.push(v);
} else {
let v = `<li><bdi>${ langname }</bdi>${ $.i18n("colon") }${ row.join($.i18n("comma")) }</li>`;
output.push(v);
}
}
if (!synonyms.length && !output.length && !output_sgn.length) {
continue;
}
let ststart = '<div class="userjs-lexemetranslations">';
if (synonyms.length) {
ststart += '<div class="synonyms">'
+ `<h4><bdi>${ $.i18n("synonyms") }</bdi></h4>`
+ `<ul>${ synonyms.join("") }</ul>`
+ '</div>';
}
if (output.length || output_sgn.length) {
ststart += '<div class="translations">'
+ '<h4><bdi>' + $.i18n("translations") + '</bdi></h4>'
if (output.length) {
ststart += "<ul>" + output.join("") + "</ul>";
}
if (output_sgn.length) {
ststart += "<ul class=\"sgn\">" + output_sgn.join("") + "</ul>";
}
ststart += '</div>';
}
ststart += '</div>';
document.querySelector("#" + sid + " .wikibase-lexeme-sense-statements").insertAdjacentHTML("beforeend", ststart);
}
});
}
function process_signwriting(word) {
return "<span class=\"signwriting\">"
+ "<span class=\"text\" style=\"font-size: 0%\">"
+ word
+ "</span>"
+ "<img src=\"https://swis.wmflabs.org/glyphogram.php?font=svg&text=" + word + "&line=0645ad\" alt=\"" + word + "\"/>"
+ "</span>"
+ "</span>";
}
mw.loader.using("jquery.i18n").then(function () {
mw.hook("wikibase.entityPage.entityView.rendered").add(function () {
mw.hook("wikibase.entityPage.entityLoaded").add(function (e) {
$.i18n().load(translations);
fetch_translations(e);
});
});
});
})();