Skip to content
Extraits de code Groupes Projets
Valider 98c3a0a8 rédigé par Jonne Haß's avatar Jonne Haß
Parcourir les fichiers

Merge pull request #5120 from jhass/i18n_js_fallback

Add fallback system to frontend I18n system
parents 01278529 92a6fc9e
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
Affichage de avec 77 ajouts et 43 suppressions
/* Copyright (c) 2010-2011, Diaspora Inc. This file is
* licensed under the Affero General Public License version 3 or later. See
* the COPYRIGHT file.
*/
Diaspora.I18n = { Diaspora.I18n = {
language: "en", language: "en",
locale: {}, locale: {
pluralizationKey: function(n) { return this.fallback.pluralizationKey(n); },
data: {},
fallback: {
pluralizationKey: function(n) { return n == 1 ? "one" : "other"; },
data: {}
}
},
loadLocale: function(locale, language) { load: function(locale, language, fallbackLocale) {
this.locale = $.extend(this.locale, locale); this.updateLocale(this.locale, locale);
this.updateLocale(this.locale.fallback, fallbackLocale);
this.language = language; this.language = language;
rule = this.t('pluralization_rule'); },
if (rule === "")
rule = 'function (n) { return n == 1 ? "one" : "other" }'; updateLocale: function(locale, data) {
eval("this.pluralizationKey = "+rule); locale.data = $.extend(locale.data, data);
rule = this.resolve(locale, ['pluralization_rule']);
if (rule !== "") {
eval("locale.pluralizationKey = "+rule);
}
}, },
t: function(item, views) { t: function(item, views) {
var items = item.split("."), var items = item.split(".");
translatedMessage, return this.resolve(this.locale, items, views);
nextNamespace; },
resolve: function(locale, items, views) {
var translatedMessage, nextNamespace, originalItems = items.slice();
if(views && typeof views.count !== "undefined") { if(views && typeof views.count !== "undefined") {
items.push(this.pluralizationKey(views.count)); items.push(locale.pluralizationKey(views.count));
} }
while(nextNamespace = items.shift()) { while(nextNamespace = items.shift()) {
translatedMessage = (translatedMessage) translatedMessage = (translatedMessage)
? translatedMessage[nextNamespace] ? translatedMessage[nextNamespace]
: this.locale[nextNamespace]; : locale.data[nextNamespace];
if(typeof translatedMessage === "undefined") { if(typeof translatedMessage === "undefined") {
return ""; if (typeof locale.fallback === "undefined") {
return "";
} else {
return this.resolve(locale.fallback, originalItems, views);
}
} }
} }
return _.template(translatedMessage, views || {}); try {
return _.template(translatedMessage, views || {});
} catch (e) {
if (typeof locale.fallback === "undefined") {
return "";
} else {
return this.resolve(locale.fallback, originalItems, views);
}
}
}, },
reset: function() { reset: function() {
this.locale = {}; this.locale.data = {};
if( arguments.length > 0 && !(_.isEmpty(arguments[0])) ) if( arguments.length > 0 && !(_.isEmpty(arguments[0])) )
this.locale = arguments[0]; this.locale.data = arguments[0];
} }
}; };
...@@ -31,7 +31,9 @@ module LayoutHelper ...@@ -31,7 +31,9 @@ module LayoutHelper
def load_javascript_locales(section = 'javascripts') def load_javascript_locales(section = 'javascripts')
content_tag(:script) do content_tag(:script) do
<<-JS.html_safe <<-JS.html_safe
Diaspora.I18n.loadLocale(#{get_javascript_strings_for(I18n.locale, section).to_json}, "#{I18n.locale}"); Diaspora.I18n.load(#{get_javascript_strings_for(I18n.locale, section).to_json},
"#{I18n.locale}",
#{get_javascript_strings_for(DEFAULT_LANGUAGE, section).to_json});
Diaspora.Page = "#{params[:controller].camelcase}#{params[:action].camelcase}"; Diaspora.Page = "#{params[:controller].camelcase}#{params[:action].camelcase}";
JS JS
end end
......
describe("app.collections.Aspects", function(){ describe("app.collections.Aspects", function(){
beforeEach(function(){ beforeEach(function(){
Diaspora.I18n.loadLocale({ Diaspora.I18n.load({
'and' : "and", 'and' : "and",
'comma' : ",", 'comma' : ",",
'my_aspects' : "My Aspects" 'my_aspects' : "My Aspects"
......
describe("app.views.AspectsList", function(){ describe("app.views.AspectsList", function(){
beforeEach(function(){ beforeEach(function(){
setFixtures('<ul id="aspects_list"></ul>'); setFixtures('<ul id="aspects_list"></ul>');
Diaspora.I18n.loadLocale({ aspect_navigation : { Diaspora.I18n.load({ aspect_navigation : {
'select_all' : 'Select all', 'select_all' : 'Select all',
'deselect_all' : 'Deselect all' 'deselect_all' : 'Deselect all'
}}); }});
......
...@@ -58,7 +58,7 @@ describe("app.views.CommentStream", function(){ ...@@ -58,7 +58,7 @@ describe("app.views.CommentStream", function(){
}); });
it("doesn't add the comment to the view, when the request fails", function(){ it("doesn't add the comment to the view, when the request fails", function(){
Diaspora.I18n.loadLocale({failed_to_post_message: "posting failed!"}); Diaspora.I18n.load({failed_to_post_message: "posting failed!"});
this.request.response({status: 500}); this.request.response({status: 500});
expect(this.view.$(".comment-content p").text()).not.toEqual("a new comment"); expect(this.view.$(".comment-content p").text()).not.toEqual("a new comment");
......
...@@ -2,7 +2,7 @@ describe("app.views.Feedback", function(){ ...@@ -2,7 +2,7 @@ describe("app.views.Feedback", function(){
beforeEach(function(){ beforeEach(function(){
loginAs({id : -1, name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); loginAs({id : -1, name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}});
Diaspora.I18n.loadLocale({stream : { Diaspora.I18n.load({stream : {
'like' : "Like", 'like' : "Like",
'unlike' : "Unlike", 'unlike' : "Unlike",
'public' : "Public", 'public' : "Public",
......
Ce diff est replié.
...@@ -2,7 +2,7 @@ describe("app.views.LikesInfo", function(){ ...@@ -2,7 +2,7 @@ describe("app.views.LikesInfo", function(){
beforeEach(function(){ beforeEach(function(){
loginAs({id : -1, name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); loginAs({id : -1, name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}});
Diaspora.I18n.loadLocale({stream : { Diaspora.I18n.load({stream : {
pins : { pins : {
zero : "<%= count %> Pins", zero : "<%= count %> Pins",
one : "<%= count %> Pin"} one : "<%= count %> Pin"}
......
...@@ -431,7 +431,7 @@ describe("app.views.Publisher", function() { ...@@ -431,7 +431,7 @@ describe("app.views.Publisher", function() {
context('successful completion', function() { context('successful completion', function() {
beforeEach(function() { beforeEach(function() {
Diaspora.I18n.loadLocale({ photo_uploader: { completed: '<%= file %> completed' }}); Diaspora.I18n.load({ photo_uploader: { completed: '<%= file %> completed' }});
$('#photodropzone').html('<li class="publisher_photo loading"><img src="" /></li>'); $('#photodropzone').html('<li class="publisher_photo loading"><img src="" /></li>');
this.uploader.onComplete(null, 'test.jpg', { this.uploader.onComplete(null, 'test.jpg', {
...@@ -469,7 +469,7 @@ describe("app.views.Publisher", function() { ...@@ -469,7 +469,7 @@ describe("app.views.Publisher", function() {
context('unsuccessful completion', function() { context('unsuccessful completion', function() {
beforeEach(function() { beforeEach(function() {
Diaspora.I18n.loadLocale({ photo_uploader: { completed: '<%= file %> completed' }}); Diaspora.I18n.load({ photo_uploader: { completed: '<%= file %> completed' }});
$('#photodropzone').html('<li class="publisher_photo loading"><img src="" /></li>'); $('#photodropzone').html('<li class="publisher_photo loading"><img src="" /></li>');
this.uploader.onComplete(null, 'test.jpg', { this.uploader.onComplete(null, 'test.jpg', {
......
...@@ -21,7 +21,7 @@ describe("app.views.StreamPost", function(){ ...@@ -21,7 +21,7 @@ describe("app.views.StreamPost", function(){
beforeEach(function(){ beforeEach(function(){
loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}});
Diaspora.I18n.loadLocale({stream : { Diaspora.I18n.load({stream : {
reshares : { reshares : {
one : "<%= count %> reshare", one : "<%= count %> reshare",
other : "<%= count %> reshares" other : "<%= count %> reshares"
......
...@@ -24,7 +24,7 @@ beforeEach(function() { ...@@ -24,7 +24,7 @@ beforeEach(function() {
var Page = Diaspora.Pages["TestPage"]; var Page = Diaspora.Pages["TestPage"];
$.extend(Page.prototype, Diaspora.EventBroker.extend(Diaspora.BaseWidget)); $.extend(Page.prototype, Diaspora.EventBroker.extend(Diaspora.BaseWidget));
Diaspora.I18n.loadLocale({}, 'en'); Diaspora.I18n.load({}, 'en', {});
Diaspora.page = new Page(); Diaspora.page = new Page();
Diaspora.page.publish("page/ready", [$(document.body)]); Diaspora.page.publish("page/ready", [$(document.body)]);
......
...@@ -24,27 +24,28 @@ describe("Diaspora.I18n", function() { ...@@ -24,27 +24,28 @@ describe("Diaspora.I18n", function() {
Diaspora.I18n.reset(); // run tests with clean locale Diaspora.I18n.reset(); // run tests with clean locale
}); });
describe("::loadLocale", function() { describe("::load", function() {
it("sets the class's locale variable", function() { it("sets the class's locale variable", function() {
Diaspora.I18n.loadLocale(locale); Diaspora.I18n.load(locale, "en", locale);
expect(Diaspora.I18n.locale).toEqual(locale); expect(Diaspora.I18n.locale.data).toEqual(locale);
expect(Diaspora.I18n.locale.fallback.data).toEqual(locale);
}); });
it("extends the class's locale variable on multiple calls", function() { it("extends the class's locale variable on multiple calls", function() {
var data = {another: 'section'}, var data = {another: 'section'},
extended = $.extend(locale, data); extended = $.extend(locale, data);
Diaspora.I18n.loadLocale(locale); Diaspora.I18n.load(locale, "en", locale);
Diaspora.I18n.loadLocale(data); Diaspora.I18n.load(data, "en", data);
expect(Diaspora.I18n.locale).toEqual(extended); expect(Diaspora.I18n.locale.data).toEqual(extended);
}); });
}); });
describe("::t", function() { describe("::t", function() {
var translation; var translation;
beforeEach(function() { Diaspora.I18n.loadLocale(locale); }); beforeEach(function() { Diaspora.I18n.load(locale, "en", {fallback: "fallback", namespace: {template: "no template"}}); });
it("returns the specified translation", function() { it("returns the specified translation", function() {
translation = Diaspora.I18n.t("namespace.message"); translation = Diaspora.I18n.t("namespace.message");
...@@ -67,20 +68,28 @@ describe("Diaspora.I18n", function() { ...@@ -67,20 +68,28 @@ describe("Diaspora.I18n", function() {
it("returns an empty string if the translation is not found", function() { it("returns an empty string if the translation is not found", function() {
expect(Diaspora.I18n.t("missing.locale")).toEqual(""); expect(Diaspora.I18n.t("missing.locale")).toEqual("");
}); });
it("falls back on missing key", function() {
expect(Diaspora.I18n.t("fallback")).toEqual("fallback");
});
it("falls back on interpolation errors", function() {
expect(Diaspora.I18n.t("namespace.template")).toEqual("no template");
});
}); });
describe("::reset", function(){ describe("::reset", function(){
it("clears the current locale", function() { it("clears the current locale", function() {
Diaspora.I18n.loadLocale(locale); Diaspora.I18n.load(locale, "en", locale);
Diaspora.I18n.reset() Diaspora.I18n.reset()
expect(Diaspora.I18n.locale).toEqual({}); expect(Diaspora.I18n.locale.data).toEqual({});
}); });
it("sets the locale to only a specific value", function() { it("sets the locale to only a specific value", function() {
var data = { some: 'value' }; var data = { some: 'value' };
Diaspora.I18n.loadLocale(locale); Diaspora.I18n.load(locale, "en", locale);
Diaspora.I18n.reset(data); Diaspora.I18n.reset(data);
expect(Diaspora.I18n.locale).toEqual(data); expect(Diaspora.I18n.locale.data).toEqual(data);
}); });
}); });
}); });
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Veuillez vous inscrire ou vous pour commenter