From 152da9796b0268069a10b73d65781301a307fcdd Mon Sep 17 00:00:00 2001
From: Vincent Petry <pvince81@owncloud.com>
Date: Tue, 18 Nov 2014 12:13:44 +0100
Subject: [PATCH] Added function to load translations from JS

For apps that support async translation loading, a new function
OC.L10N.load() can be used to asynchronously load the translations
for a given app.
---
 core/js/js.js                   | 24 +++++++++++++++--
 core/js/l10n.js                 | 41 ++++++++++++++++++++++++++++
 core/js/tests/specs/l10nSpec.js | 48 +++++++++++++++++++++++++++++++++
 3 files changed, 111 insertions(+), 2 deletions(-)

diff --git a/core/js/js.js b/core/js/js.js
index 39e382b544b..eb2f10b51f0 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -252,6 +252,17 @@ var OC={
 		}
 	},
 
+	/**
+	 * Loads translations for the given app asynchronously.
+	 *
+	 * @param {String} app app name
+	 * @param {Function} callback callback to call after loading
+	 * @return {Promise}
+	 */
+	addTranslations: function(app, callback) {
+		return OC.L10N.load(app, callback);
+	},
+
 	/**
 	 * Returns the base name of the given path.
 	 * For example for "/abc/somefile.txt" it will return "somefile.txt"
@@ -475,6 +486,15 @@ var OC={
 			return window.matchMedia(media);
 		}
 		return false;
+	},
+
+	/**
+	 * Returns the user's locale
+	 *
+	 * @return {String} locale string
+	 */
+	getLocale: function() {
+		return $('html').prop('lang');
 	}
 };
 
@@ -869,9 +889,9 @@ function object(o) {
 function initCore() {
 
 	/**
-	 * Set users local to moment.js as soon as possible
+	 * Set users locale to moment.js as soon as possible
 	 */
-	moment.locale($('html').prop('lang'));
+	moment.locale(OC.getLocale());
 
 
 	/**
diff --git a/core/js/l10n.js b/core/js/l10n.js
index e375b7eca80..d091acea049 100644
--- a/core/js/l10n.js
+++ b/core/js/l10n.js
@@ -26,6 +26,47 @@ OC.L10N = {
 	 */
 	_pluralFunctions: {},
 
+	/**
+	 * Load an app's translation bundle if not loaded already.
+	 *
+	 * @param {String} appName name of the app
+	 * @param {Function} callback callback to be called when
+	 * the translations are loaded
+	 * @return {Promise} promise
+	 */
+	load: function(appName, callback) {
+		// already available ?
+		if (this._bundles[appName] || OC.getLocale() === 'en') {
+			if (callback) {
+				callback();
+			}
+			return;
+		}
+
+		var self = this;
+		var deferred = $.Deferred();
+		var url = OC.generateUrl(
+			'apps/{app}/l10n/{locale}.json',
+			{app: appName, locale: OC.getLocale()}
+		);
+
+		var url = OC.filePath(appName, 'l10n', OC.getLocale() + '.json');
+
+		// load JSON translation bundle per AJAX
+		$.get(url,
+			function(result) {
+				if (result.translations) {
+					self.register(appName, result.translations, result.pluralForm);
+				}
+				if (callback) {
+					callback();
+					deferred.resolve();
+				}
+			}
+		);
+		return deferred.promise();
+	},
+
 	/**
 	 * Register an app's translation bundle.
 	 *
diff --git a/core/js/tests/specs/l10nSpec.js b/core/js/tests/specs/l10nSpec.js
index d5b0363ea38..dc021a0baaf 100644
--- a/core/js/tests/specs/l10nSpec.js
+++ b/core/js/tests/specs/l10nSpec.js
@@ -11,8 +11,12 @@
 describe('OC.L10N tests', function() {
 	var TEST_APP = 'jsunittestapp';
 
+	beforeEach(function() {
+		OC.appswebroots[TEST_APP] = OC.webroot + '/apps3/jsunittestapp';
+	});
 	afterEach(function() {
 		delete OC.L10N._bundles[TEST_APP];
+		delete OC.appswebroots[TEST_APP];
 	});
 
 	describe('text translation', function() {
@@ -98,4 +102,48 @@ describe('OC.L10N tests', function() {
 			checkPlurals();
 		});
 	});
+	describe('async loading of translations', function() {
+		it('loads bundle for given app and calls callback', function() {
+			var localeStub = sinon.stub(OC, 'getLocale').returns('zh_CN');
+			var callbackStub = sinon.stub();
+			var promiseStub = sinon.stub();
+			OC.L10N.load(TEST_APP, callbackStub).then(promiseStub);
+			expect(callbackStub.notCalled).toEqual(true);
+			expect(promiseStub.notCalled).toEqual(true);
+			expect(fakeServer.requests.length).toEqual(1);
+			var req = fakeServer.requests[0];
+			expect(req.url).toEqual(
+				OC.webroot + '/apps3/' + TEST_APP + '/l10n/zh_CN.json'
+			);
+			req.respond(
+				200,
+				{ 'Content-Type': 'application/json' },
+				JSON.stringify({
+					translations: {'Hello world!': '你好世界!'},
+					pluralForm: 'nplurals=2; plural=(n != 1);'
+				})
+			);
+
+			expect(callbackStub.calledOnce).toEqual(true);
+			expect(promiseStub.calledOnce).toEqual(true);
+			expect(t(TEST_APP, 'Hello world!')).toEqual('你好世界!');
+			localeStub.restore();
+		});
+		it('calls callback if translation already available', function() {
+			var callbackStub = sinon.stub();
+			OC.L10N.register(TEST_APP, {
+				'Hello world!': 'Hallo Welt!'
+			});
+			OC.L10N.load(TEST_APP, callbackStub);
+			expect(callbackStub.calledOnce).toEqual(true);
+			expect(fakeServer.requests.length).toEqual(0);
+		});
+		it('calls callback if locale is en', function() {
+			var localeStub = sinon.stub(OC, 'getLocale').returns('en');
+			var callbackStub = sinon.stub();
+			OC.L10N.load(TEST_APP, callbackStub);
+			expect(callbackStub.calledOnce).toEqual(true);
+			expect(fakeServer.requests.length).toEqual(0);
+		});
+	});
 });
-- 
GitLab