]> www.infradead.org Git - users/mchehab/andors-trail.git/commitdiff
Updated translation tool to accomodate in-place translation of strings. Major thanks...
authorOskar Wiksten <oskar.wiksten@gmail.com>
Thu, 13 Sep 2012 19:10:13 +0000 (21:10 +0200)
committerOskar Wiksten <oskar.wiksten@gmail.com>
Thu, 13 Sep 2012 19:10:13 +0000 (21:10 +0200)
AndorsTrailEdit/AndorsTrailTranslations.js
AndorsTrailEdit/DataStore.js
AndorsTrailEdit/styles2.css
AndorsTrailEdit/translations.html

index 7054941326bb5dd71d64aaa280d1000ee35d2c39..5107445e53ecc3b82c13fb3d0e991fa59991ce4d 100644 (file)
@@ -111,50 +111,99 @@ function pushMessage(res, msg) {
        return res;
 }
 
-function compareAndorsTrailResourceRow(result, fieldList, id, obj1, obj2) {
+function isTranslatableField(fieldName) {
+       return fieldName == "name" || fieldName == "logText" || fieldName == "message" || fieldName == "text";
+}
+
+function compareAndorsTrailResourceHeader(result, id, header1, header2) {
+       if (header1.length != header2.length) {
+               pushMessage(result, "Row \"" + id + "\" was expected to contain " + f1.length + " sub-entries, but only " + f2.length + " was found.");
+               return;
+       }
+       for (var i = 0; i < header1._fields.length; ++i) {
+               var f1 = header1._fields[i];
+               var fieldName1 = header1.getFieldName(i);
+               var f2 = header2._fields[i];
+               var fieldName2 = header2.getFieldName(i);
+               if (fieldName1 != fieldName2) {
+                       pushMessage(result, "Row \"" + id + "\", field \"" + fieldName + "\" was expected to contain \"" + f1 + "\", but \"" + f2 + "\" was found.");
+               }
+               var fieldName2 = header2.getFieldName(i);
+               if (f1 instanceof FieldList) {
+                       compareAndorsTrailResourceHeader(result, id+":"+fieldName1, f1, f2);
+               }
+       }
+}
+function extractTranslatableFields_(id, result, fieldList, prefix, obj) {
+       if (!result) {
+               result = {};
+               result.id = id;
+               result.fields = [];
+       }
+       if (!prefix) {
+               prefix = "";
+       }
        for (var i = 0; i < fieldList._fields.length; ++i) {
                var f = fieldList._fields[i];
-               var fieldName = fieldList.getFieldName(i);
                if (f instanceof FieldList) {
-                       fieldName = f._name;
-               }
-               var isTranslatableField = (fieldName == "name" || fieldName == "logText" || fieldName == "message" || fieldName == "text");
-               var f1 = obj1[fieldName];
-               var f2 = obj2[fieldName];
-               
-               if (f instanceof FieldList) {
-                       if (!f2) { f2 = []; }
-                       if (f1.length != f2.length) {
-                               pushMessage(result, "Row \"" + id + "\", field \"" + fieldName + "\" was expected to contain " + f1.length + " sub-entries, but only " + f2.length + " was found.");
-                               continue;
-                       }
-                       $.each(f1, function(i, obj) {
-                               var id_ = id + ":" + obj[f._fields[0]];
-                               compareAndorsTrailResourceRow(result, f, id_, f1[i], f2[i]);
+                       // f is subfieldlist
+                       $.each(obj[f._name], function(j, elem) {
+                               extractTranslatableFields_(id, result, f, prefix+f._name+"["+j+"].", elem);
                        });
                } else {
-                       if (isTranslatableField && f1.length > 1) {
-                               if (f1 == f2) {
-                                       pushMessage(result, "Row \"" + id + "\", field \"" + fieldName + "\" does not seem to be translated. Both texts are \"" + f1 + "\".");
-                               }
-                       } else {
-                               if (f1 != f2) {
-                                       pushMessage(result, "Row \"" + id + "\", field \"" + fieldName + "\" was expected to contain \"" + f1 + "\", but \"" + f2 + "\" was found.");
-                               }
+                       // f is field name
+                       if (isTranslatableField(f)) {
+                               result.fields.push({
+                                       "name":prefix+f,
+                                       "value":obj[f]
+                               });
                        }
                }
        }
+       return result;
+}
+function extractTranslatableFields(id, fieldList, obj) {
+       return extractTranslatableFields_(id, undefined, fieldList, "", obj);
+}
+
+function compareAndorsTrailResourceRow(result, fieldList, id, obj1, obj2) {
+       // Assume the headers of both objects are correctly matched
+       trans1 = extractTranslatableFields(id, fieldList, obj1);
+       trans2 = extractTranslatableFields(id, fieldList, obj2);
+       $.each(trans1.fields, function(i, f1) {
+               f2 = trans2.fields[i];
+               if (f1.name != f2.name) {
+                       pushMessage(result, "Row \"" + id + "\", field \"" + f1.name + "\" does not match in translated data field\"" + f2.name + "\".");
+               }
+               if (f1.value.length > 1) {
+                       if (f1.value == f2.value) {
+                               pushMessage(result, "Row \"" + id + "\", field \"" + f1.name + "\" does not seem to be translated. Both texts are \"" + f1.value + "\".");
+                       }
+               }
+       });
 }
 
 function compareAndorsTrailResourceFormat(text1, text2) {
-       var result = { isResource: true, class1: "ok", class2: "ok", messages: [] };
+       var result = {
+               isResource: true,
+               class1: "ok",
+               class2: "ok",
+               messages: [],
+               header: undefined,
+               ds_english: undefined,
+               ds_translated: undefined
+       };
        
        var header1 = findHeader(text1);
        if (!header1) { return { isResource: false }; }
+       result.header = header1;
        
        var header2 = findHeader(text2);
        if (!header2) { result.class2 = "red"; return result; }
        
+       compareAndorsTrailResourceHeader(result, "", header1, header2);
+       if (result.class2 != "ok") { return result; }
+       
        var ds1 = new DataStore({});
        var ds2 = new DataStore({});
        ds1.deserialize(text1);
@@ -163,42 +212,153 @@ function compareAndorsTrailResourceFormat(text1, text2) {
                var obj1 = obj;
                var obj2 = ds2.get(i);
                var id1 = obj1[header1._fields[0]];
-               if (!obj2) { return pushMessage(result, "Row " + i + ": expected to find an object with id \"" + id1 + "\", but such row was found."); }
+               if (!obj2) { return pushMessage(result, "Row " + i + ": expected to find an object with id \"" + id1 + "\", but such row was not found."); }
                var id2 = obj2[header1._fields[0]];
                if (id2 != id1) { return pushMessage(result, "Row " + i + ": Expected to find id \"" + id1 + "\", but found \"" + id2 + "\" instead."); }
                
                compareAndorsTrailResourceRow(result, header1, id1, obj1, obj2);
        });
+       
+       result.ds_english = ds1;
+       result.ds_translated = ds2;
        return result;
 }
 
+function applyChangeToObject(trans_obj, fieldName, newValue) {
+       (new Function("x", "v", "x."+fieldName+" = v;"))(trans_obj, newValue);
+}
+
+function appendEditRow(editTable, updateHook, trans_obj, id, fieldName, english_text, translated_text) {
+       if (english_text.length <= 1) {
+               // there's no meaningful text
+               return;
+       }
+       var row_id = name+"__row";
+       var cell_id = name+"__cell";
+       var edit_id = name+"__edit";
+       var cell = $("<span />").text(translated_text)
+                                       .attr("id", cell_id)
+                                       .attr("class", "clickToEdit");
+       var editor = $("<textarea />").val(translated_text)
+                                       .attr("id", cell_id)
+                                       .hide();
+       cell.click(function() {
+               editor.val(cell.text());
+               editor.show().focus();
+               cell.hide(); 
+       });
+       editor.blur(function() {
+               var new_text = editor.val();
+               cell.text(new_text);
+               editor.hide(); cell.show();
+               applyChangeToObject(trans_obj, fieldName, new_text);
+               updateHook();
+       });
+       editTable.append(
+               $("<tr />")
+                       .attr("id", name+"__row")
+                       .append($("<td />").text(id))
+                       .append($("<td />").text(fieldName))
+                       .append($("<td />").text(english_text))
+                       .append($("<td />").append(cell).append(editor))
+       );
+}
+
+function clearEditTable() {
+       var editTable = $("#editTranslation tbody");
+       editTable.children().remove();
+       $("#export_text").val("");
+}
+
+function editTranslationHandler(data2, name, resourceComparison) {
+       var updateHook = function () {
+               var header = resourceComparison.header;
+               var ds2 = resourceComparison.ds_translated;
+               var text2 = ds2.serialize();
+               data2.find("string[name=\"" + name + "\"]").text(text2);
+       };
+       return function () {
+               clearEditTable();
+               var editTable = $("#editTranslation tbody");
+               var header = resourceComparison.header;
+               var ds1 = resourceComparison.ds_english;
+               var ds2 = resourceComparison.ds_translated;
+               $.each(ds1.items, function(i, obj1) {
+                       var obj2 = ds2.get(i);
+                       var id = obj1["id"];
+                       var english_list = extractTranslatableFields(id, header, obj1);
+                       var translated_list = extractTranslatableFields(id, header, obj2);
+                       
+                       $.each(english_list.fields, function(j, f1) {
+                               var f2 = translated_list.fields[j];
+                               appendEditRow(
+                                       editTable, updateHook, obj2, id,
+                                       f1.name, f1.value, f2.value
+                               );
+                       });
+               });
+       };
+}
+function initTranslationHandler(data1, data2, name) {
+       var f = function() {
+               if (!confirm("Create new translation unit in this resouce?")) {
+                       // if canceled
+                       return;
+               }
+               clearEditTable();
+               // create new node in resource xml by copying english ver.
+               var node1 = data1.find("string[name=\"" + name + "\"]");
+               var text1 = node1.text();
+               data2.find("resources").append($("<string name=\""+name+"\" />").text(text1));
+               var resourceComparison = compareAndorsTrailResourceFormat(text1, text1);
+               // repalce this handler with "edit" event handler (and etc.)
+               var editHandler = editTranslationHandler(data2, name, resourceComparison);
+               $(this).parent().attr("class","yellow");
+               $(this).text("Edit").unbind('click', f).click(editHandler);
+               $(this).click();
+       }
+    return f;
+}
+function exportHandler(data2) {
+       var xmlString = function (data) {
+               var xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n";
+               xml += "<resources>\n";
+               $.each(data.find("string"), function() {
+                       xml += "\t<string name=\""+$(this).attr("name")+"\">\n";
+                       xml += $(this).text();
+                       xml += "\n\t</string>\n\n";
+               });
+               xml += "</resources>\n";
+               return xml;
+       }
+       return function () {
+               $("#export_text").val(xmlString(data2));
+       };
+}
+
 function appendOutputRow(outputTable, name, data1, data2) {
        if ($("#" + name, outputTable).size() > 0) return;
        
        var text1 = data1.find("string[name=\"" + name + "\"]").text();
        var text2 = data2.find("string[name=\"" + name + "\"]").text();
-       var class1 = text1 ? "ok" : "red";
        var class2 = text2 ? "ok" : "red";
        var tdTranslated = $("<td />");
-       if (text1 && text2) {
-               var resourceComparison = compareAndorsTrailResourceFormat(text1, text2);
-               if (resourceComparison.isResource) {
-                       class1 = resourceComparison.class1;
-                       class2 = resourceComparison.class2;
-                       if (resourceComparison.messages.length > 0) {
-                               var errorList = $("<ul />").attr("id", "validationWarnings");
-                               $.each(resourceComparison.messages, function(i, msg) {
-                                       errorList.append($("<li />").text(msg));
-                               });
-                               var d = $("<span />").attr("id", "showValidationWarnings").text("Expand");
-                               d.click(function() {
-                                       d.hide();
-                                       errorList.show();
-                               });
-                               tdTranslated.append(d);
-                               tdTranslated.append(errorList);
-                               errorList.hide();
+       if (text1) {
+               if (text2) {
+                       var resourceComparison = compareAndorsTrailResourceFormat(text1, text2);
+                       if (resourceComparison.isResource) {
+                               class2 = resourceComparison.class2;
+                               if (resourceComparison.messages.length > 0 || class2 == "ok") {
+                                       // yellow || ok
+                                       var d = $("<span />").text("Edit");
+                                       d.click(editTranslationHandler(data2, name, resourceComparison));
+                                       tdTranslated.append(d);
+                               }
                        }
+               } else /* if (class2 == "red") */ { 
+                       var d = $("<span />").text("Init");
+                       d.click(initTranslationHandler(data1, data2, name));
+                       tdTranslated.append(d);
                }
        }
        
@@ -206,17 +366,16 @@ function appendOutputRow(outputTable, name, data1, data2) {
                $("<tr />")
                        .attr("id", name)
                        .append($("<td />").text(name))
-                       .append($("<td />").attr("class", class1))
                        .append(tdTranslated.attr("class", class2))
        );
 }
 
 function validateTranslation_(englishData) {
        $("#englishData").text(englishData);
-       var compareData1 = $( englishData );
-       var compareData2 = $( $("#compareToInput").val() );
+       var compareData1 = $( $.parseXML(englishData) );
+       var compareData2 = $( $.parseXML($("#compareToInput").val()) );
        
-       var resultTable = $("#validateResultContent table");
+       var resultTable = $("#validateResultContent #result");
        var outputTable = $("tbody", resultTable );
        outputTable.empty();
        
@@ -229,9 +388,9 @@ function validateTranslation_(englishData) {
        
        var sectionCount = $("tr", outputTable).size();
        var errors1 = sectionCount - $("td:nth-child(2).ok", outputTable).size();
-       var errors2 = sectionCount - $("td:nth-child(3).ok", outputTable).size();;
-       $("th #count1", resultTable).text( (errors1 > 0) ? " (" + errors1 + ")" : "" );
-       $("th #count2", resultTable).text( (errors2 > 0) ? " (" + errors2 + ")" : "" );
+       $("th #count2", resultTable).text( (errors1 > 0) ? " (" + errors1 + ")" : "" );
+
+       $("#export").click(exportHandler(compareData2));
        
        $("#validateResultContent #loading").hide();
        $("#validateResultContent #result").show();
@@ -244,7 +403,6 @@ function validateTranslation(englishData) {
        }
 }
 
-
 function loadStep3() {
        var compareToContent = $("#compareToInput").val();
        if (compareToContent.length <= 0) {
@@ -269,5 +427,12 @@ function startTranslationValidator() {
                loadResourceFile( $("#compareToExisting").val(), function(data) { $("#compareToInput").val(data); } );
        });
        $("#next2").button({ icons: {primary:'ui-icon-arrowthick-1-e'} }).click(loadStep3);
-       $("#prev3").button({ icons: {primary:'ui-icon-arrowthick-1-w'} }).click(function() { stepLeft("#validateResult", "#validate2"); });
+       $("#prev3").button({ icons: {primary:'ui-icon-arrowthick-1-w'} }).click(function() {
+               if (confirm("Leaving the result page will discard any modifications on current resource. Leave anyway?")) {
+                       stepLeft("#validateResult", "#validate2");
+                       clearEditTable();
+               }
+       });
+       $("#export").button({ icons: {primary:'ui-icon-arrowthick-1-e'} })
 }
+
index aa85ca7c9f96b9bbe86f6e166615c7bfa987421a..3d10a257c06b42e7c0094c0168175dbff49997d3 100644 (file)
@@ -58,6 +58,7 @@ function DataStore(input) {
                        alert("Could not find header row, cannot deserialize");
                        return;
                }
+               this.fieldList = header;
                this.items = deserializeObjectList(header, str);
                this.onDeserialized();
        }
index f8ac04314c49c49eaaf9bc99e55d6dd76887ef6e..c64f51151f5f7bb44d5ef172d621dc9a1fb3ee2d 100644 (file)
@@ -47,6 +47,7 @@ input[readonly]                               { color: #888; }
 .validateStep h1                       { font-size: 1.1em; }
 .validateStep h1 .number       { font-size: 1.3em; font-weight: bold; text-shadow: rgba(0, 0, 0, 0.3) 1px 1px 1px; }
 .validateStep .buttons         { padding-top: 10px; }
+
 #validateResultContent table                                                   { border-collapse: collapse; margin-bottom: 1ex; }      
 #validateResultContent table th,td                                             { border: 1px #ccc solid; text-align: left; }
 #validateResultContent table tbody tr:nth-child(even)  { background-color: #eee }
@@ -55,3 +56,14 @@ input[readonly]                              { color: #888; }
 #validateResultContent table .yellow                                   { background-color: yellow; }
 #showValidationWarnings                        { cursor: pointer; }
 #showValidationWarnings:hover  { background-color: #d7d7ff; }
+
+.clickToEdit                   { cursor: pointer; }
+.clickToEdit:hover             { background-color: #d7d7ff; }
+
+#validateResultContent { width: 400px; float: left;d }
+#editorForms                   { width: 670px; float: right;}
+#editorForms #translation_edit_list                    { table-layout: fixed; }
+#editorForms #translation_edit_list tr:nth-child(1)    { width: 17em }
+#editorForms #translation_edit_list tr:nth-child(2)    { width: 8em }
+#editorForms #translation_edit_list textarea   { width: 100%; height: 8em; }
+
index 6bd78ecebbead7e4fc3f161a154d7d7ea80ebaca..135a982f6647bd24ad3a5e06ab5bbe2026359ea6 100644 (file)
        \r
        <div id="validateResult" class="validateStep" style="display: none;">\r
                <h1><span class="number">3.</span> Results</h1>\r
-       \r
-               <div id="validateResultContent">\r
-                       <div id="loading">Loading &amp; validating</div>\r
-                       <table id="result">\r
-                               <thead><tr>\r
-                                       <th>id</th>\r
-                                       <th>English<span id="count1" /></th>\r
-                                       <th>Translated<span id="count2" /></th>\r
-                               </tr></thead>\r
-                               <tbody>\r
-                               </tbody>\r
-                       </table>\r
+               <div>\r
+                       <div id="validateResultContent">\r
+                               <fieldset class="fieldSet">\r
+                                       <legend>Validation Result</legend>\r
+                                       <div id="loading">Loading &amp; validating</div>\r
+                                       <table id="result">\r
+                                               <thead><tr>\r
+                                                       <th>id</th>\r
+                                                       <th>Result<span id="count2" /></th>\r
+                                               </tr></thead>\r
+                                               <tbody>\r
+                                               </tbody>\r
+                                       </table>\r
+                               </fieldset>\r
+                       </div>\r
+                       <div id="editorForms">\r
+                               <fieldset class="fieldSet" id="editTranslation">\r
+                                       <legend>Edit translation</legend>\r
+                                       <table id="translation_edit_list">\r
+                                               <thead><tr>\r
+                                                       <th>id</th>\r
+                                                       <th>field</th>\r
+                                                       <th>English</th>\r
+                                                       <th>Translated</th>\r
+                                               </tr></thead>\r
+                                               <tbody>\r
+                                               </tbody>\r
+                                       </table>\r
+                               </fieldset>\r
+                       </div>\r
+                       <div style="floar:clear;"></div>\r
                </div>\r
                \r
                <div class="buttons">\r
                        <span id="prev3">Back</span>\r
+                       <span id="export">Export</span>\r
+               </div>\r
+               <div class="export_area">\r
+                       <p>Translated Content:</p>\r
+                       <textarea id="export_text" rows=8 cols=80></textarea>\r
                </div>\r
        </div>\r
 </div>\r