Skip to content

Instantly share code, notes, and snippets.

@dgrammatiko
Created October 5, 2020 19:24
Show Gist options
  • Save dgrammatiko/8631faa0ea083e139a7e36e41690b1b6 to your computer and use it in GitHub Desktop.
Save dgrammatiko/8631faa0ea083e139a7e36e41690b1b6 to your computer and use it in GitHub Desktop.
var BROWSER_DEFAULT = 'BROWSER_DEFAULT';
var languages = {
// not a language, used to represent absence of a language defaulting to browser language
BROWSER_DEFAULT: {
name: 'Browser default',
nativeName: 'Browser default'
},
ab: {
name: 'Abkhaz',
nativeName: 'аҧсуа'
},
aa: {
name: 'Afar',
nativeName: 'Afaraf'
},
af: {
name: 'Afrikaans',
nativeName: 'Afrikaans'
},
ak: {
name: 'Akan',
nativeName: 'Akan'
},
sq: {
name: 'Albanian',
nativeName: 'Shqip'
},
am: {
name: 'Amharic',
nativeName: 'አማርኛ'
},
ar: {
name: 'Arabic',
nativeName: 'العربية'
},
an: {
name: 'Aragonese',
nativeName: 'Aragonés'
},
hy: {
name: 'Armenian',
nativeName: 'Հայերեն'
},
as: {
name: 'Assamese',
nativeName: 'অসমীয়া'
},
av: {
name: 'Avaric',
nativeName: 'авар мацӀ, магӀарул мацӀ'
},
ae: {
name: 'Avestan',
nativeName: 'avesta'
},
ay: {
name: 'Aymara',
nativeName: 'aymar aru'
},
az: {
name: 'Azerbaijani',
nativeName: 'azərbaycan dili'
},
bm: {
name: 'Bambara',
nativeName: 'bamanankan'
},
ba: {
name: 'Bashkir',
nativeName: 'башҡорт теле'
},
eu: {
name: 'Basque',
nativeName: 'euskara, euskera'
},
be: {
name: 'Belarusian',
nativeName: 'Беларуская'
},
bn: {
name: 'Bengali',
nativeName: 'বাংলা'
},
bh: {
name: 'Bihari',
nativeName: 'भोजपुरी'
},
bi: {
name: 'Bislama',
nativeName: 'Bislama'
},
bs: {
name: 'Bosnian',
nativeName: 'bosanski jezik'
},
br: {
name: 'Breton',
nativeName: 'brezhoneg'
},
bg: {
name: 'Bulgarian',
nativeName: 'български език'
},
my: {
name: 'Burmese',
nativeName: 'ဗမာစာ'
},
ca: {
name: 'Catalan; Valencian',
nativeName: 'Català'
},
ch: {
name: 'Chamorro',
nativeName: 'Chamoru'
},
ce: {
name: 'Chechen',
nativeName: 'нохчийн мотт'
},
ny: {
name: 'Chichewa; Chewa; Nyanja',
nativeName: 'chiCheŵa, chinyanja'
},
zh: {
name: 'Chinese',
nativeName: '中文 (Zhōngwén), 汉语, 漢語'
},
cv: {
name: 'Chuvash',
nativeName: 'чӑваш чӗлхи'
},
kw: {
name: 'Cornish',
nativeName: 'Kernewek'
},
co: {
name: 'Corsican',
nativeName: 'corsu, lingua corsa'
},
cr: {
name: 'Cree',
nativeName: 'ᓀᐦᐃᔭᐍᐏᐣ'
},
hr: {
name: 'Croatian',
nativeName: 'hrvatski'
},
cs: {
name: 'Czech',
nativeName: 'česky, čeština'
},
da: {
name: 'Danish',
nativeName: 'dansk'
},
dv: {
name: 'Divehi; Dhivehi; Maldivian;',
nativeName: 'ދިވެހި'
},
nl: {
name: 'Dutch',
nativeName: 'Nederlands, Vlaams'
},
en: {
name: 'English',
nativeName: 'English'
},
eo: {
name: 'Esperanto',
nativeName: 'Esperanto'
},
et: {
name: 'Estonian',
nativeName: 'eesti, eesti keel'
},
ee: {
name: 'Ewe',
nativeName: 'Eʋegbe'
},
fo: {
name: 'Faroese',
nativeName: 'føroyskt'
},
fj: {
name: 'Fijian',
nativeName: 'vosa Vakaviti'
},
fi: {
name: 'Finnish',
nativeName: 'suomi, suomen kieli'
},
fr: {
name: 'French',
nativeName: 'français, langue française'
},
ff: {
name: 'Fula; Fulah; Pulaar; Pular',
nativeName: 'Fulfulde, Pulaar, Pular'
},
gl: {
name: 'Galician',
nativeName: 'Galego'
},
ka: {
name: 'Georgian',
nativeName: 'ქართული'
},
de: {
name: 'German',
nativeName: 'Deutsch'
},
el: {
name: 'Greek, Modern',
nativeName: 'Ελληνικά'
},
gn: {
name: 'Guaraní',
nativeName: 'Avañeẽ'
},
gu: {
name: 'Gujarati',
nativeName: 'ગુજરાતી'
},
ht: {
name: 'Haitian; Haitian Creole',
nativeName: 'Kreyòl ayisyen'
},
ha: {
name: 'Hausa',
nativeName: 'Hausa, هَوُسَ'
},
he: {
name: 'Hebrew (modern)',
nativeName: 'עברית'
},
hz: {
name: 'Herero',
nativeName: 'Otjiherero'
},
hi: {
name: 'Hindi',
nativeName: 'हिन्दी, हिंदी'
},
ho: {
name: 'Hiri Motu',
nativeName: 'Hiri Motu'
},
hu: {
name: 'Hungarian',
nativeName: 'Magyar'
},
ia: {
name: 'Interlingua',
nativeName: 'Interlingua'
},
id: {
name: 'Indonesian',
nativeName: 'Bahasa Indonesia'
},
ie: {
name: 'Interlingue',
nativeName: 'Originally called Occidental; then Interlingue after WWII'
},
ga: {
name: 'Irish',
nativeName: 'Gaeilge'
},
ig: {
name: 'Igbo',
nativeName: 'Asụsụ Igbo'
},
ik: {
name: 'Inupiaq',
nativeName: 'Iñupiaq, Iñupiatun'
},
io: {
name: 'Ido',
nativeName: 'Ido'
},
is: {
name: 'Icelandic',
nativeName: 'Íslenska'
},
it: {
name: 'Italian',
nativeName: 'Italiano'
},
iu: {
name: 'Inuktitut',
nativeName: 'ᐃᓄᒃᑎᑐᑦ'
},
ja: {
name: 'Japanese',
nativeName: '日本語 (にほんご/にっぽんご)'
},
jv: {
name: 'Javanese',
nativeName: 'basa Jawa'
},
kl: {
name: 'Kalaallisut, Greenlandic',
nativeName: 'kalaallisut, kalaallit oqaasii'
},
kn: {
name: 'Kannada',
nativeName: 'ಕನ್ನಡ'
},
kr: {
name: 'Kanuri',
nativeName: 'Kanuri'
},
ks: {
name: 'Kashmiri',
nativeName: 'कश्मीरी, كشميري‎'
},
kk: {
name: 'Kazakh',
nativeName: 'Қазақ тілі'
},
km: {
name: 'Khmer',
nativeName: 'ភាសាខ្មែរ'
},
ki: {
name: 'Kikuyu, Gikuyu',
nativeName: 'Gĩkũyũ'
},
rw: {
name: 'Kinyarwanda',
nativeName: 'Ikinyarwanda'
},
ky: {
name: 'Kirghiz, Kyrgyz',
nativeName: 'кыргыз тили'
},
kv: {
name: 'Komi',
nativeName: 'коми кыв'
},
kg: {
name: 'Kongo',
nativeName: 'KiKongo'
},
ko: {
name: 'Korean',
nativeName: '한국어 (韓國語), 조선말 (朝鮮語)'
},
ku: {
name: 'Kurdish',
nativeName: 'Kurdî, كوردی‎'
},
kj: {
name: 'Kwanyama, Kuanyama',
nativeName: 'Kuanyama'
},
la: {
name: 'Latin',
nativeName: 'latine, lingua latina'
},
lb: {
name: 'Luxembourgish, Letzeburgesch',
nativeName: 'Lëtzebuergesch'
},
lg: {
name: 'Luganda',
nativeName: 'Luganda'
},
li: {
name: 'Limburgish, Limburgan, Limburger',
nativeName: 'Limburgs'
},
ln: {
name: 'Lingala',
nativeName: 'Lingála'
},
lo: {
name: 'Lao',
nativeName: 'ພາສາລາວ'
},
lt: {
name: 'Lithuanian',
nativeName: 'lietuvių kalba'
},
lu: {
name: 'Luba-Katanga',
nativeName: 'Luba-Katanga'
},
lv: {
name: 'Latvian',
nativeName: 'latviešu valoda'
},
gv: {
name: 'Manx',
nativeName: 'Gaelg, Gailck'
},
mk: {
name: 'Macedonian',
nativeName: 'македонски јазик'
},
mg: {
name: 'Malagasy',
nativeName: 'Malagasy fiteny'
},
ms: {
name: 'Malay',
nativeName: 'bahasa Melayu, بهاس ملايو‎'
},
ml: {
name: 'Malayalam',
nativeName: 'മലയാളം'
},
mt: {
name: 'Maltese',
nativeName: 'Malti'
},
mi: {
name: 'Māori',
nativeName: 'te reo Māori'
},
mr: {
name: 'Marathi (Marāṭhī)',
nativeName: 'मराठी'
},
mh: {
name: 'Marshallese',
nativeName: 'Kajin M̧ajeļ'
},
mn: {
name: 'Mongolian',
nativeName: 'монгол'
},
na: {
name: 'Nauru',
nativeName: 'Ekakairũ Naoero'
},
nv: {
name: 'Navajo, Navaho',
nativeName: 'Diné bizaad, Dinékʼehǰí'
},
nb: {
name: 'Norwegian Bokmål',
nativeName: 'Norsk bokmål'
},
nd: {
name: 'North Ndebele',
nativeName: 'isiNdebele'
},
ne: {
name: 'Nepali',
nativeName: 'नेपाली'
},
ng: {
name: 'Ndonga',
nativeName: 'Owambo'
},
nn: {
name: 'Norwegian Nynorsk',
nativeName: 'Norsk nynorsk'
},
no: {
name: 'Norwegian',
nativeName: 'Norsk'
},
ii: {
name: 'Nuosu',
nativeName: 'ꆈꌠ꒿ Nuosuhxop'
},
nr: {
name: 'South Ndebele',
nativeName: 'isiNdebele'
},
oc: {
name: 'Occitan',
nativeName: 'Occitan'
},
oj: {
name: 'Ojibwe, Ojibwa',
nativeName: 'ᐊᓂᔑᓈᐯᒧᐎᓐ'
},
cu: {
name: 'Old Church Slavonic, Church Slavic, Church Slavonic, Old Bulgarian, Old Slavonic',
nativeName: 'ѩзыкъ словѣньскъ'
},
om: {
name: 'Oromo',
nativeName: 'Afaan Oromoo'
},
or: {
name: 'Oriya',
nativeName: 'ଓଡ଼ିଆ'
},
os: {
name: 'Ossetian, Ossetic',
nativeName: 'ирон æвзаг'
},
pa: {
name: 'Panjabi, Punjabi',
nativeName: 'ਪੰਜਾਬੀ, پنجابی‎'
},
pi: {
name: 'Pāli',
nativeName: 'पाऴि'
},
fa: {
name: 'Persian',
nativeName: 'فارسی'
},
pl: {
name: 'Polish',
nativeName: 'polski'
},
ps: {
name: 'Pashto, Pushto',
nativeName: 'پښتو'
},
pt: {
name: 'Portuguese',
nativeName: 'Português'
},
qu: {
name: 'Quechua',
nativeName: 'Runa Simi, Kichwa'
},
rm: {
name: 'Romansh',
nativeName: 'rumantsch grischun'
},
rn: {
name: 'Kirundi',
nativeName: 'kiRundi'
},
ro: {
name: 'Romanian, Moldavian, Moldovan',
nativeName: 'română'
},
ru: {
name: 'Russian',
nativeName: 'русский язык'
},
sa: {
name: 'Sanskrit (Saṁskṛta)',
nativeName: 'संस्कृतम्'
},
sc: {
name: 'Sardinian',
nativeName: 'sardu'
},
sd: {
name: 'Sindhi',
nativeName: 'सिन्धी, سنڌي، سندھی‎'
},
se: {
name: 'Northern Sami',
nativeName: 'Davvisámegiella'
},
sm: {
name: 'Samoan',
nativeName: 'gagana faa Samoa'
},
sg: {
name: 'Sango',
nativeName: 'yângâ tî sängö'
},
sr: {
name: 'Serbian',
nativeName: 'српски језик'
},
gd: {
name: 'Scottish Gaelic; Gaelic',
nativeName: 'Gàidhlig'
},
sn: {
name: 'Shona',
nativeName: 'chiShona'
},
si: {
name: 'Sinhala, Sinhalese',
nativeName: 'සිංහල'
},
sk: {
name: 'Slovak',
nativeName: 'slovenčina'
},
sl: {
name: 'Slovene',
nativeName: 'slovenščina'
},
so: {
name: 'Somali',
nativeName: 'Soomaaliga, af Soomaali'
},
st: {
name: 'Southern Sotho',
nativeName: 'Sesotho'
},
es: {
name: 'Spanish; Castilian',
nativeName: 'español, castellano'
},
su: {
name: 'Sundanese',
nativeName: 'Basa Sunda'
},
sw: {
name: 'Swahili',
nativeName: 'Kiswahili'
},
ss: {
name: 'Swati',
nativeName: 'SiSwati'
},
sv: {
name: 'Swedish',
nativeName: 'svenska'
},
ta: {
name: 'Tamil',
nativeName: 'தமிழ்'
},
te: {
name: 'Telugu',
nativeName: 'తెలుగు'
},
tg: {
name: 'Tajik',
nativeName: 'тоҷикӣ, toğikī, تاجیکی‎'
},
th: {
name: 'Thai',
nativeName: 'ไทย'
},
ti: {
name: 'Tigrinya',
nativeName: 'ትግርኛ'
},
bo: {
name: 'Tibetan Standard, Tibetan, Central',
nativeName: 'བོད་ཡིག'
},
tk: {
name: 'Turkmen',
nativeName: 'Türkmen, Түркмен'
},
tl: {
name: 'Tagalog',
nativeName: 'Wikang Tagalog, ᜏᜒᜃᜅ᜔ ᜆᜄᜎᜓᜄ᜔'
},
tn: {
name: 'Tswana',
nativeName: 'Setswana'
},
to: {
name: 'Tonga (Tonga Islands)',
nativeName: 'faka Tonga'
},
tr: {
name: 'Turkish',
nativeName: 'Türkçe'
},
ts: {
name: 'Tsonga',
nativeName: 'Xitsonga'
},
tt: {
name: 'Tatar',
nativeName: 'татарча, tatarça, تاتارچا‎'
},
tw: {
name: 'Twi',
nativeName: 'Twi'
},
ty: {
name: 'Tahitian',
nativeName: 'Reo Tahiti'
},
ug: {
name: 'Uighur, Uyghur',
nativeName: 'Uyƣurqə, ئۇيغۇرچە‎'
},
uk: {
name: 'Ukrainian',
nativeName: 'українська'
},
ur: {
name: 'Urdu',
nativeName: 'اردو'
},
uz: {
name: 'Uzbek',
nativeName: 'zbek, Ўзбек, أۇزبېك‎'
},
ve: {
name: 'Venda',
nativeName: 'Tshivenḓa'
},
vi: {
name: 'Vietnamese',
nativeName: 'Tiếng Việt'
},
vo: {
name: 'Volapük',
nativeName: 'Volapük'
},
wa: {
name: 'Walloon',
nativeName: 'Walon'
},
cy: {
name: 'Welsh',
nativeName: 'Cymraeg'
},
wo: {
name: 'Wolof',
nativeName: 'Wollof'
},
fy: {
name: 'Western Frisian',
nativeName: 'Frysk'
},
xh: {
name: 'Xhosa',
nativeName: 'isiXhosa'
},
yi: {
name: 'Yiddish',
nativeName: 'ייִדיש'
},
yo: {
name: 'Yoruba',
nativeName: 'Yorùbá'
},
za: {
name: 'Zhuang, Chuang',
nativeName: 'Saɯ cueŋƅ, Saw cuengh'
}
}; // Depending on the current location of the cursor, replace the current node with the HTML in `lang`
// This cannot be an arrow function because tinyMCE accesses it via a new keyword.
tinymce.PluginManager.add('language', function (a) {
var b = function replaceText(b) {
var c = a.selection.getNode();
var d = a.selection.getContent({
format: 'html'
});
var e = d || '&#65279'; // use zero-width character as placeholder if no existing text
var f = b === BROWSER_DEFAULT ? "<span id=\"new_span\">".concat(e, "</span>") : "<span lang=\"".concat(b, "\" id=\"new_span\">").concat(e, "</span>");
// delete any existing text
// may be in the middle of the span, so split it into two
if (a.selection.setContent(''), c.nodeName === 'SPAN') c.lang ? a.execCommand('mceInsertRawHTML', false, "</span>".concat(f, "<span lang=\"").concat(c.lang, "\">")) : a.execCommand('mceInsertRawHTML', false, "</span>".concat(f, "<span>"));else {
// could be inside another tag like <a> or <b> that is a descendant of a span
var h = tinymce.DOM.getParent(c, function (a) {
return a.nodeName === 'SPAN' && !a.dataset.mceBogus;
});
if (h) {
var i = c;
for (var j = f; i !== h;) j = "<".concat(i.nodeName.toLowerCase(), ">").concat(j, "</").concat(i.nodeName.toLowerCase(), ">"), i = i.parentNode; // create new span with or without lang attribute, depending on parent span
for (insertedText = h.lang ? "</span>".concat(insertedText, "<span lang=\"").concat(h.lang, "\">") : "</span>".concat(insertedText, "<span>"), i = c; i !== h;) insertedText = "</".concat(i.nodeName.toLowerCase(), ">").concat(insertedText, "<").concat(i.nodeName.toLowerCase(), ">"), i = i.parentNode;
a.execCommand('mceInsertRawHTML', false, insertedText);
} else // conservatively insert HTML
a.execCommand('mceInsertRawHTML', false, f);
}
var g = a.dom.get('new_span');
a.selection.select(g), a.selection.collapse(false), g.removeAttribute('id');
};
var c = function updateButtonText(b) {
var c = a.dom.select("button#lang-button-".concat(a.id), a.targetElm.nextElementSibling)[0];
c.innerText = b && b !== BROWSER_DEFAULT ? languages[b].nativeName : 'Browser default language';
}; // Get the language of the current cursor position
var d = function getSelectedLanguage(a) {
var b = a.selection.getNode();
var c; // TinyMCE inserts bogus span that have no meaning for language
if (b.nodeName === 'SPAN' && !b.dataset.mceBogus) c = b.lang;else if (b.nodeName === 'P') c = null;else {
// might be inside another tag such as <b> or <a>
var d = tinymce.DOM.getParent(b, function (a) {
return a.nodeName === 'SPAN' && !a.dataset.mceBogus;
});
c = d ? d.lang : null;
}
return c;
};
var e = function openDialog(e) {
var f = a.selection.getNode();
var g = a.selection.getStart();
var h = a.selection.getEnd();
var i = ['OL', 'UL'];
var j = ['B', 'U', 'I', 'STRONG', 'EM']; // Inserting a span across multiple tags (excluding formatting) doesn't work.
if (g !== h && !j.includes(g.nodeName) && !j.includes(h.nodeName) || i.includes(f.nodeName)) return void a.notificationManager.open({
text: 'The region that you have selected is too complex. Try selecting smaller regions, or try changing' + ' the language first and then typing your text as desired.',
type: 'error'
});
var k = d(a);
var l = k || BROWSER_DEFAULT;
a.windowManager.open({
title: 'Language plugin',
body: {
type: 'panel',
items: [{
type: 'htmlpanel',
html: "<div>Current language: ".concat(languages[l].nativeName, "</div>")
}, {
type: 'selectbox',
name: 'language',
label: 'Language',
items: Object.keys(languages).map(function (a) {
return {
value: a,
text: languages[a].nativeName
};
})
}]
},
buttons: [{
type: 'cancel',
text: 'Close'
}, {
type: 'submit',
text: 'Save',
primary: true
}],
onSubmit: function onSubmit(d) {
var f = d.getData();
a.focus(), a.undoManager.transact(function () {
b(f.language), e.setActive(f.language !== BROWSER_DEFAULT), c(f.language);
}), d.close();
}
});
};
var f = function addIdAttribute(a) {
var b = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
b < 3 ? setTimeout(function () {
// add an id attribute to the button so its text can be modified later
// might be able to improve if https://github.com/tinymce/tinymce/issues/5040 gets resolved
// We use setTimeout here without an explicit delay to avoid a race condition. The query was running
// before the innerText was being set to the button, but now, our setTimeout wrapper
// invokes this query once the current execution queue is finished.
try {
a.dom.select('button', a.targetElm.nextElementSibling).filter(function (a) {
return a.innerText === 'Browser' + ' default language';
})[0].setAttribute('id', "lang-button-".concat(a.id));
} catch (c) {
f(a, b += 1);
}
}, b * 1000) : console.error("Failed to find and set button ID in TinyMceLanguageSelectorPlugin after ".concat(b, " attempts."));
};
return a.ui.registry.addToggleButton('language', {
text: 'Browser default language',
onAction: function onAction(a) {
e(a);
},
onSetup: function onSetup(e) {
f(a);
// Update button state (disabled: default, enabled: other) and button text
var g = function updateCurrentLanguage() {
var b = d(a);
b ? e.setActive(true) : e.setActive(false), c(b);
};
return a.addShortcut('Meta+L', 'Switch to default language', function () {
var c = a.selection.getNode();
var d = c.lang ? c.lang : BROWSER_DEFAULT;
d !== BROWSER_DEFAULT && a.undoManager.transact(function () {
b(BROWSER_DEFAULT), e.setActive(false), g();
});
}), a.on('keyup', g), a.on('click', g), function () {
a.off('keyup', g), a.off('click', g);
};
}
}), {
getMetadata: function getMetadata() {
return {
name: 'Language plugin'
};
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment