mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 01:47:35 -02:30
Implement manual initialzation for Angular app
Manual initialization allows for some asynchronous work to finish ahead of Angular's startup. The initial motivation is to be able to guarantee translation files have been fetched before rendering content that needs translation. If a locale isn't supported or if the request to get a json file fails, the i18n service falls back to en. Signed-off-by: gconsidine <gconsidi@redhat.com>
This commit is contained in:
@@ -17,3 +17,4 @@ test
|
|||||||
!client/lib/models/**/*.js
|
!client/lib/models/**/*.js
|
||||||
!client/lib/services/**/*.js
|
!client/lib/services/**/*.js
|
||||||
!client/features/**/*.js
|
!client/features/**/*.js
|
||||||
|
!client/src/app.start.js
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ module.exports = {
|
|||||||
'no-param-reassign': 'off',
|
'no-param-reassign': 'off',
|
||||||
'no-plusplus': 'off',
|
'no-plusplus': 'off',
|
||||||
'no-underscore-dangle': 'off',
|
'no-underscore-dangle': 'off',
|
||||||
|
'no-use-before-define': 'off',
|
||||||
'object-curly-newline': 'off',
|
'object-curly-newline': 'off',
|
||||||
'space-before-function-paren': ['error', 'always']
|
'space-before-function-paren': ['error', 'always']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ const base = {
|
|||||||
jsonlint: 'codemirror.jsonlint'
|
jsonlint: 'codemirror.jsonlint'
|
||||||
}),
|
}),
|
||||||
new ExtractTextPlugin('css/[name].[chunkhash].css'),
|
new ExtractTextPlugin('css/[name].[chunkhash].css'),
|
||||||
new CleanWebpackPlugin([STATIC_PATH, COVERAGE_PATH, LANGUAGES_PATH], {
|
new CleanWebpackPlugin([STATIC_PATH, COVERAGE_PATH], {
|
||||||
root: UI_PATH,
|
root: UI_PATH,
|
||||||
verbose: false
|
verbose: false
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
const path = require('path');
|
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
|
|
||||||
const base = require('./webpack.base');
|
const base = require('./webpack.base');
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
const path = require('path');
|
|
||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
|
||||||
const STATIC_URL = '/static/';
|
const STATIC_URL = '/static/';
|
||||||
|
|
||||||
const development = require('./webpack.development');
|
const development = require('./webpack.base');
|
||||||
|
|
||||||
const test = {
|
const test = {
|
||||||
|
devtool: 'cheap-source-map',
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.DefinePlugin({
|
new webpack.DefinePlugin({
|
||||||
$basePath: STATIC_URL
|
$basePath: STATIC_URL
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ const path = require('path');
|
|||||||
|
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
|
|
||||||
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
|
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
|
||||||
|
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
|
||||||
|
|
||||||
const TARGET_PORT = _.get(process.env, 'npm_package_config_django_port', 8043);
|
const TARGET_PORT = _.get(process.env, 'npm_package_config_django_port', 8043);
|
||||||
const TARGET_HOST = _.get(process.env, 'npm_package_config_django_host', 'https://localhost');
|
const TARGET_HOST = _.get(process.env, 'npm_package_config_django_host', 'https://localhost');
|
||||||
@@ -29,6 +29,7 @@ const watch = {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
new HtmlWebpackHarddiskPlugin(),
|
||||||
new HardSourceWebpackPlugin({
|
new HardSourceWebpackPlugin({
|
||||||
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
|
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
|
||||||
recordsPath: 'node_modules/.cache/hard-source/[confighash]/records.json',
|
recordsPath: 'node_modules/.cache/hard-source/[confighash]/records.json',
|
||||||
@@ -41,7 +42,6 @@ const watch = {
|
|||||||
files: ['package.json']
|
files: ['package.json']
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
new HtmlWebpackHarddiskPlugin(),
|
|
||||||
new webpack.HotModuleReplacementPlugin()
|
new webpack.HotModuleReplacementPlugin()
|
||||||
],
|
],
|
||||||
devServer: {
|
devServer: {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import AddController from './add-credentials.controller';
|
|||||||
import EditController from './edit-credentials.controller';
|
import EditController from './edit-credentials.controller';
|
||||||
import CredentialsStrings from './credentials.strings';
|
import CredentialsStrings from './credentials.strings';
|
||||||
|
|
||||||
|
const MODULE_NAME = 'at.features.credentials';
|
||||||
|
|
||||||
const addEditTemplate = require('~features/credentials/add-edit-credentials.view.html');
|
const addEditTemplate = require('~features/credentials/add-edit-credentials.view.html');
|
||||||
|
|
||||||
function CredentialsResolve ($q, $stateParams, Me, Credential, CredentialType, Organization) {
|
function CredentialsResolve ($q, $stateParams, Me, Credential, CredentialType, Organization) {
|
||||||
@@ -51,12 +53,8 @@ CredentialsResolve.$inject = [
|
|||||||
'OrganizationModel'
|
'OrganizationModel'
|
||||||
];
|
];
|
||||||
|
|
||||||
function CredentialsConfig ($stateExtenderProvider, legacyProvider, stringProvider) {
|
function CredentialsRun ($stateExtender, legacy, strings) {
|
||||||
const stateExtender = $stateExtenderProvider.$get();
|
$stateExtender.addState({
|
||||||
const legacy = legacyProvider.$get();
|
|
||||||
const strings = stringProvider.$get();
|
|
||||||
|
|
||||||
stateExtender.addState({
|
|
||||||
name: 'credentials.add',
|
name: 'credentials.add',
|
||||||
route: '/add',
|
route: '/add',
|
||||||
ncyBreadcrumb: {
|
ncyBreadcrumb: {
|
||||||
@@ -78,7 +76,7 @@ function CredentialsConfig ($stateExtenderProvider, legacyProvider, stringProvid
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stateExtender.addState({
|
$stateExtender.addState({
|
||||||
name: 'credentials.edit',
|
name: 'credentials.edit',
|
||||||
route: '/:credential_id',
|
route: '/:credential_id',
|
||||||
ncyBreadcrumb: {
|
ncyBreadcrumb: {
|
||||||
@@ -101,25 +99,27 @@ function CredentialsConfig ($stateExtenderProvider, legacyProvider, stringProvid
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
stateExtender.addState(legacy.getStateConfiguration('list'));
|
$stateExtender.addState(legacy.getStateConfiguration('list'));
|
||||||
stateExtender.addState(legacy.getStateConfiguration('edit-permissions'));
|
$stateExtender.addState(legacy.getStateConfiguration('edit-permissions'));
|
||||||
stateExtender.addState(legacy.getStateConfiguration('add-permissions'));
|
$stateExtender.addState(legacy.getStateConfiguration('add-permissions'));
|
||||||
stateExtender.addState(legacy.getStateConfiguration('add-organization'));
|
$stateExtender.addState(legacy.getStateConfiguration('add-organization'));
|
||||||
stateExtender.addState(legacy.getStateConfiguration('edit-organization'));
|
$stateExtender.addState(legacy.getStateConfiguration('edit-organization'));
|
||||||
stateExtender.addState(legacy.getStateConfiguration('add-credential-type'));
|
$stateExtender.addState(legacy.getStateConfiguration('add-credential-type'));
|
||||||
stateExtender.addState(legacy.getStateConfiguration('edit-credential-type'));
|
$stateExtender.addState(legacy.getStateConfiguration('edit-credential-type'));
|
||||||
}
|
}
|
||||||
|
|
||||||
CredentialsConfig.$inject = [
|
CredentialsRun.$inject = [
|
||||||
'$stateExtenderProvider',
|
'$stateExtender',
|
||||||
'LegacyCredentialsServiceProvider',
|
'LegacyCredentialsService',
|
||||||
'CredentialsStringsProvider'
|
'CredentialsStrings'
|
||||||
];
|
];
|
||||||
|
|
||||||
angular
|
angular
|
||||||
.module('at.features.credentials', [])
|
.module(MODULE_NAME, [])
|
||||||
.config(CredentialsConfig)
|
|
||||||
.controller('AddController', AddController)
|
.controller('AddController', AddController)
|
||||||
.controller('EditController', EditController)
|
.controller('EditController', EditController)
|
||||||
.service('LegacyCredentialsService', LegacyCredentials)
|
.service('LegacyCredentialsService', LegacyCredentials)
|
||||||
.service('CredentialsStrings', CredentialsStrings);
|
.service('CredentialsStrings', CredentialsStrings)
|
||||||
|
.run(CredentialsRun);
|
||||||
|
|
||||||
|
export default MODULE_NAME;
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
import '~features/credentials';
|
import atLibServices from '~services';
|
||||||
|
import atLibComponents from '~components';
|
||||||
|
import atLibModels from '~models';
|
||||||
|
|
||||||
angular.module('at.features', [
|
import atFeaturesCredentials from '~features/credentials';
|
||||||
'at.features.credentials'
|
|
||||||
|
const MODULE_NAME = 'at.features';
|
||||||
|
|
||||||
|
angular.module(MODULE_NAME, [
|
||||||
|
atLibServices,
|
||||||
|
atLibComponents,
|
||||||
|
atLibModels,
|
||||||
|
atFeaturesCredentials
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export default MODULE_NAME;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" ng-app="awApp">
|
<html>
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en" ng-app="awApp">
|
<html>
|
||||||
<head>
|
<head>
|
||||||
{% load staticfiles %}
|
{% load staticfiles %}
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import atLibServices from '~services';
|
||||||
|
|
||||||
import actionGroup from '~components/action/action-group.directive';
|
import actionGroup from '~components/action/action-group.directive';
|
||||||
import divider from '~components/utility/divider.directive';
|
import divider from '~components/utility/divider.directive';
|
||||||
import form from '~components/form/form.directive';
|
import form from '~components/form/form.directive';
|
||||||
@@ -28,8 +30,12 @@ import truncate from '~components/truncate/truncate.directive';
|
|||||||
import BaseInputController from '~components/input/base.controller';
|
import BaseInputController from '~components/input/base.controller';
|
||||||
import ComponentsStrings from '~components/components.strings';
|
import ComponentsStrings from '~components/components.strings';
|
||||||
|
|
||||||
|
const MODULE_NAME = 'at.lib.components';
|
||||||
|
|
||||||
angular
|
angular
|
||||||
.module('at.lib.components', [])
|
.module(MODULE_NAME, [
|
||||||
|
atLibServices
|
||||||
|
])
|
||||||
.directive('atActionGroup', actionGroup)
|
.directive('atActionGroup', actionGroup)
|
||||||
.directive('atDivider', divider)
|
.directive('atDivider', divider)
|
||||||
.directive('atForm', form)
|
.directive('atForm', form)
|
||||||
@@ -58,3 +64,5 @@ angular
|
|||||||
.directive('atTruncate', truncate)
|
.directive('atTruncate', truncate)
|
||||||
.service('BaseInputController', BaseInputController)
|
.service('BaseInputController', BaseInputController)
|
||||||
.service('ComponentsStrings', ComponentsStrings);
|
.service('ComponentsStrings', ComponentsStrings);
|
||||||
|
|
||||||
|
export default MODULE_NAME;
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
import atLibServices from '~services';
|
||||||
|
|
||||||
import Base from '~models/Base';
|
import Base from '~models/Base';
|
||||||
import Config from '~models/Config';
|
import Config from '~models/Config';
|
||||||
import Credential from '~models/Credential';
|
import Credential from '~models/Credential';
|
||||||
@@ -5,11 +7,17 @@ import CredentialType from '~models/CredentialType';
|
|||||||
import Me from '~models/Me';
|
import Me from '~models/Me';
|
||||||
import Organization from '~models/Organization';
|
import Organization from '~models/Organization';
|
||||||
|
|
||||||
|
const MODULE_NAME = 'at.lib.models';
|
||||||
|
|
||||||
angular
|
angular
|
||||||
.module('at.lib.models', [])
|
.module(MODULE_NAME, [
|
||||||
|
atLibServices
|
||||||
|
])
|
||||||
.service('BaseModel', Base)
|
.service('BaseModel', Base)
|
||||||
.service('ConfigModel', Config)
|
.service('ConfigModel', Config)
|
||||||
.service('CredentialModel', Credential)
|
.service('CredentialModel', Credential)
|
||||||
.service('CredentialTypeModel', CredentialType)
|
.service('CredentialTypeModel', CredentialType)
|
||||||
.service('MeModel', Me)
|
.service('MeModel', Me)
|
||||||
.service('OrganizationModel', Organization);
|
.service('OrganizationModel', Organization);
|
||||||
|
|
||||||
|
export default MODULE_NAME;
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
|
import AppStrings from '~services/app.strings';
|
||||||
|
import BaseStringService from '~services/base-string.service';
|
||||||
import CacheService from '~services/cache.service';
|
import CacheService from '~services/cache.service';
|
||||||
import EventService from '~services/event.service';
|
import EventService from '~services/event.service';
|
||||||
import BaseStringService from '~services/base-string.service';
|
|
||||||
import AppStrings from '~services/app.strings';
|
const MODULE_NAME = 'at.lib.services';
|
||||||
|
|
||||||
angular
|
angular
|
||||||
.module('at.lib.services', [])
|
.module(MODULE_NAME, [
|
||||||
|
'I18N'
|
||||||
|
])
|
||||||
.service('AppStrings', AppStrings)
|
.service('AppStrings', AppStrings)
|
||||||
.service('BaseStringService', BaseStringService)
|
.service('BaseStringService', BaseStringService)
|
||||||
.service('CacheService', CacheService)
|
.service('CacheService', CacheService)
|
||||||
.service('EventService', EventService);
|
.service('EventService', EventService);
|
||||||
|
|
||||||
|
export default MODULE_NAME;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// Configuration dependencies
|
// Configuration dependencies
|
||||||
global.$AnsibleConfig = null;
|
global.$AnsibleConfig = null;
|
||||||
// Provided via Webpack DefinePlugin in webpack.config.js
|
// Provided via Webpack DefinePlugin in webpack.config.js
|
||||||
global.$ENV = {} ;
|
global.$ENV = {};
|
||||||
// ui-router debugging
|
// ui-router debugging
|
||||||
if ($ENV['route-debug']){
|
if ($ENV['route-debug']){
|
||||||
let trace = angular.module('ui.router').trace;
|
let trace = angular.module('ui.router').trace;
|
||||||
@@ -14,7 +14,8 @@ if ($basePath) {
|
|||||||
urlPrefix = `${$basePath}`;
|
urlPrefix = `${$basePath}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Modules
|
import start from './app.start';
|
||||||
|
|
||||||
import portalMode from './portal-mode/main';
|
import portalMode from './portal-mode/main';
|
||||||
import systemTracking from './system-tracking/main';
|
import systemTracking from './system-tracking/main';
|
||||||
import inventoriesHosts from './inventories-hosts/main';
|
import inventoriesHosts from './inventories-hosts/main';
|
||||||
@@ -46,71 +47,76 @@ import access from './access/main';
|
|||||||
import scheduler from './scheduler/main';
|
import scheduler from './scheduler/main';
|
||||||
import instanceGroups from './instance-groups/main';
|
import instanceGroups from './instance-groups/main';
|
||||||
|
|
||||||
import '../lib/components';
|
import atFeatures from '~features';
|
||||||
import '../lib/models';
|
import atLibComponents from '~components';
|
||||||
import '../lib/services';
|
import atLibModels from '~models';
|
||||||
import '../features';
|
import atLibServices from '~services';
|
||||||
|
|
||||||
angular.module('awApp', [
|
start.bootstrap(() => {
|
||||||
'I18N',
|
angular.bootstrap(document.body, ['awApp']);
|
||||||
'AngularCodeMirrorModule',
|
});
|
||||||
'angular-duration-format',
|
|
||||||
'angularMoment',
|
|
||||||
'AngularScheduler',
|
|
||||||
'angular-md5',
|
|
||||||
'dndLists',
|
|
||||||
'ncy-angular-breadcrumb',
|
|
||||||
'ngSanitize',
|
|
||||||
'ngCookies',
|
|
||||||
'ngToast',
|
|
||||||
'gettext',
|
|
||||||
'Timezones',
|
|
||||||
'ui.router',
|
|
||||||
'ui.router.state.events',
|
|
||||||
'lrInfiniteScroll',
|
|
||||||
|
|
||||||
about.name,
|
angular
|
||||||
access.name,
|
.module('awApp', [
|
||||||
license.name,
|
'I18N',
|
||||||
RestServices.name,
|
'AngularCodeMirrorModule',
|
||||||
browserData.name,
|
'angular-duration-format',
|
||||||
configuration.name,
|
'angularMoment',
|
||||||
systemTracking.name,
|
'AngularScheduler',
|
||||||
inventoriesHosts.name,
|
'angular-md5',
|
||||||
inventoryScripts.name,
|
'dndLists',
|
||||||
credentials.name,
|
'ncy-angular-breadcrumb',
|
||||||
credentialTypes.name,
|
'ngSanitize',
|
||||||
organizations.name,
|
'ngCookies',
|
||||||
managementJobs.name,
|
'ngToast',
|
||||||
breadCrumb.name,
|
'gettext',
|
||||||
home.name,
|
'Timezones',
|
||||||
login.name,
|
'ui.router',
|
||||||
activityStream.name,
|
'ui.router.state.events',
|
||||||
workflowResults.name,
|
'lrInfiniteScroll',
|
||||||
jobResults.name,
|
|
||||||
jobSubmission.name,
|
|
||||||
notifications.name,
|
|
||||||
standardOut.name,
|
|
||||||
Templates.name,
|
|
||||||
portalMode.name,
|
|
||||||
jobs.name,
|
|
||||||
teams.name,
|
|
||||||
users.name,
|
|
||||||
projects.name,
|
|
||||||
scheduler.name,
|
|
||||||
instanceGroups.name,
|
|
||||||
|
|
||||||
'Utilities',
|
about.name,
|
||||||
'templates',
|
access.name,
|
||||||
'PromptDialog',
|
license.name,
|
||||||
'AWDirectives',
|
RestServices.name,
|
||||||
'features',
|
browserData.name,
|
||||||
|
configuration.name,
|
||||||
|
systemTracking.name,
|
||||||
|
inventoriesHosts.name,
|
||||||
|
inventoryScripts.name,
|
||||||
|
credentials.name,
|
||||||
|
credentialTypes.name,
|
||||||
|
organizations.name,
|
||||||
|
managementJobs.name,
|
||||||
|
breadCrumb.name,
|
||||||
|
home.name,
|
||||||
|
login.name,
|
||||||
|
activityStream.name,
|
||||||
|
workflowResults.name,
|
||||||
|
jobResults.name,
|
||||||
|
jobSubmission.name,
|
||||||
|
notifications.name,
|
||||||
|
standardOut.name,
|
||||||
|
Templates.name,
|
||||||
|
portalMode.name,
|
||||||
|
jobs.name,
|
||||||
|
teams.name,
|
||||||
|
users.name,
|
||||||
|
projects.name,
|
||||||
|
scheduler.name,
|
||||||
|
instanceGroups.name,
|
||||||
|
|
||||||
'at.lib.components',
|
'Utilities',
|
||||||
'at.lib.models',
|
'templates',
|
||||||
'at.lib.services',
|
'PromptDialog',
|
||||||
'at.features',
|
'AWDirectives',
|
||||||
])
|
'features',
|
||||||
|
|
||||||
|
atFeatures,
|
||||||
|
atLibComponents,
|
||||||
|
atLibModels,
|
||||||
|
atLibServices
|
||||||
|
])
|
||||||
.constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
|
.constant('AngularScheduler.partials', urlPrefix + 'lib/angular-scheduler/lib/')
|
||||||
.constant('AngularScheduler.useTimezone', true)
|
.constant('AngularScheduler.useTimezone', true)
|
||||||
.constant('AngularScheduler.showUTCField', true)
|
.constant('AngularScheduler.showUTCField', true)
|
||||||
@@ -171,13 +177,13 @@ angular.module('awApp', [
|
|||||||
'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer',
|
'CheckLicense', '$location', 'Authorization', 'LoadBasePaths', 'Timer',
|
||||||
'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest',
|
'LoadConfig', 'Store', 'pendoService', 'Prompt', 'Rest',
|
||||||
'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
|
'Wait', 'ProcessErrors', '$state', 'GetBasePath', 'ConfigService',
|
||||||
'FeaturesService', '$filter', 'SocketService', 'AppStrings', 'I18NInit',
|
'FeaturesService', '$filter', 'SocketService', 'AppStrings',
|
||||||
function($stateExtender, $q, $compile, $cookies, $rootScope, $log, $stateParams,
|
function($stateExtender, $q, $compile, $cookies, $rootScope, $log, $stateParams,
|
||||||
CheckLicense, $location, Authorization, LoadBasePaths, Timer,
|
CheckLicense, $location, Authorization, LoadBasePaths, Timer,
|
||||||
LoadConfig, Store, pendoService, Prompt, Rest, Wait,
|
LoadConfig, Store, pendoService, Prompt, Rest, Wait,
|
||||||
ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService,
|
ProcessErrors, $state, GetBasePath, ConfigService, FeaturesService,
|
||||||
$filter, SocketService, AppStrings, I18NInit) {
|
$filter, SocketService, AppStrings) {
|
||||||
I18NInit();
|
|
||||||
$rootScope.$state = $state;
|
$rootScope.$state = $state;
|
||||||
$rootScope.$state.matches = function(stateName) {
|
$rootScope.$state.matches = function(stateName) {
|
||||||
return $state.current.name.search(stateName) > 0;
|
return $state.current.name.search(stateName) > 0;
|
||||||
|
|||||||
72
awx/ui/client/src/app.start.js
Normal file
72
awx/ui/client/src/app.start.js
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
const SUPPORTED_LOCALES = ['en', 'es', 'fr', 'ja', 'nl'];
|
||||||
|
const DEFAULT_LOCALE = 'en';
|
||||||
|
const BASE_PATH = global.$basePath ? `${global.$basePath}languages/` : '/static/languages/';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Angular app is manually initialized in order to complete some
|
||||||
|
* asynchronous work up front. This function returns a callback so app.js can
|
||||||
|
* call `angular.bootstrap` when the work is complete.
|
||||||
|
*
|
||||||
|
* @argument {function} - Callback.
|
||||||
|
*/
|
||||||
|
function bootstrap (callback) {
|
||||||
|
fetchLocaleStrings((locale) => {
|
||||||
|
if (locale) {
|
||||||
|
angular.module('I18N').constant('LOCALE', locale);
|
||||||
|
}
|
||||||
|
|
||||||
|
angular.element(document).ready(() => callback());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GET the localized JSON strings file or fall back to the default language
|
||||||
|
* if the locale isn't supported or if the request fails.
|
||||||
|
*
|
||||||
|
* @argument {function} - Callback.
|
||||||
|
*
|
||||||
|
* @returns {object=} - Locale data if it exists.
|
||||||
|
*/
|
||||||
|
function fetchLocaleStrings (callback) {
|
||||||
|
const code = normalizeLocaleCode(navigator.language || navigator.userLanguage);
|
||||||
|
|
||||||
|
if (isDefaultLocale(code) || !isSupportedLocale(code)) {
|
||||||
|
callback({ code });
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const request = $.ajax(`${BASE_PATH}${code}.json`);
|
||||||
|
|
||||||
|
request.done(res => {
|
||||||
|
if (res[code]) {
|
||||||
|
callback({ code, strings: res[code] });
|
||||||
|
} else {
|
||||||
|
callback({ code: DEFAULT_LOCALE });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
request.fail(() => callback({ code: DEFAULT_LOCALE }));
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeLocaleCode (code) {
|
||||||
|
try {
|
||||||
|
code = code.split('-')[0].toLowerCase();
|
||||||
|
} catch (error) {
|
||||||
|
code = DEFAULT_LOCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isSupportedLocale (code) {
|
||||||
|
return SUPPORTED_LOCALES.includes(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isDefaultLocale (code) {
|
||||||
|
return code === DEFAULT_LOCALE;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
bootstrap
|
||||||
|
};
|
||||||
@@ -1,52 +1,36 @@
|
|||||||
/* jshint ignore:start */
|
import { sprintf } from 'sprintf-js';
|
||||||
|
|
||||||
var sprintf = require('sprintf-js').sprintf;
|
function I18n (gettextCatalog) {
|
||||||
let defaultLanguage = 'en_US';
|
return {
|
||||||
|
N_,
|
||||||
|
sprintf,
|
||||||
|
_: s => gettextCatalog.getString(s),
|
||||||
|
translate: (singular, context) => gettextCatalog.getString(singular, context),
|
||||||
|
translatePlural: (count, singular, plural, context) => {
|
||||||
|
return gettextCatalog.getPlural(count, singular, plural, context);
|
||||||
|
},
|
||||||
|
hasTranslation: () => gettextCatalog.strings[gettextCatalog.currentLanguage] !== undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
I18n.$inject = ['gettextCatalog'];
|
||||||
|
|
||||||
|
function run (LOCALE, gettextCatalog) {
|
||||||
|
if (LOCALE.code && LOCALE.strings) {
|
||||||
|
gettextCatalog.setCurrentLanguage(LOCALE.code);
|
||||||
|
gettextCatalog.setStrings(LOCALE.code, LOCALE.strings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
run.$inject = ['LOCALE', 'gettextCatalog'];
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc method
|
|
||||||
* @name function:i18n#N_
|
|
||||||
* @methodOf function:N_
|
|
||||||
* @description this function marks the translatable string with N_
|
|
||||||
* for 'grunt nggettext_extract'
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
export function N_(s) {
|
export function N_(s) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default
|
export default angular
|
||||||
angular.module('I18N', [])
|
.module('I18N', [
|
||||||
.factory('I18NInit', ['$window', 'gettextCatalog',
|
'gettext'
|
||||||
function ($window, gettextCatalog) {
|
])
|
||||||
return function() {
|
.factory('i18n', I18n)
|
||||||
var langInfo = ($window.navigator.languages || [])[0] ||
|
.run(run);
|
||||||
$window.navigator.language ||
|
|
||||||
$window.navigator.userLanguage ||
|
|
||||||
'';
|
|
||||||
var langUrl = langInfo.replace('-', '_');
|
|
||||||
|
|
||||||
if (langUrl === defaultLanguage) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// gettextCatalog.debug = true;
|
|
||||||
gettextCatalog.setCurrentLanguage(langInfo);
|
|
||||||
gettextCatalog.loadRemote('/static/languages/' + langUrl + '.json');
|
|
||||||
};
|
|
||||||
}])
|
|
||||||
.factory('i18n', ['gettextCatalog',
|
|
||||||
function (gettextCatalog) {
|
|
||||||
return {
|
|
||||||
_: function (s) { return gettextCatalog.getString (s); },
|
|
||||||
N_: N_,
|
|
||||||
translate: (singular, context) => gettextCatalog.getString(singular, context),
|
|
||||||
translatePlural: (count, singular, plural, context) => {
|
|
||||||
return gettextCatalog.getPlural(count, singular, plural, context);
|
|
||||||
},
|
|
||||||
sprintf: sprintf,
|
|
||||||
hasTranslation: function () {
|
|
||||||
return gettextCatalog.strings[gettextCatalog.currentLanguage] !== undefined;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}]);
|
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ module.exports = function(config) {
|
|||||||
reporters: ['progress', 'coverage', 'junit'],
|
reporters: ['progress', 'coverage', 'junit'],
|
||||||
files:[
|
files:[
|
||||||
'./client/src/vendor.js',
|
'./client/src/vendor.js',
|
||||||
'./client/src/app.js',
|
|
||||||
'./node_modules/angular-mocks/angular-mocks.js',
|
'./node_modules/angular-mocks/angular-mocks.js',
|
||||||
{ pattern: './tests/**/*-test.js' },
|
'./client/src/app.js',
|
||||||
'client/src/**/*.html'
|
'./tests/**/*-test.js',
|
||||||
|
'./client/src/**/*.html'
|
||||||
],
|
],
|
||||||
preprocessors: {
|
preprocessors: {
|
||||||
'./client/src/vendor.js': ['webpack', 'sourcemap'],
|
'./client/src/vendor.js': ['webpack'],
|
||||||
'./client/src/app.js': ['webpack', 'sourcemap'],
|
'./client/src/app.js': ['webpack'],
|
||||||
'./tests/**/*-test.js': ['webpack', 'sourcemap'],
|
'./tests/**/*-test.js': ['webpack'],
|
||||||
'client/src/**/*.html': ['html2js']
|
'./client/src/**/*.html': ['html2js']
|
||||||
},
|
},
|
||||||
webpack: webpackTestConfig,
|
webpack: webpackTestConfig,
|
||||||
webpackMiddleware: {
|
webpackMiddleware: {
|
||||||
|
|||||||
Reference in New Issue
Block a user