From 931c31c7bddc2781702fb9ca3ea2626681231a78 Mon Sep 17 00:00:00 2001 From: Santhosh Thottingal Date: Mon, 2 Apr 2012 18:31:10 +0530 Subject: [PATCH] (bug 33658) support for {{GRAMMAR:}} in jqueryMsg This add GRAMMAR support to the mediawiki.jqueryMsg module: 1. make jqueryMsg understand GRAMMAR(case insensitive) 2. mw.language get convertGrammar, can be overridden per language as in php 3. Introduce resourceloader module ResourceLoaderLanguageDataModule 4. Language.php get a method to filter wgGrammerForms for the current contentLanguage. 5. Qunit tests 6. This code was originally written in jsgrammar branch of svn and had reviewed during the last slush time. Change-Id: I90dd0b2f0cb30fd30539896c292829adc4fc7364 --- includes/AutoLoader.php | 1 + .../ResourceLoaderLanguageDataModule.php | 79 +++++++++++++++++++ languages/Language.php | 13 ++- resources/Resources.php | 3 + .../mediawiki.language/mediawiki.language.js | 68 +++++++++++++++- resources/mediawiki/mediawiki.jqueryMsg.js | 13 ++- .../mediawiki/mediawiki.jqueryMsg.test.js | 12 +++ 7 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 includes/resourceloader/ResourceLoaderLanguageDataModule.php diff --git a/includes/AutoLoader.php b/includes/AutoLoader.php index eaeda494ee..a1bbc3c0aa 100644 --- a/includes/AutoLoader.php +++ b/includes/AutoLoader.php @@ -739,6 +739,7 @@ $wgAutoloadLocalClasses = array( 'ResourceLoaderUserModule' => 'includes/resourceloader/ResourceLoaderUserModule.php', 'ResourceLoaderUserOptionsModule' => 'includes/resourceloader/ResourceLoaderUserOptionsModule.php', 'ResourceLoaderUserTokensModule' => 'includes/resourceloader/ResourceLoaderUserTokensModule.php', + 'ResourceLoaderLanguageDataModule' => 'includes/resourceloader/ResourceLoaderLanguageDataModule.php', 'ResourceLoaderWikiModule' => 'includes/resourceloader/ResourceLoaderWikiModule.php', # includes/revisiondelete diff --git a/includes/resourceloader/ResourceLoaderLanguageDataModule.php b/includes/resourceloader/ResourceLoaderLanguageDataModule.php new file mode 100644 index 0000000000..e1d6fb4461 --- /dev/null +++ b/includes/resourceloader/ResourceLoaderLanguageDataModule.php @@ -0,0 +1,79 @@ +getGrammarForms(); + } + + /** + * @param $context ResourceLoaderContext + * @return string Javascript code + */ + public function getScript( ResourceLoaderContext $context ) { + global $wgContLang; + + return Xml::encodeJsCall( 'mw.language.setData', array( + $wgContLang->getCode(), + array( 'grammarForms' => $this->getSiteLangGrammarForms() ) + ) ); + } + + /** + * @param $context ResourceLoaderContext + * @return array|int|Mixed + */ + public function getModifiedTime( ResourceLoaderContext $context ) { + $cache = wfGetCache( CACHE_ANYTHING ); + $key = wfMemcKey( 'resourceloader', 'langdatamodule', 'changeinfo' ); + + $forms = $this->getSiteLangGrammarForms(); + $hash = md5( serialize( $forms ) ); + + $result = $cache->get( $key ); + if ( is_array( $result ) ) { + if ( $result['hash'] === $hash ) { + return $result['timestamp']; + } + } + $timestamp = wfTimestamp(); + $cache->set( $key, array( 'hash' => $hash, 'timestamp' => $timestamp ) ); + return $timestamp; + } + + /** + * @return array + */ + public function getDependencies() { + return array( 'mediawiki.language' ); + } +} diff --git a/languages/Language.php b/languages/Language.php index 8db7e843cb..463ea19062 100644 --- a/languages/Language.php +++ b/languages/Language.php @@ -3233,7 +3233,18 @@ class Language { } return $word; } - + /** + * Get the grammar forms for the content language + * @return array of grammar forms + * @since 1.20 + */ + function getGrammarForms() { + global $wgGrammarForms; + if ( isset( $wgGrammarForms[$this->getCode()] ) && is_array( $wgGrammarForms[$this->getCode()] ) ) { + return $wgGrammarForms[$this->getCode()]; + } + return array(); + } /** * Provides an alternative text depending on specified gender. * Usage {{gender:username|masculine|feminine|neutral}}. diff --git a/resources/Resources.php b/resources/Resources.php index b891a1fdcf..2855f9ab7b 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -21,6 +21,9 @@ return array( 'user.options' => array( 'class' => 'ResourceLoaderUserOptionsModule' ), 'user.tokens' => array( 'class' => 'ResourceLoaderUserTokensModule' ), + // Scripts for the dynamic language specific data, like grammar forms. + 'mediawiki.language.data' => array( 'class' => 'ResourceLoaderLanguageDataModule' ), + /* Skins */ 'skins.chick' => array( diff --git a/resources/mediawiki.language/mediawiki.language.js b/resources/mediawiki.language/mediawiki.language.js index 4abfa4ba28..67b605cc8a 100644 --- a/resources/mediawiki.language/mediawiki.language.js +++ b/resources/mediawiki.language/mediawiki.language.js @@ -7,7 +7,52 @@ */ ( function( $, mw ) { -mw.language = { +var language = { + /** + * @var data {Object} Language related data (keyed by language, + * contains instances of mw.Map). + * @example Set data + * + * // Override, extend or create the language data object of 'nl' + * mw.language.setData( 'nl', 'myKey', 'My value' ); + * + * @example Get GrammarForms data for language 'nl': + * + * var grammarForms = mw.language.getData( 'nl', 'grammarForms' ); + * + */ + data: {}, + + /** + * Convenience method for retreiving language data by language code and data key, + * covering for the potential inexistance of a data object for this langiage. + * @param langCode {String} + * @param dataKey {String} + * @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 = language.data; + if ( langData[langCode] instanceof mw.Map ) { + return langData[langCode].get( dataKey ); + } + return undefined; + }, + + /** + * Convenience method for setting language data by language code and data key. + * Creates a data object if there isn't one for the specified language already. + * @param langCode {String} + * @param dataKey {String} + * @param value {mixed} + */ + setData: function ( langCode, dataKey, value ) { + var langData = language.data; + if ( !( langData[langCode] instanceof mw.Map ) ) { + langData[langCode] = new mw.Map(); + } + langData[langCode].set( dataKey, value ); + }, /** * Process the PLURAL template substitution * @@ -122,7 +167,28 @@ mw.language = { 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 grammar + * forms can be computed dynamically by overriding this method per language + * + * @param word {String} + * @param form {String} + * @return {String} + */ + convertGrammar: function ( word, form ) { + var grammarForms = language.getData( mw.config.get( 'wgContentLanguage' ), 'grammarForms' ); + if ( grammarForms && grammarForms[form] ) { + return grammarForms[form][word] || word; + } + return word; + }, + // Digit Transform Table, populated by language classes where applicable 'digitTransformTable': null }; + +mw.language = language; + } )( jQuery, mediaWiki ); diff --git a/resources/mediawiki/mediawiki.jqueryMsg.js b/resources/mediawiki/mediawiki.jqueryMsg.js index 3e33bde9a5..043ebcee0f 100644 --- a/resources/mediawiki/mediawiki.jqueryMsg.js +++ b/resources/mediawiki/mediawiki.jqueryMsg.js @@ -664,8 +664,19 @@ } var forms = nodes.slice(1); return this.language.gender( gender, forms ); - } + }, + /** + * Transform parsed structure into grammar conversion. + * Invoked by putting {{grammar:form|word}} in a message + * @param {Array} of nodes [{Grammar case eg: genitive}, {String word}] + * @return {String} selected grammatical form according to current language + */ + grammar: function( nodes ) { + var form = nodes[0]; + var word = nodes[1]; + return word && form && this.language.convertGrammar( word, form ); + } }; // deprecated! don't rely on gM existing. diff --git a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js index 265ec2ae53..2abe016a22 100644 --- a/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js +++ b/tests/qunit/suites/resources/mediawiki/mediawiki.jqueryMsg.test.js @@ -41,3 +41,15 @@ test( 'mw.jqueryMsg Gender', function() { ok( mw.messages.set( 'gender-msg-wrong', '{{gender}} is awesome' ), 'mw.messages.set: Register' ); equal( parser( 'gender-msg-wrong', 'female' ) , ' is awesome', 'Wrong syntax used, but ignore the {{gender}}' ); } ); + + +test( 'mw.jqueryMsg Grammar', function() { + expect( 5 ); + var parser = mw.jqueryMsg.getMessageFunction(); + ok( parser, 'Parser Function initialized' ); + // Hope the grammar form grammar_case_foo is not valid in any language + ok( mw.messages.set( 'grammar-msg', 'Przeszukaj {{GRAMMAR:grammar_case_foo|{{SITENAME}}}}' ), 'mw.messages.set: Register' ); + equal( parser( 'grammar-msg' ) , 'Przeszukaj ' + mw.config.get( 'wgSiteName' ) , 'Grammar Test with sitename' ); + ok( mw.messages.set( 'grammar-msg-wrong-syntax', 'Przeszukaj {{GRAMMAR:grammar_case_xyz}}' ), 'mw.messages.set: Register' ); + equal( parser( 'grammar-msg-wrong-syntax' ) , 'Przeszukaj ' , 'Grammar Test with wrong grammar template syntax' ); +} ); -- 2.20.1