thingsboard-aplcache

Details

ui/package.json 16(+9 -7)

diff --git a/ui/package.json b/ui/package.json
index a4b0e4d..4959237 100644
--- a/ui/package.json
+++ b/ui/package.json
@@ -36,12 +36,12 @@
     "angular-socialshare": "^2.3.8",
     "angular-storage": "0.0.15",
     "angular-touch": "1.5.8",
-    "angular-translate": "2.13.1",
-    "angular-translate-handler-log": "2.13.1",
-    "angular-translate-interpolation-messageformat": "2.13.1",
-    "angular-translate-loader-static-files": "2.13.1",
-    "angular-translate-storage-cookie": "2.13.1",
-    "angular-translate-storage-local": "2.13.1",
+    "angular-translate": "2.18.1",
+    "angular-translate-handler-log": "2.18.1",
+    "angular-translate-interpolation-messageformat": "2.18.1",
+    "angular-translate-loader-static-files": "2.18.1",
+    "angular-translate-storage-cookie": "2.18.1",
+    "angular-translate-storage-local": "2.18.1",
     "angular-ui-ace": "^0.2.3",
     "angular-ui-router": "^0.3.1",
     "angular-websocket": "^2.0.1",
@@ -127,7 +127,9 @@
     "webpack-dev-middleware": "^1.6.1",
     "webpack-dev-server": "^1.15.1",
     "webpack-hot-middleware": "^2.12.2",
-    "webpack-material-design-icons": "^0.1.0"
+    "webpack-material-design-icons": "^0.1.0",
+    "directory-tree": "^2.1.0",
+    "jsonminify": "^0.4.1"
   },
   "engine": "node >= 5.9.0",
   "nyc": {
diff --git a/ui/src/app/app.config.js b/ui/src/app/app.config.js
index a84bdde..3ae2122 100644
--- a/ui/src/app/app.config.js
+++ b/ui/src/app/app.config.js
@@ -15,10 +15,6 @@
  */
 import injectTapEventPlugin from 'react-tap-event-plugin';
 import UrlHandler from './url.handler';
-import addLocaleKorean from './locale/locale.constant-ko';
-import addLocaleChinese from './locale/locale.constant-zh';
-import addLocaleRussian from './locale/locale.constant-ru';
-import addLocaleSpanish from './locale/locale.constant-es';
 
 /* eslint-disable import/no-unresolved, import/default */
 
@@ -38,46 +34,24 @@ export default function AppConfig($provide,
                                   $mdThemingProvider,
                                   $httpProvider,
                                   $translateProvider,
-                                  storeProvider,
-                                  locales) {
+                                  storeProvider) {
 
     injectTapEventPlugin();
     $locationProvider.html5Mode(true);
     $urlRouterProvider.otherwise(UrlHandler);
     storeProvider.setCaching(false);
-
-    $translateProvider.useSanitizeValueStrategy(null);
-    $translateProvider.useMissingTranslationHandler('tbMissingTranslationHandler');
-    $translateProvider.addInterpolation('$translateMessageFormatInterpolation');
-    $translateProvider.fallbackLanguage('en_US');
-
-    addLocaleKorean(locales);
-    addLocaleChinese(locales);
-    addLocaleRussian(locales);
-    addLocaleSpanish(locales);
-
-    for (var langKey in locales) {
-        var translationTable = locales[langKey];
-        $translateProvider.translations(langKey, translationTable);
-    }
-
-    var lang = $translateProvider.resolveClientLocale();
-    if (lang) {
-        lang = lang.toLowerCase();
-        if (lang.startsWith('ko')) {
-            $translateProvider.preferredLanguage('ko_KR');
-        } else if (lang.startsWith('zh')) {
-            $translateProvider.preferredLanguage('zh_CN');
-        } else if (lang.startsWith('es')) {
-            $translateProvider.preferredLanguage('es_ES');
-        } else if (lang.startsWith('ru')) {
-            $translateProvider.preferredLanguage('ru_RU');
-        } else {
-            $translateProvider.preferredLanguage('en_US');
-        }
-    } else {
-        $translateProvider.preferredLanguage('en_US');
-    }
+    
+    $translateProvider.useSanitizeValueStrategy(null)
+                      .useMissingTranslationHandler('tbMissingTranslationHandler')
+                      .addInterpolation('$translateMessageFormatInterpolation')
+                      .useStaticFilesLoader({
+                          prefix: PUBLIC_PATH + 'locale/locale.constant-', //eslint-disable-line
+                          suffix: '.json'
+                      })
+                      .registerAvailableLanguageKeys(SUPPORTED_LANGS, getLanguageAliases(SUPPORTED_LANGS)) //eslint-disable-line
+                      .fallbackLanguage('en_US') // must be before determinePreferredLanguage   
+                      .uniformLanguageTag('java')  // must be before determinePreferredLanguage
+                      .determinePreferredLanguage();                
 
     $httpProvider.interceptors.push('globalInterceptor');
 
@@ -168,4 +142,24 @@ export default function AppConfig($provide,
         //$mdThemingProvider.alwaysWatchTheme(true);
     }
 
+    function getLanguageAliases(supportedLangs) {
+        var aliases = {};
+
+        supportedLangs.sort().forEach(function(item, index, array) {
+            if (item.length === 2) { 
+                aliases[item] = item;
+                aliases[item + '_*'] = item;
+            } else {
+                var key = item.slice(0, 2);
+                if (index === 0 || key !== array[index - 1].slice(0, 2)) {
+                    aliases[key] = item;
+                    aliases[key + '_*'] = item;
+                } else {
+                    aliases[item] = item;
+                }
+            }
+        });
+        
+        return aliases;
+    }
 }
\ No newline at end of file
diff --git a/ui/src/app/app.js b/ui/src/app/app.js
index f021efb..c8cdeb0 100644
--- a/ui/src/app/app.js
+++ b/ui/src/app/app.js
@@ -51,7 +51,7 @@ import react from 'ngreact';
 import '@flowjs/ng-flow/dist/ng-flow-standalone.min';
 import 'ngFlowchart/dist/ngFlowchart';
 
-import thingsboardLocales from './locale/locale.constant';
+import thingsboardTranslateHandler from './locale/translate-handler';
 import thingsboardLogin from './login';
 import thingsboardDialogs from './components/datakey-config-dialog.controller';
 import thingsboardMenu from './services/menu.service';
@@ -117,7 +117,7 @@ angular.module('thingsboard', [
     react.name,
     'flow',
     'flowchart',
-    thingsboardLocales,
+    thingsboardTranslateHandler,
     thingsboardLogin,
     thingsboardDialogs,
     thingsboardMenu,
diff --git a/ui/src/app/locale/translate-handler.js b/ui/src/app/locale/translate-handler.js
index 11feb00..9fb28f5 100644
--- a/ui/src/app/locale/translate-handler.js
+++ b/ui/src/app/locale/translate-handler.js
@@ -13,8 +13,12 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+ export default angular.module('thingsboard.locale', [])
+                       .factory('tbMissingTranslationHandler', ThingsboardMissingTranslateHandler)
+                       .name;
+
 /*@ngInject*/
-export default function ThingsboardMissingTranslateHandler($log, types) {
+function ThingsboardMissingTranslateHandler($log, types) {
 
     return function (translationId) {
         if (translationId && !translationId.startsWith(types.translate.customTranslationsPrefix)) {
diff --git a/ui/src/app/profile/profile.controller.js b/ui/src/app/profile/profile.controller.js
index d17a65a..b947bde 100644
--- a/ui/src/app/profile/profile.controller.js
+++ b/ui/src/app/profile/profile.controller.js
@@ -24,16 +24,9 @@ export default function ProfileController(userService, $scope, $document, $mdDia
     var vm = this;
 
     vm.profileUser = {};
-
     vm.save = save;
     vm.changePassword = changePassword;
-    vm.languageList = {
-        en_US: {value : "en_US", name: "language.en_US"}, 
-        ko_KR: {value : "ko_KR", name: "language.ko_KR"},
-        zh_CN: {value : "zh_CN", name: "language.zh_CN"},
-        ru_RU: {value : "ru_RU", name: "language.ru_RU"},
-        es_ES: {value : "es_ES", name: "language.es_ES"},
-    };
+    vm.languageList = SUPPORTED_LANGS; //eslint-disable-line
 
     loadProfile();
 
diff --git a/ui/src/app/profile/profile.tpl.html b/ui/src/app/profile/profile.tpl.html
index a0358c1..58e4aac 100644
--- a/ui/src/app/profile/profile.tpl.html
+++ b/ui/src/app/profile/profile.tpl.html
@@ -43,8 +43,8 @@
                     <md-input-container class="md-block">
                         <label translate>language.language</label>
                         <md-select name="language" ng-model="vm.profileUser.additionalInfo.lang">
-                            <md-option ng-repeat="lang in vm.languageList" ng-value="lang.value">
-                                {{lang.name | translate}}
+                            <md-option ng-repeat="lang in vm.languageList" ng-value="lang">
+                                {{ 'language.locales.' + lang | translate}}
                             </md-option>
                         </md-select>
                     </md-input-container>
diff --git a/ui/webpack.config.dev.js b/ui/webpack.config.dev.js
index b1a1911..7d2b0d3 100644
--- a/ui/webpack.config.dev.js
+++ b/ui/webpack.config.dev.js
@@ -20,6 +20,17 @@ const ExtractTextPlugin = require('extract-text-webpack-plugin');
 const CopyWebpackPlugin = require('copy-webpack-plugin');
 const webpack = require('webpack');
 const path = require('path');
+const dirTree = require('directory-tree');
+const jsonminify = require("jsonminify");
+
+const PUBLIC_RESOURCE_PATH = '/';
+
+var langs = [];
+dirTree('./src/app/locale/', {extensions:/\.json$/}, (item) => {
+    /* It is expected what the name of a locale file has the following format: */
+    /* 'locale.constant-LANG_CODE[_REGION_CODE].json', e.g. locale.constant-es.json or locale.constant-zh_CN.json*/
+    langs.push(item.name.slice(item.name.lastIndexOf('-') + 1, -5));
+});
 
 /* devtool: 'cheap-module-eval-source-map', */
 
@@ -32,7 +43,7 @@ module.exports = {
     ],
     output: {
         path: path.resolve(__dirname, 'target/generated-resources/public/static'),
-        publicPath: '/',
+        publicPath: PUBLIC_RESOURCE_PATH,
         filename: 'bundle.js',
     },
     plugins: [
@@ -45,7 +56,18 @@ module.exports = {
             moment: "moment"
         }),
         new CopyWebpackPlugin([
-            { from: './src/thingsboard.ico', to: 'thingsboard.ico' }
+            {
+                from: './src/thingsboard.ico',
+                to: 'thingsboard.ico'
+            },
+            {
+                from: './src/app/locale',
+                to: 'locale',
+                ignore: [ '*.js' ],
+                transform: function(content, path) {
+                    return Buffer.from(jsonminify(content.toString()));
+                }
+            }
         ]),
         new webpack.HotModuleReplacementPlugin(),
         new HtmlWebpackPlugin({
@@ -65,6 +87,8 @@ module.exports = {
             'process.env': {
                 NODE_ENV: JSON.stringify('development'),
             },
+            PUBLIC_PATH: PUBLIC_RESOURCE_PATH,
+            SUPPORTED_LANGS: JSON.stringify(langs)
         }),
     ],
     node: {
@@ -117,7 +141,7 @@ module.exports = {
                     'url?limit=8192',
                     'img?minimize'
                 ]
-            },
+            }
         ],
     },
     'html-minifier-loader': {
diff --git a/ui/webpack.config.prod.js b/ui/webpack.config.prod.js
index f02b880..a442590 100644
--- a/ui/webpack.config.prod.js
+++ b/ui/webpack.config.prod.js
@@ -21,6 +21,17 @@ const CopyWebpackPlugin = require('copy-webpack-plugin');
 const CompressionPlugin = require('compression-webpack-plugin');
 const webpack = require('webpack');
 const path = require('path');
+const dirTree = require('directory-tree');
+const jsonminify = require("jsonminify");
+
+const PUBLIC_RESOURCE_PATH = '/static/';
+
+var langs = [];
+dirTree('./src/app/locale/', {extensions:/\.json$/}, (item) => {
+    /* It is expected what the name of a locale file has the following format: */
+    /* 'locale.constant-LANG_CODE[_REGION_CODE].json', e.g. locale.constant-es.json or locale.constant-zh_CN.json*/
+    langs.push(item.name.slice(item.name.lastIndexOf('-') + 1, -5));
+});
 
 module.exports = {
     devtool: 'source-map',
@@ -30,7 +41,7 @@ module.exports = {
     ],
     output: {
         path: path.resolve(__dirname, 'target/generated-resources/public/static'),
-        publicPath: '/static/',
+        publicPath: PUBLIC_RESOURCE_PATH,
         filename: 'bundle.[hash].js',
     },
     plugins: [
@@ -43,7 +54,18 @@ module.exports = {
             moment: "moment"
         }),
         new CopyWebpackPlugin([
-            {from: './src/thingsboard.ico', to: 'thingsboard.ico'}
+            {
+                from: './src/thingsboard.ico',
+                to: 'thingsboard.ico'
+            },
+            {
+                from: './src/app/locale',
+                to: 'locale',
+                ignore: [ '*.js' ],
+                transform: function(content, path) {
+                    return Buffer.from(jsonminify(content.toString()));
+                }
+            }
         ]),
         new HtmlWebpackPlugin({
             template: './src/index.html',
@@ -64,11 +86,13 @@ module.exports = {
             'process.env': {
                 NODE_ENV: JSON.stringify('production'),
             },
+            PUBLIC_PATH: PUBLIC_RESOURCE_PATH,
+            SUPPORTED_LANGS: JSON.stringify(langs)
         }),
         new CompressionPlugin({
             asset: "[path].gz[query]",
             algorithm: "gzip",
-            test: /\.js$|\.css$|\.svg$|\.ttf$|\.woff$|\.woff2|\.eot$/,
+            test: /\.js$|\.css$|\.svg$|\.ttf$|\.woff$|\.woff2|\.eot$\.json$/,
             threshold: 10240,
             minRatio: 0.8
         })
@@ -123,7 +147,7 @@ module.exports = {
                     'url?limit=8192',
                     'img?minimize'
                 ]
-            },
+            }
         ],
     },
     'html-minifier-loader': {