Skip to content
This repository has been archived by the owner on Nov 2, 2023. It is now read-only.

Fix #268: create empty nodes for missing translations #270

Merged
merged 1 commit into from
Jan 25, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 56 additions & 25 deletions public/javascripts/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,41 +219,72 @@ var dataNS = odkmaker.namespace.load('odkmaker.data');
};

/**
* Push a translated extra node to a given array.
* Push translated extra node to a given array.
*
* Nodes are only created if the extra has at least one non-empty string.
*
* E.g. `ext` for labels with no extras is an empty object `{}` and will not create any nodes.
*
* `ext` for labels with additional, missing translations is an object with some empty or even
* missing keys (languageCodes), e.g. `{0: "English label", 1: ""}` or `{0: "English label"}`.
* Here, langugeCode 1 will get an empty node in both cases.
*
* @param {Object} arr The array to be added to.
* @param {Object} ext The value of an item of the extra object.
* @param {Object} frm The value for "form".
* @param {String} txn The desired language.
* @param {String} pre An optional prefix for the translated value, e.g. `jr://images/`.
* @return None, the arr is mutated in place.
*/
var pushChildren = function(arr, ext, frm, txn, pre)
{
var pre = (typeof pre !== 'undefined') ? pre : "";
// Only create a node for non-empty control object values
if ((ext !== undefined) && !_.isEmpty(ext[txn._languageCode]))
{
var pushChildren = function (arr, ext, frm, txn, pre) {
var pre = (pre !== undefined) ? pre : "";

// #268: skip unless ext contains at least one non-empty value
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We test whether e.g. English (first lang) has a value given, while other added languages are empty. In that case, we'll want empty nodes. Only if nothing is given, we can skip creating nodes.

var contains_non_empty_value = false;
for (var key in ext) {
if (ext[key] !== '') {
contains_non_empty_value = true;
break;
}
};

if ((ext !== undefined) && contains_non_empty_value && !_.isEmpty(ext[txn._languageCode])) {
arr.push({
name: 'value',
attrs: {
form: frm
},
_noWhitespace: true,
children: getTranslation(ext, txn, prefix = pre)
});
name: 'value',
attrs: {
form: frm
},
_noWhitespace: true,
children: getTranslation(ext, txn, prefix = pre)
});
} else if ((ext !== undefined) && contains_non_empty_value && _.isEmpty(ext[txn._languageCode])) {
Copy link
Contributor Author

@florianm florianm Jan 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If any other language contains a non empty value (contains_non_empty_value) but this translation is empty (isEmpty...), then push an empty node (children: [""]).

// #268: if other languages are given but this language is empty or missing, push an empty node
arr.push({
name: 'value',
attrs: {
form: frm
},
_noWhitespace: true,
children: [""]
});
};
};

/**
* Generate all translations for a given control element and optional extras.
*
* @param {Object} obj A control element, e.g. control.label.
* @param {String} itextPath The XPath for the control element.
* @param {Object} translations The translations structure, which is mutated.
* @param {String} itextPath The XPath for the control element, e.g. `/data/field_1:label`.
* @param {Object} translations The translations structure, which is mutated.
* This structure is the JSON equivalent of the XForm's `itext` node.
* @param {Object} [extras] An optional object of extra control elements.
* Supported are keys "image", "audio",
* "video", "big-image", "short", and "guidance".
* These are added as additional "forms" to the `itext/translation/itextPath` node.
* E.g., a `label` can get an extra `short`, `image`, `bigimate`, `audio`, or `video` form.
* Similarly, a `hint` can get an extra `guidance` form.
* See <https://getodk.github.io/xforms-spec/#supported-media-types>
* and <https://docs.getodk.org/form-styling/#media>
* and <https://docs.getodk.org/form-styling/#media>.
*/
var addTranslation = function(obj, itextPath, translations, extras)
{
Expand All @@ -262,7 +293,7 @@ var dataNS = odkmaker.namespace.load('odkmaker.data');
{

// The translation for the main control object obj
var schoolyard = [{
var tx = [{
Copy link
Contributor Author

@florianm florianm Jan 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've renamed this variable because the metaphor of pushing children across a schoolyard has no explanatory value. The additional function docs now clarify what this function does.

name: 'value',
_noWhitespace: true,
children: getTranslation(obj, translation)
Expand All @@ -271,20 +302,20 @@ var dataNS = odkmaker.namespace.load('odkmaker.data');
// Extras: if present, push translations for each additional control object
if (extras !== {})
{
pushChildren(schoolyard, extras['short'], "short", translation);
pushChildren(schoolyard, extras.image, "image", translation, pre = "jr://images/");
pushChildren(schoolyard, extras.video, "video", translation, pre = "jr://video/");
pushChildren(schoolyard, extras.audio, "audio", translation, pre = "jr://audio/");
pushChildren(schoolyard, extras.bigimage, "big-image", translation, pre = "jr://images/");
pushChildren(schoolyard, extras.guidance, "guidance", translation);
pushChildren(tx, extras['short'], "short", translation);
pushChildren(tx, extras.image, "image", translation, pre = "jr://images/");
pushChildren(tx, extras.video, "video", translation, pre = "jr://video/");
pushChildren(tx, extras.audio, "audio", translation, pre = "jr://audio/");
pushChildren(tx, extras.bigimage, "big-image", translation, pre = "jr://images/");
pushChildren(tx, extras.guidance, "guidance", translation);
};

translation.children.push({
name: 'text',
attrs: {
'id': itextPath
},
children: schoolyard
children: tx
});

})
Expand Down