From efd1723912b50f37d6f1ed42a8f238beaa63cb16 Mon Sep 17 00:00:00 2001 From: temi Date: Wed, 29 Nov 2023 23:38:43 +1100 Subject: [PATCH] #1581 - added async internationalisation ko binding --- gradle.properties | 2 +- grails-app/assets/javascripts/i18n.js | 49 +++++++++++++++++++ .../javascripts/knockout-custom-bindings.js | 47 +++++++++++++++++- .../biocollect/merit/HomeController.groovy | 8 +++ .../ala/biocollect/merit/CommonService.groovy | 5 ++ 5 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 grails-app/assets/javascripts/i18n.js diff --git a/gradle.properties b/gradle.properties index e3d23421d..e73bc1e17 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ -biocollectVersion=6.7-SNAPSHOT +biocollectVersion=6.8-i18n-SNAPSHOT grailsVersion=5.1.9 grailsGradlePluginVersion=5.1.5 assetPipelineVersion=3.3.4 diff --git a/grails-app/assets/javascripts/i18n.js b/grails-app/assets/javascripts/i18n.js new file mode 100644 index 000000000..d4fad5d2f --- /dev/null +++ b/grails-app/assets/javascripts/i18n.js @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 Atlas of Living Australia + * All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * Created by Temi on 15/11/19. + */ + +(function() { + var messages = {}, + deffer = $.Deferred(); + $.get({ + url: fcConfig.i18nURL, + cache: true + }).done(function (data) { + messages = data; + deffer.resolve(); + }).fail(function () { + deffer.reject(); + }); + + $i18n = function(key, defaultValue) { + if (messages[key] !== undefined) { + return messages[key]; + } else { + return defaultValue || key; + } + }; + + $i18nAsync = function(key, defaultValue, callback) { + if (callback) { + deffer.done(function () { + callback($i18n(key, defaultValue)); + }).fail(function () { + callback($i18n(key, defaultValue)); + }) + } + } + +})(); diff --git a/grails-app/assets/javascripts/knockout-custom-bindings.js b/grails-app/assets/javascripts/knockout-custom-bindings.js index 79cf95b83..c9a1a6a98 100644 --- a/grails-app/assets/javascripts/knockout-custom-bindings.js +++ b/grails-app/assets/javascripts/knockout-custom-bindings.js @@ -1148,4 +1148,49 @@ ko.bindingHandlers.debug = { console.log(element); console.log(ko.toJS(valueAccessor())); } -}; \ No newline at end of file +}; + + +/** + * This binding requires i18n.js to be loaded. It also requires fcConfig.i18nURL to be set. + * Params can be a string or an object. If string, it is treated as key and translated to text. Object parameter has the + * following properties: + * @contentType can be 'text' or 'html' (default is 'text') + * @key is the key to be translated + * @defaultValue is the default value to be used if the key is not found + * + * Usage examples: + *
+ *
+ * + */ +ko.bindingHandlers.i18n = { + init: function (element, valueAccessor, allBindings, viewModel, bindingContext) { + var value = valueAccessor(); + value = ko.unwrap(value); + var contentType = value && value.contentType || 'text' + + // $i18nAsync is required to be defined + if(typeof $i18nAsync === 'undefined') + return + + if( typeof value === 'string') { + $i18nAsync(value, '',function(text) { + $(element).text(text); + }); + } + else if (typeof value === 'object') { + $i18nAsync(value.key, value.defaultValue,function(text) { + switch (contentType) { + default: + case 'text': + $(element).text(text); + break; + case 'html': + $(element).html(text); + break; + } + }); + } + } +} \ No newline at end of file diff --git a/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy b/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy index 9062b447e..1bf80cd7a 100644 --- a/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy +++ b/grails-app/controllers/au/org/ala/biocollect/merit/HomeController.groovy @@ -14,6 +14,7 @@ class HomeController { def settingService def metadataService def userService + CommonService commonService @PreAuthorise(accessLevel = 'alaAdmin', redirectController = "admin") @SSO @@ -61,6 +62,13 @@ class HomeController { def works() { } + def i18n() { + if (request.isGet()) { + Map props = commonService.i18n(request.locale) + render props as JSON + } + } + /** * The purpose of this method is to enable the display of the spatial object corresponding to a selected * value from a geographic facet (e.g. to display the polygon representing NSW on the map if the user has diff --git a/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy b/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy index 286fac098..1ba6ddf75 100644 --- a/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy +++ b/grails-app/services/au/org/ala/biocollect/merit/CommonService.groovy @@ -3,6 +3,7 @@ package au.org.ala.biocollect.merit import grails.converters.JSON import grails.web.mapping.LinkGenerator import grails.web.servlet.mvc.GrailsParameterMap +import org.springframework.context.MessageSource import javax.servlet.http.HttpServletRequest import javax.xml.bind.DatatypeConverter @@ -13,6 +14,7 @@ class CommonService { UserService userService LinkGenerator grailsLinkGenerator + MessageSource messageSource List ignores = ["action","controller"] @@ -92,4 +94,7 @@ class CommonService { queryParams } + def i18n(Locale locale) { + messageSource.getMergedProperties(locale)?.properties + } }