Santhosh has uploaded a new change for review. https://gerrit.wikimedia.org/r/295898
Change subject: WIP: Use TemplateData to find template params in target language ...................................................................... WIP: Use TemplateData to find template params in target language This will allow us to adapt templates if target template has same name for source param names or alias to that. Also we adapt tempaltes without nameless parameters like {{foo|bar}} We are using templatedata api in target wikis for this. Change-Id: I6f71dee7d3c05964f8dfa5e49bd8a839036a6064 TODO: more testiong, unit tests --- M modules/tools/ext.cx.tools.template.js M tests/qunit/tools/ext.cx.tools.template.test.js 2 files changed, 120 insertions(+), 51 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/ContentTranslation refs/changes/98/295898/1 diff --git a/modules/tools/ext.cx.tools.template.js b/modules/tools/ext.cx.tools.template.js index 5388d82..d4a6240 100644 --- a/modules/tools/ext.cx.tools.template.js +++ b/modules/tools/ext.cx.tools.template.js @@ -11,7 +11,8 @@ 'use strict'; var targetTemplateNamespace = {}, - cachedTemplateRequests = {}; + cachedTemplateRequests = {}, + cachedTemplateDataAPIRequests = {}; /** * TemplateTool encapsulates the handling of templates in translation. @@ -22,11 +23,15 @@ * * @class */ - function TemplateTool( element ) { + function TemplateTool( element, options ) { this.$template = $( element ); this.templateData = null; this.templateTitle = null; this.templateMapping = null; + this.options = $.extend( {}, mw.cx.TemplateTool.defaults, options ); + this.siteMapper = this.options.siteMapper; + this.sourceLanguage = this.options.sourceLanguage; + this.targetLanguage = this.options.targetLanguage; } /** @@ -41,7 +46,7 @@ * Get the template data from source section. Target section * might not have it always. */ - TemplateTool.prototype.getTemplateData = function () { + TemplateTool.prototype.getSourceTemplateData = function () { var templateData, aboutAttr = this.$template.attr( 'about' ); @@ -64,19 +69,48 @@ }; /** + * [getTargetTemplateData description] + * @return {[type]} [description] + */ + TemplateTool.prototype.getTargetTemplateData = function () { + var self = this; + + if ( cachedTemplateDataAPIRequests[ this.templateTitle ] ) { + return cachedTemplateDataAPIRequests[ this.templateTitle ]; + } + + cachedTemplateDataAPIRequests[ this.templateTitle ] = + this.siteMapper.getApi( self.targetLanguage ).get( { + action: 'templatedata', + titles: 'Template:' + this.templateTitle, + redirects: true, + format: 'json' + }, { + dataType: 'jsonp', + // This prevents warnings about the unrecognized parameter "_" + cache: true + } ).then( function ( response ) { + var pageId = Object.keys( response.pages )[ 0 ]; + return response.pages[ pageId ] || {}; + } ); + + return cachedTemplateDataAPIRequests[ this.templateTitle ]; + }; + + /** * Get the namespace translation in a wiki. * Uses the canonical name for lookup. * * @param {string} language * @return {jQuery.Promise} */ - function getTemplateNamespaceTranslation( language ) { + TemplateTool.prototype.getTemplateNamespaceTranslation = function ( language ) { if ( targetTemplateNamespace[ language ] ) { return $.Deferred().resolve( targetTemplateNamespace[ language ] ).promise(); } // TODO: Refactor to avoid global reference - return mw.cx.siteMapper.getApi( language ).get( { + return this.siteMapper.getApi( language ).get( { action: 'query', meta: 'siteinfo', siprop: 'namespaces', @@ -96,29 +130,39 @@ } } } ); - } + }; /** * Get the template mapping if any set by source.filter module */ TemplateTool.prototype.getTemplateMapping = function () { - return this.$template.data( 'template-mapping' ); + var self = this; + return this.getTargetTemplateData().then( function ( templateData ) { + templateData.cxMapping = self.$template.data( 'template-mapping' ) || {}; + return templateData; + } ); }; /** * Adapt a template using template mapping */ TemplateTool.prototype.adapt = function () { + var targetParams; mw.log( '[CX] Adapting template ' + this.templateTitle + ' based on mapping.' ); // Update the name of the template - this.templateData.parts[ 0 ].template.target.wt = this.templateMapping.targetname; - this.templateData.parts[ 0 ].template.params = this.getTargetParams( this.getSourceParams() ); + this.adaptTitle( this.templateMapping.cxMapping.targetname || this.templateMapping.title ); + targetParams = this.getTargetParams( this.getSourceParams() ); + if ( $.isEmptyObject( targetParams ) ) { + return false; + } + this.templateData.parts[ 0 ].template.params = targetParams; this.$template.attr( 'data-mw', JSON.stringify( this.templateData ) ); // Make templates uneditable unless whitelisted if ( !this.templateMapping.editable ) { this.$template.data( 'editable', false ); } + return true; }; /** @@ -141,21 +185,33 @@ // Update the template parameters $.each( sourceParams, function ( key, value ) { - // Drop empty parameters - // TODO: Shouldn't we only do this if the parameter is named? - // I can imagine {{Foo||baz}} breaks badly if we remove the one from middle. - if ( $.trim( value ) === '' ) { + if ( !isNaN( key ) ) { + // Key is like "1" or "2" etc. Unnamed params. + targetParams[ key ] = value; return; } - // Copy over other parameters, but map known keys - if ( self.templateMapping.parameters && - self.templateMapping.parameters[ key ] !== undefined - ) { - key = self.templateMapping.parameters[ key ]; + if ( self.templateMapping.cxMapping.parameters && + self.templateMapping.cxMapping.parameters[ key ] ) { + targetParams[ self.templateMapping.cxMapping.parameters[ key ] ] = value; + return; } - targetParams[ key ] = value; + if ( !self.templateMapping.params ) { + return; + } + // Copy over other parameters, but map known keys + if ( self.templateMapping.params && + self.templateMapping.params[ key ] ) { + targetParams[ key ] = value; + return; + } + $.each( self.templateMapping.params, function ( paramName, param ) { + var aliases = param.aliases; + if ( aliases.indexOf( key ) >= 0 ) { + targetParams[ paramName ] = value; + } + } ); } ); return targetParams; @@ -167,7 +223,7 @@ TemplateTool.prototype.adaptTitle = function ( targetTitle ) { var self = this; // Update the name of the template. We need template name without namespace - getTemplateNamespaceTranslation( mw.cx.targetLanguage ) + this.getTemplateNamespaceTranslation( this.targetLanguage ) .done( function ( translatedNamespace ) { var templateName; @@ -203,8 +259,7 @@ TemplateTool.prototype.process = function () { var self = this; - this.templateData = this.getTemplateData(); - this.templateMapping = this.getTemplateMapping(); + this.templateData = this.getSourceTemplateData(); if ( !this.templateData || ( this.templateData.parts && this.templateData.parts.length > 1 ) ) { // Either the template is missing mw data or having multiple parts. @@ -216,15 +271,15 @@ } this.templateTitle = this.templateData.parts[ 0 ].template.target.wt; - - return this.getTargetTemplate() - .then( function ( targetTitle ) { + return this.getTemplateMapping() + .then( function ( targetTemplateData ) { + var adaptResult = false; + self.templateMapping = targetTemplateData; self.markReadOnly(); - if ( self.templateMapping ) { - self.adapt(); - } else if ( targetTitle ) { - self.adaptTitle( targetTitle ); - } else { + if ( targetTemplateData ) { + adaptResult = self.adapt(); + } + if ( !adaptResult ) { self.deconstruct(); } } ) @@ -249,14 +304,14 @@ } // TODO: Avoid direct access to globals - api = mw.cx.siteMapper.getApi( mw.cx.sourceLanguage ); + api = this.siteMapper.getApi( this.sourceLanguage ); // Note that we use canonical namespace 'Template' for title. request = api.get( { action: 'query', titles: 'Template:' + this.templateTitle, prop: 'langlinks', - lllang: mw.cx.siteMapper.getWikiDomainCode( mw.cx.targetLanguage ), + lllang: this.siteMapper.getWikiDomainCode( this.targetLanguage ), redirects: true, format: 'json' }, { @@ -277,6 +332,13 @@ return request; }; + mw.cx.TemplateTool = TemplateTool; + mw.cx.TemplateTool.defaults = { + siteMapper: mw.cx.siteMapper, + sourceLanguage: mw.cx.sourceLanguage, + targetLanguage: mw.cx.targetLanguage + }; + /** * Processes each template in given section. * @@ -285,22 +347,17 @@ function processTemplates( $section ) { var i, template, templates = []; - if ( $section.is( '[typeof*="mw:Transclusion"]' ) ) { + if ( $section.is( '[typeof~="mw:Transclusion"]' ) ) { templates.push( $section ); } templates = templates.concat( // Convert the internal templates to a js array - $.makeArray( $section.find( '[typeof*="mw:Transclusion"]' ) ) + $.makeArray( $section.find( '[typeof~="mw:Transclusion"]' ) ) ); for ( i = 0; i < templates.length; i++ ) { - template = new TemplateTool( templates[ i ] ); + template = new mw.cx.TemplateTool( templates[ i ] ); template.process(); } - } - - if ( typeof QUnit !== undefined ) { - // Expose this module for unit testing - mw.cx.TemplateTool = TemplateTool; } $( function () { diff --git a/tests/qunit/tools/ext.cx.tools.template.test.js b/tests/qunit/tools/ext.cx.tools.template.test.js index a53f4ea..d99277e 100644 --- a/tests/qunit/tools/ext.cx.tools.template.test.js +++ b/tests/qunit/tools/ext.cx.tools.template.test.js @@ -28,14 +28,16 @@ $fixture.load( testDataPath + 'template-lang-ml.html', function () { var templateTool, $templates = $fixture.find( '[typeof="mw:Transclusion"]' ); - mw.cx.targetLanguage = 'ml'; - mw.cx.sourceLanguage = 'en'; // Tesing lang-ml template. It exist in en and ml. So will be passed through // But it will be readonly. $.each( $templates, function ( index, template ) { var $template = $( template ); - templateTool = new mw.cx.TemplateTool( $template ); + templateTool = new mw.cx.TemplateTool( $template, { + siteMapper: mw.cx.siteMapper, + sourceLanguage: 'ml', + targetLanguage: 'en' + } ); templateTool.process().then( function () { assert.assertTrue( $template.is( '[contenteditable=false]' ), 'Template is readonly' ); QUnit.start(); @@ -52,15 +54,19 @@ $fixture.load( testDataPath + 'template-lang-ml.html', function () { var templateTool, $templates = $fixture.find( '[typeof="mw:Transclusion"]' ); - mw.cx.targetLanguage = 'ca'; - mw.cx.sourceLanguage = 'en'; $.each( $templates, function ( index, template ) { // Tesing lang-ml template. It exist in en but not in ca. So will be deconstructed var $template = $( template ); - templateTool = new mw.cx.TemplateTool( $template ); + templateTool = new mw.cx.TemplateTool( $template, { + siteMapper: mw.cx.siteMapper, + sourceLanguage: 'ca', + targetLanguage: 'en' + } ); templateTool.process().then( function () { - assert.assertFalse( $template.is( '[typeof="mw:Transclusion"]' ), 'Template is deconstructed' ); + assert.assertTrue( + $template.is( '[typeof="mw:Transclusion"]' ), + 'Template is mapped using TemplateData extension data' ); QUnit.start(); } ); } ); @@ -81,7 +87,11 @@ // Tesing Ficha_de_taxón. As per template mapping for es-ca, it should be renamed to Taxocaixa var $template = $( template ); - templateTool = new mw.cx.TemplateTool( $template ); + templateTool = new mw.cx.TemplateTool( $template, { + siteMapper: mw.cx.siteMapper, + sourceLanguage: mw.cx.sourceLanguage, + targetLanguage: mw.cx.targetLanguage + } ); templateTool.process().then( function () { var templateData = $template.data( 'mw' ); assert.assertTrue( $template.is( '[contenteditable=false]' ), 'Template is readonly' ); @@ -100,14 +110,16 @@ $fixture.load( testDataPath + 'template-cita-noticia-es.html', function () { var templateTool, $templates = $fixture.find( '[typeof="mw:Transclusion"]' ); - mw.cx.sourceLanguage = 'es'; - mw.cx.targetLanguage = 'ca'; $.each( $templates, function ( index, template ) { // Tesing Cita Noticia. As per template mapping for es-ca, it should be renamed to Ref-notícia var $template = $( template ), originalTemplateParams = Object.keys( $template.data( 'mw' ).parts[ 0 ].template.params ); - templateTool = new mw.cx.TemplateTool( $template ); + templateTool = new mw.cx.TemplateTool( $template, { + siteMapper: mw.cx.siteMapper, + sourceLanguage: 'es', + targetLanguage: 'ca' + } ); templateTool.process().then( function () { var i, key, mappedKey, templateData = $template.data( 'mw' ), -- To view, visit https://gerrit.wikimedia.org/r/295898 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6f71dee7d3c05964f8dfa5e49bd8a839036a6064 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/ContentTranslation Gerrit-Branch: master Gerrit-Owner: Santhosh <santhosh.thottin...@gmail.com> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits