From 40b94a38a86aa0d2a4cc38861c3d1bd64e3feb3e Mon Sep 17 00:00:00 2001 From: Takao Fujiwara Date: Fri, 7 Oct 2016 18:43:33 +0900 Subject: [PATCH 1/4] Enable message i18n with angular-gettext Signed-off-by: Takao Fujiwara --- Makefile | 41 +- awx/ui/Gruntfile.js | 1 + awx/ui/client/src/about/about.controller.js | 4 +- awx/ui/client/src/about/about.partial.html | 2 +- awx/ui/client/src/app.js | 36 +- .../src/bread-crumb/bread-crumb.partial.html | 2 +- awx/ui/client/src/controllers/Projects.js | 112 +- awx/ui/client/src/controllers/Users.js | 34 +- .../counts/dashboard-counts.directive.js | 15 +- .../graphs/dashboard-graphs.partial.html | 34 +- .../job-status/job-status-graph.directive.js | 11 +- .../dashboard/hosts/dashboard-hosts.list.js | 8 +- .../job-templates-list.partial.html | 14 +- .../lists/jobs/jobs-list.partial.html | 12 +- awx/ui/client/src/forms/Credentials.js | 111 +- awx/ui/client/src/forms/Inventories.js | 35 +- awx/ui/client/src/forms/JobTemplates.js | 154 +- awx/ui/client/src/forms/Organizations.js | 25 +- awx/ui/client/src/forms/Projects.js | 78 +- awx/ui/client/src/forms/Teams.js | 41 +- awx/ui/client/src/forms/Users.js | 47 +- awx/ui/client/src/helpers/Credentials.js | 92 +- awx/ui/client/src/i18n.js | 97 + .../inventory-scripts.form.js | 20 +- .../inventory-scripts.list.js | 28 +- .../add/job-templates-add.route.js | 3 +- .../client/src/license/license.controller.js | 11 +- .../client/src/license/license.partial.html | 52 +- awx/ui/client/src/lists/CompletedJobs.js | 21 +- awx/ui/client/src/lists/Credentials.js | 37 +- awx/ui/client/src/lists/Inventories.js | 41 +- awx/ui/client/src/lists/JobTemplates.js | 47 +- awx/ui/client/src/lists/PortalJobTemplates.js | 19 +- awx/ui/client/src/lists/PortalJobs.js | 15 +- awx/ui/client/src/lists/Projects.js | 34 +- awx/ui/client/src/lists/ScheduledJobs.js | 29 +- awx/ui/client/src/lists/Teams.js | 33 +- awx/ui/client/src/lists/Users.js | 33 +- .../login/loginModal/loginModal.partial.html | 8 +- .../src/main-menu/main-menu.partial.html | 34 +- .../management-jobs/card/card.partial.html | 8 +- .../notificationTemplates.form.js | 108 +- .../notificationTemplates.list.js | 30 +- .../src/notifications/notifications.list.js | 20 +- .../shared/type-change.service.js | 18 +- .../list/organizations-list.partial.html | 11 +- awx/ui/client/src/partials/breadcrumb.html | 4 +- awx/ui/client/src/partials/jobs.html | 8 +- .../portal-mode/portal-mode-jobs.partial.html | 6 +- .../src/setup-menu/setup-menu.partial.html | 36 +- awx/ui/client/src/shared/form-generator.js | 98 +- .../list-generator/list-generator.factory.js | 13 +- .../src/shared/socket/socket.service.js | 6 +- awx/ui/grunt-tasks/concurrent.js | 4 +- awx/ui/grunt-tasks/copy.js | 8 + awx/ui/grunt-tasks/nggettext_compile.js | 15 + awx/ui/grunt-tasks/nggettext_extract.js | 11 + awx/ui/package.json | 4 + awx/ui/po/ansible-tower.pot | 2041 +++++++++++++++++ awx/ui/webpack.config.js | 1 + 60 files changed, 3116 insertions(+), 805 deletions(-) create mode 100644 awx/ui/client/src/i18n.js create mode 100644 awx/ui/grunt-tasks/nggettext_compile.js create mode 100644 awx/ui/grunt-tasks/nggettext_extract.js create mode 100644 awx/ui/po/ansible-tower.pot diff --git a/Makefile b/Makefile index d74468a9e7..3112a2f4bd 100644 --- a/Makefile +++ b/Makefile @@ -81,7 +81,7 @@ SETUP_TAR_CHECKSUM=$(NAME)-setup-CHECKSUM # DEB build parameters DEBUILD_BIN ?= debuild -DEBUILD_OPTS = +DEBUILD_OPTS = DPUT_BIN ?= dput DPUT_OPTS ?= -c .dput.cf -u REPREPRO_BIN ?= reprepro @@ -506,6 +506,43 @@ test_jenkins : test_coverage # UI TASKS # -------------------------------------- +HAVE_PO := $(shell ls awx/ui/po/*.po 2>/dev/null) +check-po: +ifdef HAVE_PO + # Should be 'Language: zh-CN' but not 'Language: zh_CN' in zh_CN.po + for po in awx/ui/po/*.po ; do \ + echo $$po; \ + mo="awx/ui/po/`basename $$po .po`.mo"; \ + msgfmt --check --verbose $$po -o $$mo; \ + if test "$$?" -ne 0 ; then \ + exit -1; \ + fi; \ + rm $$mo; \ + name=`echo "$$po" | grep '-'`; \ + if test "x$$name" != x ; then \ + right_name=`echo $$language | sed -e 's/-/_/'`; \ + echo "ERROR: WRONG $$name CORRECTION: $$right_name"; \ + exit -1; \ + fi; \ + language=`grep '^"Language:' "$$po" | grep '_'`; \ + if test "x$$language" != x ; then \ + right_language=`echo $$language | sed -e 's/_/-/'`; \ + echo "ERROR: WRONG $$language CORRECTION: $$right_language in $$po"; \ + exit -1; \ + fi; \ + done; +else + @echo No PO files +endif + +# generate l10n .json +languages: awx/ui/package.json check-po + $(NPM_BIN) --prefix awx/ui run languages + +# generate .pot +pot: awx/ui/package.json + $(NPM_BIN) --prefix awx/ui run pot + ui-deps: $(UI_DEPS_FLAG_FILE) $(UI_DEPS_FLAG_FILE): awx/ui/package.json @@ -518,7 +555,7 @@ ui-docker-machine: $(UI_DEPS_FLAG_FILE) ui-docker: $(UI_DEPS_FLAG_FILE) $(NPM_BIN) --prefix awx/ui run build-docker-cid -ui-release: $(UI_RELEASE_FLAG_FILE) +ui-release: languages $(UI_RELEASE_FLAG_FILE) $(UI_RELEASE_FLAG_FILE): $(UI_DEPS_FLAG_FILE) $(NPM_BIN) --prefix awx/ui run build-release diff --git a/awx/ui/Gruntfile.js b/awx/ui/Gruntfile.js index 57fddad6ed..16b61f0405 100644 --- a/awx/ui/Gruntfile.js +++ b/awx/ui/Gruntfile.js @@ -16,6 +16,7 @@ module.exports = function(grunt) { // Project configuration. grunt.initConfig(configs); grunt.loadNpmTasks('grunt-newer'); + grunt.loadNpmTasks('grunt-angular-gettext'); // writes environment variables for development. current manages: // browser-sync + websocket proxy diff --git a/awx/ui/client/src/about/about.controller.js b/awx/ui/client/src/about/about.controller.js index 90824532db..2c821b9e09 100644 --- a/awx/ui/client/src/about/about.controller.js +++ b/awx/ui/client/src/about/about.controller.js @@ -1,5 +1,6 @@ export default - ['$scope', '$state', 'ConfigService', function($scope, $state, ConfigService){ + ['$scope', '$state', 'ConfigService', 'i18n', + function($scope, $state, ConfigService, i18n){ var processVersion = function(version){ // prettify version & calculate padding // e,g 3.0.0-0.git201602191743/ -> 3.0.0 @@ -20,6 +21,7 @@ export default .then(function(config){ $scope.subscription = config.license_info.subscription_name; $scope.version = processVersion(config.version); + $scope.version_str = i18n._("Version"); $('#about-modal').modal('show'); }); }; diff --git a/awx/ui/client/src/about/about.partial.html b/awx/ui/client/src/about/about.partial.html index 65cfd11f03..bcb2a5cd33 100644 --- a/awx/ui/client/src/about/about.partial.html +++ b/awx/ui/client/src/about/about.partial.html @@ -11,7 +11,7 @@
  ________________
