MediaWiki:Multilingual description.js/public
Jump to navigation
Jump to search
/**
* to benefit of [[:Template:Multilingual_description]] or [[:Template:MLD]] template
* you need to load this javascript into your monobook.js
* by putting in it
*
* importScript('MediaWiki:Multilingual description.js');
*
*
* Implements language selection for multilingual elements
*
* In certain environments, it's not feasible to neatly box away each
* different language into its own section of the site. By marking elements
* multilingual, you can emulate this behavior by only displaying the
* message in the user's language. This reduced the "Tower of Babel" effect.
*
* @author Edward Z. Yang (Ambush Commander)
* @version $Id: language_select.js 1358 2007-02-19 15:34:59Z Edward $
* Changes performed since:
* - Transformed the form to have only one button with a text that alternates.
* - Fixed multiples forms being loaded if several multilingual div were in the page.
* - Multiples linguistic templates eg: {{en|text1...}} {{en|text2...}} are taken into account correctly.
* - The inline bug is fixed. See http://commons.wikimedia.org/w/index.php?title=Commons:Help_desk&diff=next&oldid=18063001#Adding_language-specific_captions_to_images for the description of the issue.
*/
// logging facitily
function appendErro(str){
// throw new Error("DEBUG: "+str)
}
// disable it when putting in production
function log(str)
{
//setTimeout("appendErro('"+str+"')", 1)
}
var log_inc=0;
function loginc(str)
{
log_inc = log_inc +1;
log(log_inc + ' ' + str);
}
function logresetinc()
{
log_inc=0;
}
function getElemInfo(elem)
{
res = elem.nodeName + ' ' + elem.lang + " " ;
for (var i=0; i<elem.attributes.length ; i++)
{
if (elem.attributes[i].nodeName == 'class')
res = res + elem.attributes[i].nodeName + ": " + elem.attributes[i].nodeValue + " ";
}
for (var i=0; i<elem.childNodes.length ; i++)
{
if (elem.childNodes[i].nodeName.toUpperCase() == 'A')
res = res + elem.childNodes[i].href + " ";
}
return res;
}
/* Configuration: */
// in your monobook.js, set ls_enable = false to stop the javascript
// maybe it should be cookie configurable. However, you can achieve
// something almost to this effect through cookie settings
if(typeof ls_enable == 'undefined') ls_enable = true;
var ls_mul = 'mul' ; // code used to define that all languages must be displayed...
// the cookie name we use to stash the info.
// change this if you are porting it to another wiki!
var ls_cookie = 'commonswiki_language_js';
// link to the language select page
var ls_help_url = 'http://meta.wikimedia.org/wiki/Meta:Language_select';
// strings that are part of the widgets
var ls_string_help = {
'de': 'Sprachauswahl',
'en': 'Language select:',
'fr': 'Selecteur de langue:',
'ko': '언어 선택:',
'mk': 'Јазик:',
'nds':'Spraakutwahl:',
'nl': 'Taal',
'pl': 'Wybierz język:'
};
var ls_string_select = {
'de': 'Auswahl',
'en': 'Select',
'fr': 'Seulement ce langage',
'ko': '선택',
'mk': 'Одбери',
'nds': 'Utwählen',
'nl': 'Selecteer',
'pl': 'Wybierz'
};
var ls_string_showall = {
'de': 'Alle anzeigen',
'en': 'Show all',
'fr': 'Tous les langages',
'ko': '모두 보기',
'mk': 'Сите',
'nds': 'All wiesen',
'nl': 'Toon alles',
'pl': 'Pokaż wszystkie'
};
// define some meta-variables
var ls__first = true; // used to build the widget
var ls_g_form = false;
// node compatability fix
if (!window.Node) {
var Node = {
ELEMENT_NODE : 1,
ATTRIBUTE_NODE: 2,
TEXT_NODE: 3,
COMMENT_NODE: 8,
DOCUMENT_NODE: 9,
DOCUMENT_FRAGMENT_NODE: 11
};
}
// autodetects a browser language
function ls_getBrowserLanguage() {
return navigator.userLanguage || navigator.language || navigator.browserLanguage;
}
// grabs language from cookie
function ls_getCookieLanguage() {
var allcookies = document.cookie;
var marker = ls_cookie + '=';
var pos = allcookies.indexOf(marker);
// cookie isn't set, so no behavior defined
if (pos === -1) return null;
// cookie is set
var start = pos + marker.length;
var end = allcookies.indexOf(';', start);
if (end == -1) end = allcookies.length;
var raw = allcookies.substring(start,end);
var value = unescape(raw);
return value;
}
// sets a new language to the cookie
function ls_setCookieLanguage(language) {
var today = new Date();
var expiry = new Date(today.getUTCFullYear() + 30, 1);
document.cookie = ls_cookie + '=' + escape(language) + '; expires=' + expiry.toGMTString();
}
// deletes the cookie
function ls_deleteCookieLanguage(language) {
document.cookie = ls_cookie + '=; expires=Fri, 02-Jan-1970 00:00:00 GMT';
}
// grabs the ISO 639 language code based
// on either the browser or a supplied cookie
// return of ls_mul will display all available strings
function ls_getLanguage() {
var language = '';
// Priority:
// 1. Cookie
// 2. wgUserLanguage global variable
// 3. Browser autodetection
// grab according to cookie
language = ls_getCookieLanguage();
// grab according to wgUserLanguage if user is logged in
if (!language && window.wgUserLanguage && mw.config.get('wgUserGroups') !== null) {
language = wgUserLanguage;
}
// grab according to browser if none defined
if (!language) {
language = ls_getBrowserLanguage();
}
// inflexible: can't accept multiple languages
// remove dialect/region code, leaving only the ISO 639 code
var length;
// possible bug: supposedly the language string could be en_US
// switch to regexps when we get the chance
if ((length = language.indexOf('-')) !== -1) {
language = language.substr(0, length);
}
return language;
}
// walks all child elements and finds all elements with multilingual in them
function ls_getAllMultilingualElements(n) {
var elements = new Array();
// possible bug if we have a classname that includes the word multilingual
// but it's unlikely
if (n.className && n.className.indexOf('multilingual') != -1) {
elements = elements.concat(n);
}
var children = n.childNodes;
for(var i=0; i < children.length; i++) {
if (children[i].nodeType !== Node.ELEMENT_NODE) continue;
elements = elements.concat(ls_getAllMultilingualElements(children[i]));
}
return elements;
}
function ls_check(elem, language, language_exist ) {
// we don't care about components without language
if (!elem.lang) return;
//we ignore the components without lang or description names
if (
(elem.className.indexOf('lang') == -1)
&& (elem.className.indexOf('description') == -1)
&& (elem.className.indexOf('langlabel') == -1)
)
return;
// hiding language label when only one language is displayed and is found.
if (language_exist && (language != 'mul' )
&& (
(elem.className.indexOf('langlabel') != -1) // used by mld
|| (elem.className.indexOf('language') != -1) // used by templates like {{en|...}
)
&& (language == elem.lang ) )
{
elem.style.display ="none";
loginc('hiding ' + ' ' + getElemInfo(elem) );
return;
}
// do not hide if the language was not found or if the language is corresponding
if (!language_exist || (elem.lang == language ) )
{
elem.style.display = "";
loginc('showing ' + ' ' + getElemInfo(elem) );
}
else // hide
{
elem.style.display ="none";
loginc('hiding ' + ' ' + getElemInfo(elem) );
}
}
// walks a hash and hides all non-matching languages
function ls_check_all(lang_element_hash, language, language_exist) {
for (var i in lang_element_hash)
{
var elem = lang_element_hash[i];
ls_check(elem,language, language_exist);
containerlist = elem.getElementsByTagName('span');
for (var j in containerlist )
{
var span = containerlist[j];
ls_check(span, language, language_exist);
}
}
}
var ls_string_help_text = ls_string_help[wgUserLanguage] || ls_string_help['en'];
// build widget for changing the language cookie
function ls_buildWidget(language) {
// preventing multiple widget to be build per page
if (ls_g_form) return;
// set up the floating form
var form = document.createElement('form');
form.className = 'lang_info';
form.onsubmit = function() {
if (this.elements[1].ls_mul_flag) {
var language = ls_mul;
} else {
ls_setCookieLanguage(this.elements[0].value);
var language = this.elements[0].value;
}
ls_applyLanguageSelect(language);
return false; // don't perform action
};
form.appendSpace = function() {
this.appendChild(document.createTextNode(' '));
};
// link to language select description page
var link = document.createElement('a');
link.href = ls_help_url;
link.className = 'ls_link';
link.appendChild(document.createTextNode(ls_string_help_text));
form.appendChild(link);
form.appendSpace();
// input box for the language
var input = document.createElement('input');
input.setAttribute('type', 'text');
input.setAttribute('size', '2');
input.setAttribute('maxlength', '3');
input.onclick = function() { this.select(); };
input.className = 'ls_input';
input.value = language;
form.appendChild(input);
form.appendSpace();
// save button
var submit = document.createElement('input');
submit.setAttribute('type', 'submit');
submit.value = ls_string_showall[wgUserLanguage] || ls_string_showall['en'];
submit.className = 'ls_select';
submit.onclick = function() {
if (this.ls_mul_flag)
{
submit.value = ls_string_showall[wgUserLanguage] || ls_string_showall['en'];
}
else
{
submit.value = ls_string_select[wgUserLanguage] || ls_string_select['en'];
}
this.ls_mul_flag = !(this.ls_mul_flag);
};
form.appendChild(submit);
var bc = document.getElementById('bodyContent');
var f = document.getElementById('file');
if (f != null) { f.appendChild(form); } else { bc.insertBefore(form, bc.childNodes[0]); }
ls_g_form = form;
ls_g_form.elements[1].ls_mul_flag = false;
}
var mls;
// main body of the function
function ls_applyLanguageSelect(language) {
// possible site for cookie checking to disable language select
if (!ls_enable) return;
//disabling the gadget on special pages
if(mw.config.get('wgCanonicalNamespace') == "Special") return;
// only activated in view , purge, historysubmit or submit mode
if (!( (mw.config.get('wgAction') == 'view')
|| (mw.config.get('wgAction') == 'purge')
|| (mw.config.get('wgAction') == 'edit')
|| (mw.config.get('wgAction') == 'historysubmit')
|| (mw.config.get('wgAction') == 'submit')
))
return;
// if language is blank, delete the cookie and then recalculate
if (!language) {
log('language is blank, deleting cookie');
ls_deleteCookieLanguage();
language = ls_getLanguage();
}
// grab the body element (only one)
var body = document.getElementsByTagName('body')[0];
// grab an array of multilingual elements
mls = ls_getAllMultilingualElements(body);
// Only build form if there are MLDs on page. Without this check the form is put on all pages.
if (mls && mls.constructor==Array && mls.length==0)
{
return;
}
// if it's the first iteration...
if (ls__first)
{
ls_buildWidget(language);
ls__first = false;
}
log('language detected: ' + language);
logresetinc();
// this will get overwritten many times,
var language_element_hash;
// update widget if the language is not set to ls_mul
if (language != ls_mul)
ls_g_form.elements[0].value = language;
// iterate through all those elements
for (var i = 0; i < mls.length; i++) {
var ml = mls[i]; // the current multilingual container
var ml_c = ml.childNodes; // children of the container
// variable used to check if the target language was found
// this is used to not hide if the language target was not found
// (eg: no fr version if you are browsing all fr will show all versions available.)
var language_exists = false;
// checking ml.parentNode to verify if it is not of type 'image_annotation_content'; this allows to not handle the mld div inside annotation.
if (ml.parentNode.className.indexOf('image_annotation_content')==-1)
{
// iterate through all languages and set up a hash
// with references to each of the language nodes
lang_element_hash = new Object();
for (var j = 0; j < ml_c.length; j++)
{
var n = ml_c[j];
if (n.nodeType != Node.ELEMENT_NODE) continue; // skip non-elements
if (n.lang.indexOf(language) === 0)
{ // it turns out our language is here
language_exists = true;
}
lang_element_hash[j] = n;
}
ls_check_all(lang_element_hash, language,language_exists);
}
}
log('mls length: ' + mls.length );
}
function ls_applyDefaultLanguageSelect() {
ls_applyLanguageSelect(ls_getLanguage(), false);
}
// register as onload function
$(ls_applyDefaultLanguageSelect);