Skip to content

Localize from object #94

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Prev Previous commit
Next Next commit
Support for custom callback when using raw objects
The method that replace the localized tags by the texts defined inside of
a raw object did not consider any of the possible options you could
receive as a second parameter in a 'localize' call.

The 'callback' option is now supported. The 'data' object will be
converted to a valid json object before calling the default callback, so
if the user sets any of the data properties to a function, the elements
for which the 'data-localize' attribute references any of those invalid property
values will not be updated.

The 'localize_test.coffee' file do now include new methods to test the new functionality.

The 'localize_from_object.html' has been also updated
and seems to be working as expected in the following browsers:

 - Google Chrome (59.0.3071.115)
 - Mozilla Firefox (45.0, 47.0.1)
 - Microsoft Edge (40.15063.0.0)
  • Loading branch information
LonelyPrincess committed Jul 9, 2017
commit 8094a54bb265b36cab8d531d5c7d9510214ca59f
13 changes: 10 additions & 3 deletions dist/jquery.localize.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ http://keith-wood.name/localisation.html
};
$.defaultLanguage = normaliseLang(navigator.languages && navigator.languages.length > 0 ? navigator.languages[0] : navigator.language || navigator.userLanguage);
$.localize = function(pkg, options) {
var defaultCallback, deferred, fileExtension, intermediateLangData, jsonCall, loadLanguage, localizeElement, localizeForSpecialKeys, localizeImageElement, localizeInputElement, localizeOptgroupElement, notifyDelegateLanguageLoaded, regexify, setAttrFromValueForKey, setTextFromValueForKey, useFileAsDataSource, useObjectAsDataSource, valueForKey, wrappedSet;
var defaultCallback, deferred, fileExtension, intermediateLangData, jsonCall, loadLanguage, localizeElement, localizeForSpecialKeys, localizeImageElement, localizeInputElement, localizeOptgroupElement, notifyDelegateLanguageLoaded, regexify, sanitizedCallback, setAttrFromValueForKey, setTextFromValueForKey, useFileAsDataSource, useObjectAsDataSource, valueForKey, wrappedSet;
if (options == null) {
options = {};
}
Expand Down Expand Up @@ -189,10 +189,17 @@ http://keith-wood.name/localisation.html
return loadLanguage(filename, lang, 1);
}
};
useObjectAsDataSource = function(object) {
sanitizedCallback = function(object) {
var data;
data = JSON.parse(JSON.stringify(object));
defaultCallback(data);
return defaultCallback(data);
};
useObjectAsDataSource = function(object) {
if (options.callback != null) {
options.callback(object, sanitizedCallback);
} else {
sanitizedCallback(object);
}
return deferred.resolve();
};
if (typeof pkg === "object") {
Expand Down
2 changes: 1 addition & 1 deletion dist/jquery.localize.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 13 additions & 1 deletion examples/localize_from_object.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,12 @@ <h1>Test localization...</h1>
Ruby image should be round.
</p>
<p data-localize="basic">It failed :(</p>
<p data-localize="message">Optional callback never happened.</p>

<p data-localize="function">This text should remain unchanged</p>
<input data-localize="function" type="text" value="fixed value" readonly />
<input data-localize="added_function" type="text" value="fixed value" readonly />

<script type="text/javascript" charset="utf-8">
$(function(){
var object = {
Expand Down Expand Up @@ -55,7 +60,14 @@ <h1>Test localization...</h1>
"function": function () {}
};

$("[data-localize]").localize(object);
var customCallback = function(data, defaultCallback) {
data.message = "Optional call back works.";
data.added_function = function () {};
defaultCallback(data);
};

var opts = { callback: customCallback };
$("[data-localize]").localize(object, opts);
})
</script>
</body>
Expand Down
14 changes: 10 additions & 4 deletions src/jquery.localize.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -144,12 +144,18 @@ do ($ = jQuery) ->
else
loadLanguage(filename, lang, 1)

# Retrieve translations from an object
useObjectAsDataSource = (object) ->
# We stringify and parse the received object to ensure the object is a valid json
# Any functions defined within the object will be removed during this process
# We stringify and parse the received object to ensure the object is a valid json
# Any functions defined within the object will be removed during this process
sanitizedCallback = (object) ->
data = JSON.parse(JSON.stringify(object))
defaultCallback(data)

# Retrieve translations from an object
useObjectAsDataSource = (object) ->
if options.callback?
options.callback(object, sanitizedCallback)
else
sanitizedCallback(object)
deferred.resolve()

# If 'pkg' is an object, use it as the source for translations
Expand Down
34 changes: 29 additions & 5 deletions test/localize_test.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -208,13 +208,37 @@ do ($ = jQuery) ->
module "Using object as data source"

asyncTest "basic tag text substitution using object as data source", (assert) ->
obj = { "basic": "basic success" }
obj = basic: "basic success"
t = localizableTagWithRel("p", "basic", text: "basic fail")
t.localize(obj).localizePromise.then ->
assert.equal t.text(), "basic success"

asyncTest "don't replace tag text if matching object property contains a function", (assert) ->
obj = { "function": (->) }
t = localizableTagWithRel("p", "function", text: "This text should remain unchanged")
asyncTest "custom callback is fired when object is used as data source", (assert) ->
opts = {}
opts.callback = (data, defaultCallback) ->
data.custom_callback = "custom callback success"
defaultCallback(data)
t = localizableTagWithRel("p", "custom_callback", text: "custom callback fail")
t.localize({}, opts).localizePromise.then ->
assert.equal t.text(), "custom callback success"

asyncTest "tag text must not be replaced if matching object property contains a function", (assert) ->
obj = "function": (->)
t = localizableTagWithRel("p", "function", text: "this text should remain unchanged")
t.localize(obj).localizePromise.then ->
assert.equal t.text(), "This text should remain unchanged"
assert.equal t.text(), "this text should remain unchanged"

asyncTest "input value must not be replaced if matching object property contains a function", (assert) ->
obj = "function": (->)
t = localizableTagWithRel("input", "function", text: "remain after default callback")
t.localize(obj).localizePromise.then ->
assert.equal t.text(), "remain after default callback"

asyncTest "input value must not be replaced if custom callback introduced a matching property that contains a function", (assert) ->
opts = {}
opts.callback = (data, defaultCallback) ->
data.added_function = (->)
defaultCallback(data)
t = localizableTagWithRel("input", "added_function", text: "remain after custom callback")
t.localize({}, opts).localizePromise.then ->
assert.equal t.text(), "remain after custom callback"
48 changes: 44 additions & 4 deletions test/localize_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,7 @@
asyncTest("basic tag text substitution using object as data source", function(assert) {
var obj, t;
obj = {
"basic": "basic success"
basic: "basic success"
};
t = localizableTagWithRel("p", "basic", {
text: "basic fail"
Expand All @@ -375,16 +375,56 @@
return assert.equal(t.text(), "basic success");
});
});
return asyncTest("don't replace tag text if matching object property contains a function", function(assert) {
asyncTest("custom callback is fired when object is used as data source", function(assert) {
var opts, t;
opts = {};
opts.callback = function(data, defaultCallback) {
data.custom_callback = "custom callback success";
return defaultCallback(data);
};
t = localizableTagWithRel("p", "custom_callback", {
text: "custom callback fail"
});
return t.localize({}, opts).localizePromise.then(function() {
return assert.equal(t.text(), "custom callback success");
});
});
asyncTest("tag text must not be replaced if matching object property contains a function", function(assert) {
var obj, t;
obj = {
"function": (function() {})
};
t = localizableTagWithRel("p", "function", {
text: "This text should remain unchanged"
text: "this text should remain unchanged"
});
return t.localize(obj).localizePromise.then(function() {
return assert.equal(t.text(), "this text should remain unchanged");
});
});
asyncTest("input value must not be replaced if matching object property contains a function", function(assert) {
var obj, t;
obj = {
"function": (function() {})
};
t = localizableTagWithRel("input", "function", {
text: "remain after default callback"
});
return t.localize(obj).localizePromise.then(function() {
return assert.equal(t.text(), "This text should remain unchanged");
return assert.equal(t.text(), "remain after default callback");
});
});
return asyncTest("input value must not be replaced if custom callback introduced a matching property that contains a function", function(assert) {
var opts, t;
opts = {};
opts.callback = function(data, defaultCallback) {
data.added_function = (function() {});
return defaultCallback(data);
};
t = localizableTagWithRel("input", "added_function", {
text: "remain after custom callback"
});
return t.localize({}, opts).localizePromise.then(function() {
return assert.equal(t.text(), "remain after custom callback");
});
});
})(jQuery);