jenkins-bot has submitted this change and it was merged. ( 
https://gerrit.wikimedia.org/r/380935 )

Change subject: CX2: Restore the saved translation
......................................................................


CX2: Restore the saved translation

Fill the translation sections with saved translations from earlier
sessions by matching the section number.

This commit implements the very basic section number matching logic.
So it matches a linear order of source sections.

If source article changed heavily, we need to use a better algorithm
to identify source sections even if it changed. And fallback to
original source revision if source article changed beyond restoring
a saved translation. That is for follow up.

Bug: T176843
Change-Id: Idd2dae87b487219d80391ff4f1a9cf74d6e9e8e4
---
M modules/dm/mw.cx.dm.Translation.js
M modules/mw.cx.TranslationController.js
M modules/mw.cx.init.Translation.js
3 files changed, 74 insertions(+), 80 deletions(-)

Approvals:
  Esanders: Looks good to me, but someone else must approve
  jenkins-bot: Verified
  Nikerabbit: Checked; Looks good to me, approved



diff --git a/modules/dm/mw.cx.dm.Translation.js 
b/modules/dm/mw.cx.dm.Translation.js
index 75e5a55..dc9e585 100644
--- a/modules/dm/mw.cx.dm.Translation.js
+++ b/modules/dm/mw.cx.dm.Translation.js
@@ -10,15 +10,14 @@
  * @param {mw.cx.dm.WikiPage} sourceWikiPage Details of source wiki page
  * @param {mw.cx.dm.WikiPage} targetWikiPage Details of target wiki page
  * @param {string} sourceHtml Segmented source HTML
- * @param {Object} config
+ * @param {Object} [draft] Saved translation
  */
-mw.cx.dm.Translation = function MwCxDmTranslation( sourceWikiPage, 
targetWikiPage, sourceHtml, config ) {
+mw.cx.dm.Translation = function MwCxDmTranslation( sourceWikiPage, 
targetWikiPage, sourceHtml, draft ) {
        // Mixin constructor
        OO.EventEmitter.call( this );
 
        this.sourceWikiPage = sourceWikiPage;
        this.targetWikiPage = targetWikiPage;
-       this.config = config;
        this.id = null;
        this.sourceCategories = null;
        this.targetCategories = null;
@@ -38,13 +37,17 @@
        this.topTranslationUnits = [];
        this.translationUnitById = {};
 
+       if ( draft ) {
+               this.setSavedTranslation( draft );
+       }
+
        this.sourceDoc = ve.dm.converter.getModelFromDom(
                this.constructor.static.getSourceDom( sourceHtml, false ),
                { lang: this.sourceWikiPage.getLanguage(), dir: 
this.sourceWikiPage.getDirection() }
        );
 
        this.targetDoc = ve.dm.converter.getModelFromDom(
-               this.constructor.static.getSourceDom( sourceHtml, true ),
+               this.constructor.static.getSourceDom( sourceHtml, true, 
this.savedTranslationUnits ),
                { lang: this.targetWikiPage.getLanguage(), dir: 
this.targetWikiPage.getDirection() }
        );
 
@@ -62,9 +65,10 @@
  *
  * @param {string} sourceHtml The source HTML
  * @param {boolean} forTarget Replace each top-level wrapper section with an 
empty placeholder?
+ * @param {Object} [savedTranslationUnits] Saved translation units if any
  * @return {HTMLDocument} Restructured source DOM
  */
-mw.cx.dm.Translation.static.getSourceDom = function ( sourceHtml, forTarget ) {
+mw.cx.dm.Translation.static.getSourceDom = function ( sourceHtml, forTarget, 
savedTranslationUnits ) {
        var lastAboutGroup,
                nextSectionId = 1,
                sectionIdPrefix = forTarget ? 'cxTargetSection' : 
'cxSourceSection',
@@ -86,20 +90,27 @@
        // TODO: it would be better to do section wrapping on the CX server
        Array.prototype.forEach.call( domDoc.body.childNodes, function ( node ) 
{
                var sectionNode, aboutGroup;
-               if ( node.nodeType !== Node.ELEMENT_NODE ) {
-                       return;
-               }
-               sectionNode = domDoc.createElement( 'section' );
-               aboutGroup = node.getAttribute( 'about' );
-               // For block level templates and their about-grouped siblings, 
don't give them
-               // a section ID as they can't be translated yet
-               // TODO: handle more systematically
-               if ( ( aboutGroup && aboutGroup === lastAboutGroup ) || ( 
node.getAttribute( 'typeof' ) || '' ).match( /\bmw:Transclusion\b/ ) ) {
-                       lastAboutGroup = aboutGroup;
-               } else {
-                       sectionNode.setAttribute( 'id', sectionIdPrefix + 
nextSectionId );
-                       sectionNode.setAttribute( 'rel', forTarget ? 
'cx:Placeholder' : 'cx:Section' );
+               if ( forTarget && savedTranslationUnits && 
savedTranslationUnits[ nextSectionId ] ) {
+                       sectionNode = this.getSavedTranslation( 
savedTranslationUnits[ nextSectionId ] );
                        nextSectionId++;
+               } else {
+                       if ( node.nodeType !== Node.ELEMENT_NODE ) {
+                               return;
+                       }
+                       sectionNode = domDoc.createElement( 'section' );
+                       aboutGroup = node.getAttribute( 'about' );
+
+                       // For block level templates and their about-grouped 
siblings, don't give them
+                       // a section ID as they can't be translated yet
+                       // TODO: handle more systematically
+                       if ( ( aboutGroup && aboutGroup === lastAboutGroup ) || 
( node.getAttribute( 'typeof' ) || '' ).match( /\bmw:Transclusion\b/ ) ) {
+                               lastAboutGroup = aboutGroup;
+                       } else {
+                               sectionNode.setAttribute( 'id', sectionIdPrefix 
+ nextSectionId );
+                               sectionNode.setAttribute( 'rel', forTarget ? 
'cx:Placeholder' : 'cx:Section' );
+                               nextSectionId++;
+                       }
+
                }
                if ( forTarget ) {
                        node.parentNode.removeChild( node );
@@ -107,17 +118,42 @@
                        sectionNode.appendChild( node );
                }
                articleNode.appendChild( sectionNode );
-       } );
+       }.bind( this ) );
+
+       // TODO: We need to see if all savedTranslationUnit items were restored 
or not.
+       // Based on that we should inform user/create orphan sections/load 
original source
+       // article used for translation.
        domDoc.body.appendChild( articleNode );
 
        return domDoc;
 };
 
-mw.cx.dm.Translation.prototype.getTargetPage = function () {
-       return this.targetPage;
+/**
+ * Get HTML content of a translation unit to restore.
+ *
+ * @param {Object} translationUnit
+ * @return {Element} Document element corresponding to the saved HTML of the 
section.
+ */
+mw.cx.dm.Translation.static.getSavedTranslation = function ( translationUnit ) 
{
+       var translation;
+
+       // If the translator has manual translation from scratch or on top of 
MT use that.
+       if ( translationUnit.user && translationUnit.user.content ) {
+               translation = translationUnit.user.content;
+       } else if ( translationUnit.mt ) { // Machine translation, unmodified.
+               translation = translationUnit.mt.content;
+       } else if ( translationUnit.source ) { // Unmodified source copy.
+               translation = translationUnit.source.content;
+       }
+
+       return $.parseHTML( translation )[ 0 ];
 };
 
 /* Methods */
+
+mw.cx.dm.Translation.prototype.getTargetPage = function () {
+       return this.targetPage;
+};
 
 /**
  * Get Translation id
@@ -200,6 +236,21 @@
 };
 
 /**
+ * Extract translation metadata from the draft translation fetched
+ * and set to this model.
+ * @param {Object} draft Saved translation.
+ */
+mw.cx.dm.Translation.prototype.setSavedTranslation = function ( draft ) {
+       this.setTargetURL( draft.targetURL );
+       this.setStatus( draft.status );
+       this.setTargetRevisionId( draft.targetRevisionId );
+       this.setProgress( JSON.parse( draft.progress ) );
+       this.setId( draft.id );
+       this.setTargetTitle( draft.targetTitle );
+       this.savedTranslationUnits = draft.translationUnits;
+};
+
+/**
  * Build a translation unit from the source ve.dm.Node or ve.dm.Annotation, if 
one matches
  *
  * @param {ve.dm.Node|ve.dm.Annotation} sourceModel Source node or annotation
diff --git a/modules/mw.cx.TranslationController.js 
b/modules/mw.cx.TranslationController.js
index 35b9b1f..45f5e91 100644
--- a/modules/mw.cx.TranslationController.js
+++ b/modules/mw.cx.TranslationController.js
@@ -1,5 +1,5 @@
 /**
- * CX Translation - save, fetch and restore controller
+ * CX Translation - save, fetch controller
  *
  * @param {mw.cx.dm.Translation} translation
  * @param {mw.cx.ui.TranslationView} translationView
@@ -284,42 +284,6 @@
                origin: 'source'
        } );
        return records;
-};
-
-/**
- * Restore translations from a saved draft.
- * @param {Object} savedTranslation
- */
-mw.cx.TranslationController.prototype.restore = function ( savedTranslation ) {
-       var savedUnits = savedTranslation.translationUnits;
-
-       this.translation.getTranslationUnits().forEach( function ( unit ) {
-               var savedSection, provider, document,
-                       sectionId = unit.getId();
-
-               if ( !savedUnits[ sectionId ] ) {
-                       return;
-               }
-
-               // It's possible that we only saved prefilled MT with no user 
modifications
-               savedSection = savedUnits[ sectionId ].user || savedUnits[ 
sectionId ].mt;
-
-               if ( !savedSection ) {
-                       mw.log.error( '[CX] Missing content to restore for 
section ' + sectionId );
-                       return;
-               }
-
-               // Convert HTML string to Element.
-               document = $( savedSection.content )[ 0 ];
-               // XXX: We don't really know whether it was "source" or 
"scratch" if user changed the default
-               provider = ( savedUnits[ sectionId ].mt && savedUnits[ 
sectionId ].mt.engine ) || 'source';
-
-               // XXX: This is broken when we get for example 
CXDMTemplateTranslationUnit as the top level unit
-               if ( unit instanceof mw.cx.dm.SectionTranslationUnit ) {
-                       unit.adaptWithRestoredContent( document, provider );
-               }
-       } );
-       // TODO: Find out orphan translation units and handle them.
 };
 
 /**
diff --git a/modules/mw.cx.init.Translation.js 
b/modules/mw.cx.init.Translation.js
index 5473a3b..9ecc6d8 100644
--- a/modules/mw.cx.init.Translation.js
+++ b/modules/mw.cx.init.Translation.js
@@ -72,14 +72,12 @@
                        this.sourceWikiPage,
                        this.targetWikiPage,
                        sourcePageContent.segmentedContent,
-                       this.config
+                       draft
                );
                // Initialize translation controller
                this.translationController = new mw.cx.TranslationController(
                        this.translationModel, this.translationView, this.config
                );
-               // Restore draft, if any;
-               this.restoreDraftTranslation( draft );
                this.translationView.setTranslation( this.translationModel );
                mw.log( '[CX] Translation initialized successfully' );
                // Fetch and adapt categories
@@ -295,25 +293,6 @@
        } ).then( function ( response ) {
                return response.query.contenttranslation.translation;
        } );
-};
-
-mw.cx.init.Translation.prototype.restoreDraftTranslation = function ( draft ) {
-       // In case there is no draft (see fetchDraft), there is nothing for us 
to do
-       if ( !draft ) {
-               return;
-       }
-       mw.log( '[CX] Restoring translation draft...' );
-       this.translationModel.setTargetURL( draft.targetURL );
-       this.translationModel.setStatus( draft.status );
-       this.translationModel.setTargetRevisionId( draft.targetRevisionId );
-       this.translationModel.setProgress( JSON.parse( draft.progress ) );
-       this.translationModel.setId( draft.id );
-       this.translationModel.setTargetTitle( draft.targetTitle );
-
-       // Restore each translation storage units against the source sections.
-       this.translationController.restore( draft );
-       // TODO: Restore failures not handled.
-       this.translationView.emit( 'translationRestored' );
 };
 
 mw.cx.init.Translation.prototype.fetchDraftError = function ( errorCode, 
details ) {

-- 
To view, visit https://gerrit.wikimedia.org/r/380935
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Idd2dae87b487219d80391ff4f1a9cf74d6e9e8e4
Gerrit-PatchSet: 5
Gerrit-Project: mediawiki/extensions/ContentTranslation
Gerrit-Branch: master
Gerrit-Owner: Santhosh <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Nikerabbit <[email protected]>
Gerrit-Reviewer: Santhosh <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to