From c1f9b1f7b1b77776192048005dcc66dcf3df2bfb Mon Sep 17 00:00:00 2001 From: Pierre Schmitz Date: Sat, 27 Dec 2014 15:41:37 +0100 Subject: Update to MediaWiki 1.24.1 --- resources/src/mediawiki.language/languages/bs.js | 19 ++ resources/src/mediawiki.language/languages/dsb.js | 19 ++ resources/src/mediawiki.language/languages/fi.js | 47 ++++ resources/src/mediawiki.language/languages/ga.js | 38 +++ resources/src/mediawiki.language/languages/he.js | 29 +++ resources/src/mediawiki.language/languages/hsb.js | 19 ++ resources/src/mediawiki.language/languages/hu.js | 23 ++ resources/src/mediawiki.language/languages/hy.js | 29 +++ resources/src/mediawiki.language/languages/la.js | 50 ++++ resources/src/mediawiki.language/languages/os.js | 69 ++++++ resources/src/mediawiki.language/languages/ru.js | 57 +++++ resources/src/mediawiki.language/languages/sl.js | 19 ++ resources/src/mediawiki.language/languages/uk.js | 37 +++ resources/src/mediawiki.language/mediawiki.cldr.js | 32 +++ .../mediawiki.language.fallback.js | 35 +++ .../mediawiki.language/mediawiki.language.init.js | 81 +++++++ .../src/mediawiki.language/mediawiki.language.js | 171 ++++++++++++++ .../mediawiki.language.months.js | 56 +++++ .../mediawiki.language.numbers.js | 258 +++++++++++++++++++++ 19 files changed, 1088 insertions(+) create mode 100644 resources/src/mediawiki.language/languages/bs.js create mode 100644 resources/src/mediawiki.language/languages/dsb.js create mode 100644 resources/src/mediawiki.language/languages/fi.js create mode 100644 resources/src/mediawiki.language/languages/ga.js create mode 100644 resources/src/mediawiki.language/languages/he.js create mode 100644 resources/src/mediawiki.language/languages/hsb.js create mode 100644 resources/src/mediawiki.language/languages/hu.js create mode 100644 resources/src/mediawiki.language/languages/hy.js create mode 100644 resources/src/mediawiki.language/languages/la.js create mode 100644 resources/src/mediawiki.language/languages/os.js create mode 100644 resources/src/mediawiki.language/languages/ru.js create mode 100644 resources/src/mediawiki.language/languages/sl.js create mode 100644 resources/src/mediawiki.language/languages/uk.js create mode 100644 resources/src/mediawiki.language/mediawiki.cldr.js create mode 100644 resources/src/mediawiki.language/mediawiki.language.fallback.js create mode 100644 resources/src/mediawiki.language/mediawiki.language.init.js create mode 100644 resources/src/mediawiki.language/mediawiki.language.js create mode 100644 resources/src/mediawiki.language/mediawiki.language.months.js create mode 100644 resources/src/mediawiki.language/mediawiki.language.numbers.js (limited to 'resources/src/mediawiki.language') diff --git a/resources/src/mediawiki.language/languages/bs.js b/resources/src/mediawiki.language/languages/bs.js new file mode 100644 index 00000000..b56e4b29 --- /dev/null +++ b/resources/src/mediawiki.language/languages/bs.js @@ -0,0 +1,19 @@ +/*! + * Bosnian (bosanski) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'bs', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'instrumental': // instrumental + word = 's ' + word; + break; + case 'lokativ': // locative + word = 'o ' + word; + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/dsb.js b/resources/src/mediawiki.language/languages/dsb.js new file mode 100644 index 00000000..69c36cc0 --- /dev/null +++ b/resources/src/mediawiki.language/languages/dsb.js @@ -0,0 +1,19 @@ +/*! + * Lower Sorbian (Dolnoserbski) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'dsb', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'instrumental': // instrumental + word = 'z ' + word; + break; + case 'lokatiw': // lokatiw + word = 'wo ' + word; + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/fi.js b/resources/src/mediawiki.language/languages/fi.js new file mode 100644 index 00000000..453a675d --- /dev/null +++ b/resources/src/mediawiki.language/languages/fi.js @@ -0,0 +1,47 @@ +/*! + * Finnish (Suomi) language functions + * @author Santhosh Thottingal + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms, aou, origWord; + + grammarForms = mediaWiki.language.getData( 'fi', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + + // vowel harmony flag + aou = word.match( /[aou][^äöy]*$/i ); + origWord = word; + if ( word.match( /wiki$/i ) ) { + aou = false; + } + //append i after final consonant + if ( word.match( /[bcdfghjklmnpqrstvwxz]$/i ) ) { + word += 'i'; + } + + switch ( form ) { + case 'genitive': + word += 'n'; + break; + case 'elative': + word += ( aou ? 'sta' : 'stä' ); + break; + case 'partitive': + word += ( aou ? 'a' : 'ä' ); + break; + case 'illative': + // Double the last letter and add 'n' + word += word.slice( -1 ) + 'n'; + break; + case 'inessive': + word += ( aou ? 'ssa' : 'ssä' ); + break; + default: + word = origWord; + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/ga.js b/resources/src/mediawiki.language/languages/ga.js new file mode 100644 index 00000000..fb4e9396 --- /dev/null +++ b/resources/src/mediawiki.language/languages/ga.js @@ -0,0 +1,38 @@ +/*! + * Irish (Gaeilge) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + /*jshint onecase:true */ + var grammarForms = mediaWiki.language.getData( 'ga', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'ainmlae': + switch ( word ) { + case 'an Domhnach': + word = 'Dé Domhnaigh'; + break; + case 'an Luan': + word = 'Dé Luain'; + break; + case 'an Mháirt': + word = 'Dé Mháirt'; + break; + case 'an Chéadaoin': + word = 'Dé Chéadaoin'; + break; + case 'an Déardaoin': + word = 'Déardaoin'; + break; + case 'an Aoine': + word = 'Dé hAoine'; + break; + case 'an Satharn': + word = 'Dé Sathairn'; + break; + } + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/he.js b/resources/src/mediawiki.language/languages/he.js new file mode 100644 index 00000000..d1eba43b --- /dev/null +++ b/resources/src/mediawiki.language/languages/he.js @@ -0,0 +1,29 @@ +/*! + * Hebrew (עברית) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'he', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'prefixed': + case 'תחילית': // the same word in Hebrew + // Duplicate prefixed "Waw", but only if it's not already double + if ( word.slice( 0, 1 ) === 'ו' && word.slice( 0, 2 ) !== 'וו' ) { + word = 'ו' + word; + } + + // Remove the "He" if prefixed + if ( word.slice( 0, 1 ) === 'ה' ) { + word = word.slice( 1 ); + } + + // Add a hyphen (maqaf) before numbers and non-Hebrew letters + if ( word.slice( 0, 1 ) < 'א' || word.slice( 0, 1 ) > 'ת' ) { + word = '־' + word; + } + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/hsb.js b/resources/src/mediawiki.language/languages/hsb.js new file mode 100644 index 00000000..2d6b733e --- /dev/null +++ b/resources/src/mediawiki.language/languages/hsb.js @@ -0,0 +1,19 @@ +/*! + * Upper Sorbian (Hornjoserbsce) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'hsb', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'instrumental': // instrumental + word = 'z ' + word; + break; + case 'lokatiw': // lokatiw + word = 'wo ' + word; + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/hu.js b/resources/src/mediawiki.language/languages/hu.js new file mode 100644 index 00000000..d72a1c05 --- /dev/null +++ b/resources/src/mediawiki.language/languages/hu.js @@ -0,0 +1,23 @@ +/*! + * Hungarian language functions + * @author Santhosh Thottingal + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'hu', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'rol': + word += 'ról'; + break; + case 'ba': + word += 'ba'; + break; + case 'k': + word += 'k'; + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/hy.js b/resources/src/mediawiki.language/languages/hy.js new file mode 100644 index 00000000..9cae360b --- /dev/null +++ b/resources/src/mediawiki.language/languages/hy.js @@ -0,0 +1,29 @@ +/*! + * Armenian (Հայերեն) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + /*jshint onecase:true */ + var grammarForms = mediaWiki.language.getData( 'hy', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + + // These rules are not perfect, but they are currently only used for site names so it doesn't + // matter if they are wrong sometimes. Just add a special case for your site name if necessary. + + switch ( form ) { + case 'genitive': // սեռական հոլով + if ( word.slice( -1 ) === 'ա' ) { + word = word.slice( 0, -1 ) + 'այի'; + } else if ( word.slice( -1 ) === 'ո' ) { + word = word.slice( 0, -1 ) + 'ոյի'; + } else if ( word.slice( -4 ) === 'գիրք' ) { + word = word.slice( 0, -4 ) + 'գրքի'; + } else { + word = word + 'ի'; + } + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/la.js b/resources/src/mediawiki.language/languages/la.js new file mode 100644 index 00000000..52e8dd44 --- /dev/null +++ b/resources/src/mediawiki.language/languages/la.js @@ -0,0 +1,50 @@ +/*! + * Latin (lingua Latina) language functions + * @author Santhosh Thottingal + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'la', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'genitive': + // only a few declensions, and even for those mostly the singular only + word = word.replace( /u[ms]$/i, 'i' ); // 2nd declension singular + word = word.replace( /ommunia$/i, 'ommunium' ); // 3rd declension neuter plural (partly) + word = word.replace( /a$/i, 'ae' ); // 1st declension singular + word = word.replace( /libri$/i, 'librorum' ); // 2nd declension plural (partly) + word = word.replace( /nuntii$/i, 'nuntiorum' ); // 2nd declension plural (partly) + word = word.replace( /tio$/i, 'tionis' ); // 3rd declension singular (partly) + word = word.replace( /ns$/i, 'ntis' ); + word = word.replace( /as$/i, 'atis' ); + word = word.replace( /es$/i, 'ei' ); // 5th declension singular + break; + case 'accusative': + // only a few declensions, and even for those mostly the singular only + word = word.replace( /u[ms]$/i, 'um' ); // 2nd declension singular + word = word.replace( /ommunia$/i, 'am' ); // 3rd declension neuter plural (partly) + word = word.replace( /a$/i, 'ommunia' ); // 1st declension singular + word = word.replace( /libri$/i, 'libros' ); // 2nd declension plural (partly) + word = word.replace( /nuntii$/i, 'nuntios' );// 2nd declension plural (partly) + word = word.replace( /tio$/i, 'tionem' ); // 3rd declension singular (partly) + word = word.replace( /ns$/i, 'ntem' ); + word = word.replace( /as$/i, 'atem'); + word = word.replace( /es$/i, 'em' ); // 5th declension singular + break; + case 'ablative': + // only a few declensions, and even for those mostly the singular only + word = word.replace( /u[ms]$/i, 'o' ); // 2nd declension singular + word = word.replace( /ommunia$/i, 'ommunibus' ); // 3rd declension neuter plural (partly) + word = word.replace( /a$/i, 'a' ); // 1st declension singular + word = word.replace( /libri$/i, 'libris' ); // 2nd declension plural (partly) + word = word.replace( /nuntii$/i, 'nuntiis' ); // 2nd declension plural (partly) + word = word.replace( /tio$/i, 'tione' ); // 3rd declension singular (partly) + word = word.replace( /ns$/i, 'nte' ); + word = word.replace( /as$/i, 'ate'); + word = word.replace( /es$/i, 'e' ); // 5th declension singular + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/os.js b/resources/src/mediawiki.language/languages/os.js new file mode 100644 index 00000000..787be36d --- /dev/null +++ b/resources/src/mediawiki.language/languages/os.js @@ -0,0 +1,69 @@ +/*! + * Ossetian (Ирон) language functions + * @author Santhosh Thottingal + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'os', 'grammarForms' ), + // Ending for allative case + endAllative = 'мæ', + // Variable for 'j' beetwen vowels + jot = '', + // Variable for "-" for not Ossetic words + hyphen = '', + // Variable for ending + ending = ''; + + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + // Checking if the $word is in plural form + if ( word.match( /тæ$/i ) ) { + word = word.slice( 0, -1 ); + endAllative = 'æм'; + } + // Works if word is in singular form. + // Checking if word ends on one of the vowels: е, ё, и, о, ы, э, ю, я. + else if ( word.match( /[аæеёиоыэюя]$/i ) ) { + jot = 'й'; + } + // Checking if word ends on 'у'. 'У' can be either consonant 'W' or vowel 'U' in cyrillic Ossetic. + // Examples: {{grammar:genitive|аунеу}} = аунеуы, {{grammar:genitive|лæппу}} = лæппуйы. + else if ( word.match( /у$/i ) ) { + if ( !word.slice( -2, -1 ).match( /[аæеёиоыэюя]$/i ) ) { + jot = 'й'; + } + } else if ( !word.match( /[бвгджзйклмнопрстфхцчшщьъ]$/i ) ) { + hyphen = '-'; + } + + switch ( form ) { + case 'genitive': + ending = hyphen + jot + 'ы'; + break; + case 'dative': + ending = hyphen + jot + 'æн'; + break; + case 'allative': + ending = hyphen + endAllative; + break; + case 'ablative': + if ( jot === 'й' ) { + ending = hyphen + jot + 'æ'; + } + else { + ending = hyphen + jot + 'æй'; + } + break; + case 'superessive': + ending = hyphen + jot + 'ыл'; + break; + case 'equative': + ending = hyphen + jot + 'ау'; + break; + case 'comitative': + ending = hyphen + 'имæ'; + break; + } + return word + ending; +}; diff --git a/resources/src/mediawiki.language/languages/ru.js b/resources/src/mediawiki.language/languages/ru.js new file mode 100644 index 00000000..2077b6be --- /dev/null +++ b/resources/src/mediawiki.language/languages/ru.js @@ -0,0 +1,57 @@ +/*! + * Russian (Русский) language functions + */ + +// These tests were originally made for names of Wikimedia +// websites, so they don't currently cover all the possible +// cases. + +mediaWiki.language.convertGrammar = function ( word, form ) { + 'use strict'; + + var grammarForms = mediaWiki.language.getData( 'ru', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'genitive': // родительный падеж + if ( word.slice( -1 ) === 'ь' ) { + word = word.slice( 0, -1 ) + 'я'; + } else if ( word.slice( -2 ) === 'ия' ) { + word = word.slice( 0, -2 ) + 'ии'; + } else if ( word.slice( -2 ) === 'ка' ) { + word = word.slice( 0, -2 ) + 'ки'; + } else if ( word.slice( -2 ) === 'ти' ) { + word = word.slice( 0, -2 ) + 'тей'; + } else if ( word.slice( -2 ) === 'ды' ) { + word = word.slice( 0, -2 ) + 'дов'; + } else if ( word.slice( -1 ) === 'д' ) { + word = word.slice( 0, -1 ) + 'да'; + } else if ( word.slice( -3 ) === 'ные' ) { + word = word.slice( 0, -3 ) + 'ных'; + } else if ( word.slice( -3 ) === 'ник' ) { + word = word.slice( 0, -3 ) + 'ника'; + } + break; + case 'prepositional': // предложный падеж + if ( word.slice( -1 ) === 'ь' ) { + word = word.slice( 0, -1 ) + 'е'; + } else if ( word.slice( -2 ) === 'ия' ) { + word = word.slice( 0, -2 ) + 'ии'; + } else if ( word.slice( -2 ) === 'ка' ) { + word = word.slice( 0, -2 ) + 'ке'; + } else if ( word.slice( -2 ) === 'ти' ) { + word = word.slice( 0, -2 ) + 'тях'; + } else if ( word.slice( -2 ) === 'ды' ) { + word = word.slice( 0, -2 ) + 'дах'; + } else if ( word.slice( -1 ) === 'д' ) { + word = word.slice( 0, -1 ) + 'де'; + } else if ( word.slice( -3 ) === 'ные' ) { + word = word.slice( 0, -3 ) + 'ных'; + } else if ( word.slice( -3 ) === 'ник' ) { + word = word.slice( 0, -3 ) + 'нике'; + } + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/sl.js b/resources/src/mediawiki.language/languages/sl.js new file mode 100644 index 00000000..d20d0b34 --- /dev/null +++ b/resources/src/mediawiki.language/languages/sl.js @@ -0,0 +1,19 @@ +/*! + * Slovenian (Slovenščina) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'sl', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'mestnik': // locative + word = 'o ' + word; + break; + case 'orodnik': // instrumental + word = 'z ' + word; + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/languages/uk.js b/resources/src/mediawiki.language/languages/uk.js new file mode 100644 index 00000000..550a388c --- /dev/null +++ b/resources/src/mediawiki.language/languages/uk.js @@ -0,0 +1,37 @@ +/*! + * Ukrainian (Українська) language functions + */ + +mediaWiki.language.convertGrammar = function ( word, form ) { + var grammarForms = mediaWiki.language.getData( 'uk', 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word]; + } + switch ( form ) { + case 'genitive': // родовий відмінок + if ( word.slice( -4 ) !== 'вікі' && word.slice( -4 ) !== 'Вікі' ) { + if ( word.slice( -1 ) === 'ь' ) { + word = word.slice(0, -1 ) + 'я'; + } else if ( word.slice( -2 ) === 'ія' ) { + word = word.slice(0, -2 ) + 'ії'; + } else if ( word.slice( -2 ) === 'ка' ) { + word = word.slice(0, -2 ) + 'ки'; + } else if ( word.slice( -2 ) === 'ти' ) { + word = word.slice(0, -2 ) + 'тей'; + } else if ( word.slice( -2 ) === 'ды' ) { + word = word.slice(0, -2 ) + 'дов'; + } else if ( word.slice( -3 ) === 'ник' ) { + word = word.slice(0, -3 ) + 'ника'; + } + } + break; + case 'accusative': // знахідний відмінок + if ( word.slice( -4 ) !== 'вікі' && word.slice( -4 ) !== 'Вікі' ) { + if ( word.slice( -2 ) === 'ія' ) { + word = word.slice(0, -2 ) + 'ію'; + } + } + break; + } + return word; +}; diff --git a/resources/src/mediawiki.language/mediawiki.cldr.js b/resources/src/mediawiki.language/mediawiki.cldr.js new file mode 100644 index 00000000..f6fb8f10 --- /dev/null +++ b/resources/src/mediawiki.language/mediawiki.cldr.js @@ -0,0 +1,32 @@ +( function ( mw ) { + 'use strict'; + + /** + * Namespace for CLDR-related utility methods. + * + * @class + * @singleton + */ + mw.cldr = { + /** + * Get the plural form index for the number. + * + * In case none of the rules passed, we return `pluralRules.length` - + * that means it is the "other" form. + * + * @param {number} number + * @param {Array} pluralRules + * @return {number} plural form index + */ + getPluralForm: function ( number, pluralRules ) { + var i; + for ( i = 0; i < pluralRules.length; i++ ) { + if ( mw.libs.pluralRuleParser( pluralRules[i], number ) ) { + break; + } + } + return i; + } + }; + +}( mediaWiki ) ); diff --git a/resources/src/mediawiki.language/mediawiki.language.fallback.js b/resources/src/mediawiki.language/mediawiki.language.fallback.js new file mode 100644 index 00000000..b1bab02a --- /dev/null +++ b/resources/src/mediawiki.language/mediawiki.language.fallback.js @@ -0,0 +1,35 @@ +/* + * Language-fallback-chain-related utilities for mediawiki.language. + */ +( function ( mw, $ ) { + /** + * @class mw.language + */ + + $.extend( mw.language, { + + /** + * Get the language fallback chain for current UI language (not including the language itself). + * + * @return {string[]} List of language keys, e.g. `['de', 'en']` + */ + getFallbackLanguages: function () { + return mw.language.getData( + mw.config.get( 'wgUserLanguage' ), + 'fallbackLanguages' + ) || []; + }, + + /** + * Get the language fallback chain for current UI language, including the language itself. + * + * @return {string[]} List of language keys, e.g. `['pfl', de', 'en']` + */ + getFallbackLanguageChain: function () { + return [ mw.config.get( 'wgUserLanguage' ) ] + .concat( mw.language.getFallbackLanguages() ); + } + + } ); + +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.language/mediawiki.language.init.js b/resources/src/mediawiki.language/mediawiki.language.init.js new file mode 100644 index 00000000..df95d751 --- /dev/null +++ b/resources/src/mediawiki.language/mediawiki.language.init.js @@ -0,0 +1,81 @@ +( function ( mw ) { + /** + * Base language object with methods related to language support, attempting to mirror some of the + * functionality of the Language class in MediaWiki: + * + * - storing and retrieving language data + * - transforming message syntax (`{{PLURAL:}}`, `{{GRAMMAR:}}`, `{{GENDER:}}`) + * - formatting numbers + * + * @class + * @singleton + */ + mw.language = { + /** + * Language-related data (keyed by language, contains instances of mw.Map). + * Loaded dynamically (see ResourceLoaderLanguageDataModule class in PHP, registered + * as mediawiki.language.data on the client). + * + * To set data: + * + * // Override, extend or create the language data object of 'nl' + * mw.language.setData( 'nl', 'myKey', 'My value' ); + * + * // Set multiple key/values pairs at once + * mw.language.setData( 'nl', { foo: 'X', bar: 'Y' } ); + * + * To get GrammarForms data for language 'nl': + * + * var grammarForms = mw.language.getData( 'nl', 'grammarForms' ); + * + * Possible data keys: + * + * - `digitTransformTable` + * - `separatorTransformTable` + * - `grammarForms` + * - `pluralRules` + * - `digitGroupingPattern` + * - `fallbackLanguages` + * + * @property + */ + data: {}, + + /** + * Convenience method for retrieving language data. + * + * Structured by language code and data key, covering for the potential inexistence of a + * data object for this language. + * + * @param {string} langCode + * @param {string} dataKey + * @return {Mixed} Value stored in the mw.Map (or `undefined` if there is no map for the + * specified langCode) + */ + getData: function ( langCode, dataKey ) { + var langData = mw.language.data; + if ( langData && langData[langCode] instanceof mw.Map ) { + return langData[langCode].get( dataKey ); + } + return undefined; + }, + + /** + * Convenience method for setting language data. + * + * Creates the data mw.Map if there isn't one for the specified language already. + * + * @param {string} langCode + * @param {string|Object} dataKey Key or object of key/values + * @param {Mixed} [value] Value for dataKey, omit if dataKey is an object + */ + setData: function ( langCode, dataKey, value ) { + var langData = mw.language.data; + if ( !( langData[langCode] instanceof mw.Map ) ) { + langData[langCode] = new mw.Map(); + } + langData[langCode].set( dataKey, value ); + } + }; + +}( mediaWiki ) ); diff --git a/resources/src/mediawiki.language/mediawiki.language.js b/resources/src/mediawiki.language/mediawiki.language.js new file mode 100644 index 00000000..d4f3c69e --- /dev/null +++ b/resources/src/mediawiki.language/mediawiki.language.js @@ -0,0 +1,171 @@ +/* + * Methods for transforming message syntax. + */ +( function ( mw, $ ) { + +/** + * @class mw.language + */ +$.extend( mw.language, { + + /** + * Process the PLURAL template substitution + * + * @private + * @param {Object} template Template object + * @param {string} template.title + * @param {Array} template.parameters + * @return {string} + */ + procPLURAL: function ( template ) { + if ( template.title && template.parameters && mw.language.convertPlural ) { + // Check if we have forms to replace + if ( template.parameters.length === 0 ) { + return ''; + } + // Restore the count into a Number ( if it got converted earlier ) + var count = mw.language.convertNumber( template.title, true ); + // Do convertPlural call + return mw.language.convertPlural( parseInt( count, 10 ), template.parameters ); + } + // Could not process plural return first form or nothing + if ( template.parameters[0] ) { + return template.parameters[0]; + } + return ''; + }, + + /** + * Plural form transformations, needed for some languages. + * + * @param {number} count Non-localized quantifier + * @param {Array} forms List of plural forms + * @return {string} Correct form for quantifier in this language + */ + convertPlural: function ( count, forms ) { + var pluralRules, + formCount, + form, + index, + equalsPosition, + pluralFormIndex = 0; + + if ( !forms || forms.length === 0 ) { + return ''; + } + + // Handle for explicit n= forms + for ( index = 0; index < forms.length; index++ ) { + form = forms[index]; + if ( /^\d+=/.test( form ) ) { + equalsPosition = form.indexOf( '=' ); + formCount = parseInt( form.slice( 0, equalsPosition ), 10 ); + if ( formCount === count ) { + return form.slice( equalsPosition + 1 ); + } + forms[index] = undefined; + } + } + + // Remove explicit plural forms from the forms. + forms = $.map( forms, function ( form ) { + return form; + } ); + + if ( forms.length === 0 ) { + return ''; + } + + pluralRules = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'pluralRules' ); + if ( !pluralRules ) { + // default fallback. + return ( count === 1 ) ? forms[0] : forms[1]; + } + pluralFormIndex = mw.cldr.getPluralForm( count, pluralRules ); + pluralFormIndex = Math.min( pluralFormIndex, forms.length - 1 ); + return forms[pluralFormIndex]; + }, + + /** + * Pads an array to a specific length by copying the last one element. + * + * @private + * @param {Array} forms Number of forms given to convertPlural + * @param {number} count Number of forms required + * @return {Array} Padded array of forms + */ + preConvertPlural: function ( forms, count ) { + while ( forms.length < count ) { + forms.push( forms[ forms.length - 1 ] ); + } + return forms; + }, + + /** + * Provides an alternative text depending on specified gender. + * + * Usage in message text: `{{gender:[gender|user object]|masculine|feminine|neutral}}`. + * If second or third parameter are not specified, masculine is used. + * + * These details may be overriden per language. + * + * @param {string} gender 'male', 'female', or anything else for neutral. + * @param {Array} forms List of gender forms + * @return string + */ + gender: function ( gender, forms ) { + if ( !forms || forms.length === 0 ) { + return ''; + } + forms = mw.language.preConvertPlural( forms, 2 ); + if ( gender === 'male' ) { + return forms[0]; + } + if ( gender === 'female' ) { + return forms[1]; + } + return ( forms.length === 3 ) ? forms[2] : forms[0]; + }, + + /** + * Grammatical transformations, needed for inflected languages. + * Invoked by putting `{{grammar:form|word}}` in a message. + * + * The rules can be defined in $wgGrammarForms global or computed + * dynamically by overriding this method per language. + * + * @param {string} word + * @param {string} form + * @return {string} + */ + convertGrammar: function ( word, form ) { + var grammarForms = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word] || word; + } + return word; + }, + + /** + * Turn a list of string into a simple list using commas and 'and'. + * + * See Language::listToText in languages/Language.php + * + * @param {string[]} list + * @return {string} + */ + listToText: function ( list ) { + var text = '', i = 0; + for ( ; i < list.length; i++ ) { + text += list[i]; + if ( list.length - 2 === i ) { + text += mw.msg( 'and' ) + mw.msg( 'word-separator' ); + } else if ( list.length - 1 !== i ) { + text += mw.msg( 'comma-separator' ); + } + } + return text; + } +} ); + +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.language/mediawiki.language.months.js b/resources/src/mediawiki.language/mediawiki.language.months.js new file mode 100644 index 00000000..5a1a5cb6 --- /dev/null +++ b/resources/src/mediawiki.language/mediawiki.language.months.js @@ -0,0 +1,56 @@ +/* + * Transfer of month names from messages into mw.language. + * + * Loading this module also ensures the availability of appropriate messages via mw.msg. + */ +( function ( mw, $ ) { + var + monthMessages = [ + 'january', 'february', 'march', 'april', + 'may_long', 'june', 'july', 'august', + 'september', 'october', 'november', 'december' + ], + monthGenMessages = [ + 'january-gen', 'february-gen', 'march-gen', 'april-gen', + 'may-gen', 'june-gen', 'july-gen', 'august-gen', + 'september-gen', 'october-gen', 'november-gen', 'december-gen' + ], + monthAbbrevMessages = [ + 'jan', 'feb', 'mar', 'apr', + 'may', 'jun', 'jul', 'aug', + 'sep', 'oct', 'nov', 'dec' + ]; + + // Function suitable for passing to jQuery.map + // Can't use mw.msg directly because jQuery.map passes element index as second argument + function mwMsgMapper( key ) { + return mw.msg( key ); + } + + /** + * Information about month names in current UI language. + * + * Object keys: + * + * - `names`: array of month names (in nominative case in languages which have the distinction), + * zero-indexed + * - `genitive`: array of month names in genitive case, zero-indexed + * - `abbrev`: array of three-letter-long abbreviated month names, zero-indexed + * - `keys`: object with three keys like the above, containing zero-indexed arrays of message keys + * for appropriate messages which can be passed to mw.msg. + * + * @property + * @member mw.language + */ + mw.language.months = { + keys: { + names: monthMessages, + genitive: monthGenMessages, + abbrev: monthAbbrevMessages + }, + names: $.map( monthMessages, mwMsgMapper ), + genitive: $.map( monthGenMessages, mwMsgMapper ), + abbrev: $.map( monthAbbrevMessages, mwMsgMapper ) + }; + +}( mediaWiki, jQuery ) ); diff --git a/resources/src/mediawiki.language/mediawiki.language.numbers.js b/resources/src/mediawiki.language/mediawiki.language.numbers.js new file mode 100644 index 00000000..a0b81410 --- /dev/null +++ b/resources/src/mediawiki.language/mediawiki.language.numbers.js @@ -0,0 +1,258 @@ +/* + * Number-related utilities for mediawiki.language. + */ +( function ( mw, $ ) { + /** + * @class mw.language + */ + + /** + * Pad a string to guarantee that it is at least `size` length by + * filling with the character `ch` at either the start or end of the + * string. Pads at the start, by default. + * + * Example: Fill the string to length 10 with '+' characters on the right. + * + * pad( 'blah', 10, '+', true ); // => 'blah++++++' + * + * @private + * @param {string} text The string to pad + * @param {number} size The length to pad to + * @param {string} [ch='0'] Character to pad with + * @param {boolean} [end=false] Adds padding at the end if true, otherwise pads at start + * @return {string} + */ + function pad( text, size, ch, end ) { + if ( !ch ) { + ch = '0'; + } + + var out = String( text ), + padStr = replicate( ch, Math.ceil( ( size - out.length ) / ch.length ) ); + + return end ? out + padStr : padStr + out; + } + + /** + * Replicate a string 'n' times. + * + * @private + * @param {string} str The string to replicate + * @param {number} num Number of times to replicate the string + * @return {string} + */ + function replicate( str, num ) { + if ( num <= 0 || !str ) { + return ''; + } + + var buf = []; + while ( num-- ) { + buf.push( str ); + } + return buf.join( '' ); + } + + /** + * Apply numeric pattern to absolute value using options. Gives no + * consideration to local customs. + * + * Adapted from dojo/number library with thanks + * + * + * @private + * @param {number} value the number to be formatted, ignores sign + * @param {string} pattern the number portion of a pattern (e.g. `#,##0.00`) + * @param {Object} [options] If provided, both option keys must be present: + * @param {string} options.decimal The decimal separator. Defaults to: `'.'`. + * @param {string} options.group The group separator. Defaults to: `','`. + * @return {string} + */ + function commafyNumber( value, pattern, options ) { + options = options || { + group: ',', + decimal: '.' + }; + + if ( isNaN( value) ) { + return value; + } + + var padLength, + patternDigits, + index, + whole, + off, + remainder, + patternParts = pattern.split( '.' ), + maxPlaces = ( patternParts[1] || [] ).length, + valueParts = String( Math.abs( value ) ).split( '.' ), + fractional = valueParts[1] || '', + groupSize = 0, + groupSize2 = 0, + pieces = []; + + if ( patternParts[1] ) { + // Pad fractional with trailing zeros + padLength = ( patternParts[1] && patternParts[1].lastIndexOf( '0' ) + 1 ); + + if ( padLength > fractional.length ) { + valueParts[1] = pad( fractional, padLength, '0', true ); + } + + // Truncate fractional + if ( maxPlaces < fractional.length ) { + valueParts[1] = fractional.slice( 0, maxPlaces ); + } + } else { + if ( valueParts[1] ) { + valueParts.pop(); + } + } + + // Pad whole with leading zeros + patternDigits = patternParts[0].replace( ',', '' ); + + padLength = patternDigits.indexOf( '0' ); + + if ( padLength !== -1 ) { + padLength = patternDigits.length - padLength; + + if ( padLength > valueParts[0].length ) { + valueParts[0] = pad( valueParts[0], padLength ); + } + + // Truncate whole + if ( patternDigits.indexOf( '#' ) === -1 ) { + valueParts[0] = valueParts[0].slice( valueParts[0].length - padLength ); + } + } + + // Add group separators + index = patternParts[0].lastIndexOf( ',' ); + + if ( index !== -1 ) { + groupSize = patternParts[0].length - index - 1; + remainder = patternParts[0].slice( 0, index ); + index = remainder.lastIndexOf( ',' ); + if ( index !== -1 ) { + groupSize2 = remainder.length - index - 1; + } + } + + for ( whole = valueParts[0]; whole; ) { + off = groupSize ? whole.length - groupSize : 0; + pieces.push( ( off > 0 ) ? whole.slice( off ) : whole ); + whole = ( off > 0 ) ? whole.slice( 0, off ) : ''; + + if ( groupSize2 ) { + groupSize = groupSize2; + groupSize2 = null; + } + } + valueParts[0] = pieces.reverse().join( options.group ); + + return valueParts.join( options.decimal ); + } + + $.extend( mw.language, { + + /** + * Converts a number using #getDigitTransformTable. + * + * @param {number} num Value to be converted + * @param {boolean} [integer=false] Whether to convert the return value to an integer + * @return {number|string} Formatted number + */ + convertNumber: function ( num, integer ) { + var i, tmp, transformTable, numberString, convertedNumber, pattern; + + pattern = mw.language.getData( mw.config.get( 'wgUserLanguage' ), + 'digitGroupingPattern' ) || '#,##0.###'; + + // Set the target transform table: + transformTable = mw.language.getDigitTransformTable(); + + if ( !transformTable ) { + return num; + } + + // Check if the 'restore' to Latin number flag is set: + if ( integer ) { + if ( parseInt( num, 10 ) === num ) { + return num; + } + tmp = []; + for ( i in transformTable ) { + tmp[ transformTable[ i ] ] = i; + } + transformTable = tmp; + numberString = num + ''; + } else { + numberString = mw.language.commafy( num, pattern ); + } + + convertedNumber = ''; + for ( i = 0; i < numberString.length; i++ ) { + if ( transformTable[ numberString[i] ] ) { + convertedNumber += transformTable[numberString[i]]; + } else { + convertedNumber += numberString[i]; + } + } + return integer ? parseInt( convertedNumber, 10 ) : convertedNumber; + }, + + /** + * Get the digit transform table for current UI language. + * @return {Object|Array} + */ + getDigitTransformTable: function () { + return mw.language.getData( mw.config.get( 'wgUserLanguage' ), + 'digitTransformTable' ) || []; + }, + + /** + * Get the separator transform table for current UI language. + * @return {Object|Array} + */ + getSeparatorTransformTable: function () { + return mw.language.getData( mw.config.get( 'wgUserLanguage' ), + 'separatorTransformTable' ) || []; + }, + + /** + * Apply pattern to format value as a string. + * + * Using patterns from [Unicode TR35](http://www.unicode.org/reports/tr35/#Number_Format_Patterns). + * + * @param {number} value + * @param {string} pattern Pattern string as described by Unicode TR35 + * @throws {Error} If unable to find a number expression in `pattern`. + * @return {string} + */ + commafy: function ( value, pattern ) { + var numberPattern, + transformTable = mw.language.getSeparatorTransformTable(), + group = transformTable[','] || ',', + numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/, // not precise, but good enough + decimal = transformTable['.'] || '.', + patternList = pattern.split( ';' ), + positivePattern = patternList[0]; + + pattern = patternList[ ( value < 0 ) ? 1 : 0] || ( '-' + positivePattern ); + numberPattern = positivePattern.match( numberPatternRE ); + + if ( !numberPattern ) { + throw new Error( 'unable to find a number expression in pattern: ' + pattern ); + } + + return pattern.replace( numberPatternRE, commafyNumber( value, numberPattern[0], { + decimal: decimal, + group: group + } ) ); + } + + } ); + +}( mediaWiki, jQuery ) ); -- cgit v1.2.2