-/  Tower Version \\
+/  Tower {{version_str}} \\
 \\{{version}}/
  ----------------
         \\   ^__^
diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js
index 6df9567b34..4e4f5b0b92 100644
--- a/awx/ui/client/src/app.js
+++ b/awx/ui/client/src/app.js
@@ -7,6 +7,7 @@
 // Vendor dependencies
 import 'jquery';
 import 'angular';
+import 'angular-gettext';
 import 'bootstrap';
 import 'jquery-ui';
 import 'bootstrap-datepicker';
@@ -79,6 +80,7 @@ import config from './shared/config/main';
 import './login/authenticationServices/pendo/ng-pendo';
 import footer from './footer/main';
 import scheduler from './scheduler/main';
+import {N_} from './i18n';
 
 var tower = angular.module('Tower', [
     // how to add CommonJS / AMD  third-party dependencies:
@@ -203,6 +205,8 @@ var tower = angular.module('Tower', [
     scheduler.name,
     'ApiModelHelper',
     'ActivityStreamHelper',
+    'gettext',
+    'I18N',
 ])
 
 .constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
@@ -237,6 +241,10 @@ var tower = angular.module('Tower', [
                 $state.go('dashboard');
             });
 
+            /* Mark translatable strings with N_() and
+             * extract them by 'grunt nggettext_extract'
+             * but angular.config() cannot get gettextCatalog.
+             */
             $stateProvider.
             state('teams', {
                 url: '/teams',
@@ -248,7 +256,7 @@ var tower = angular.module('Tower', [
                 },
                 ncyBreadcrumb: {
                     parent: 'setup',
-                    label: 'TEAMS'
+                    label: N_("TEAMS")
                 }
             }).
 
@@ -258,7 +266,7 @@ var tower = angular.module('Tower', [
                 controller: TeamsAdd,
                 ncyBreadcrumb: {
                     parent: "teams",
-                    label: "CREATE TEAM"
+                    label: N_("CREATE TEAM")
                 }
             }).
 
@@ -333,7 +341,7 @@ var tower = angular.module('Tower', [
                 },
                 ncyBreadcrumb: {
                     parent: 'setup',
-                    label: 'CREDENTIALS'
+                    label: N_("CREDENTIALS")
                 }
             }).
 
@@ -343,7 +351,7 @@ var tower = angular.module('Tower', [
                 controller: CredentialsAdd,
                 ncyBreadcrumb: {
                     parent: "credentials",
-                    label: "CREATE CREDENTIAL"
+                    label: N_("CREATE CREDENTIAL")
                 }
             }).
 
@@ -370,7 +378,7 @@ var tower = angular.module('Tower', [
                 },
                 ncyBreadcrumb: {
                     parent: 'setup',
-                    label: 'USERS'
+                    label: N_("USERS")
                 }
             }).
 
@@ -380,7 +388,7 @@ var tower = angular.module('Tower', [
                 controller: UsersAdd,
                 ncyBreadcrumb: {
                     parent: "users",
-                    label: "CREATE USER"
+                    label: N_("CREATE USER")
                 }
             }).
 
@@ -420,7 +428,7 @@ var tower = angular.module('Tower', [
                 templateUrl: urlPrefix + 'partials/sockets.html',
                 controller: SocketsController,
                 ncyBreadcrumb: {
-                    label: 'SOCKETS'
+                    label: N_("SOCKETS")
                 }
             });
         }
@@ -443,12 +451,12 @@ var tower = angular.module('Tower', [
     'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer',
     'ClearScope', 'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest',
     'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
-    'FeaturesService', '$filter', 'SocketService',
+    'FeaturesService', '$filter', 'SocketService', 'I18NInit',
     function($stateExtender, $q, $compile, $cookieStore, $rootScope, $log,
         CheckLicense, $location, Authorization, LoadBasePaths, Timer,
         ClearScope, LoadConfig, Store, pendoService, Prompt, Rest, Wait,
         ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService,
-        $filter, SocketService) {
+        $filter, SocketService, I18NInit) {
 
         $stateExtender.addState({
             name: 'dashboard',
@@ -466,7 +474,7 @@ var tower = angular.module('Tower', [
                 refreshButton: true
             },
             ncyBreadcrumb: {
-                label: "DASHBOARD"
+                label: N_("DASHBOARD")
             },
             resolve: {
                 graphData: ['$q', 'jobStatusGraphData', '$rootScope',
@@ -487,7 +495,7 @@ var tower = angular.module('Tower', [
             templateUrl: urlPrefix + 'partials/jobs.html',
             controller: JobsListController,
             ncyBreadcrumb: {
-                label: "JOBS"
+                label: N("JOBS")
             },
             params: {
                 search: {
@@ -512,7 +520,7 @@ var tower = angular.module('Tower', [
                 activityStreamTarget: 'project'
             },
             ncyBreadcrumb: {
-                label: "PROJECTS"
+                label: N("PROJECTS")
             },
             socket: {
                 "groups":{
@@ -528,7 +536,7 @@ var tower = angular.module('Tower', [
             controller: ProjectsAdd,
             ncyBreadcrumb: {
                 parent: "projects",
-                label: "CREATE PROJECT"
+                label: N("CREATE PROJECT")
             },
             socket: {
                 "groups":{
@@ -570,6 +578,8 @@ var tower = angular.module('Tower', [
             controller: OrganizationsAdd
         });
 
+        I18NInit();
+
         $rootScope.addPermission = function(scope) {
             $compile("")(scope);
         };
diff --git a/awx/ui/client/src/bread-crumb/bread-crumb.partial.html b/awx/ui/client/src/bread-crumb/bread-crumb.partial.html
index 8e661904ba..4500556e96 100644
--- a/awx/ui/client/src/bread-crumb/bread-crumb.partial.html
+++ b/awx/ui/client/src/bread-crumb/bread-crumb.partial.html
@@ -3,7 +3,7 @@