mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 01:57:35 -03:30
Add plural and contextual translation support
This commit is contained in:
parent
78a656bdd9
commit
b990d84e3b
@ -5,27 +5,27 @@ function CredentialsStrings (BaseString) {
|
||||
let ns = this.credentials;
|
||||
|
||||
ns.state = {
|
||||
ADD_BREADCRUMB_LABEL: t('CREATE CREDENTIAL'),
|
||||
EDIT_BREADCRUMB_LABEL: t('EDIT CREDENTIAL')
|
||||
ADD_BREADCRUMB_LABEL: t.s('CREATE CREDENTIAL'),
|
||||
EDIT_BREADCRUMB_LABEL: t.s('EDIT CREDENTIAL')
|
||||
};
|
||||
|
||||
ns.tab = {
|
||||
DETAILS: t('Details'),
|
||||
PERMISSIONS: t('Permissions')
|
||||
DETAILS: t.s('Details'),
|
||||
PERMISSIONS: t.s('Permissions')
|
||||
};
|
||||
|
||||
ns.inputs = {
|
||||
GROUP_TITLE: t('Type Details'),
|
||||
ORGANIZATION_PLACEHOLDER: t('SELECT AN ORGANIZATION'),
|
||||
CREDENTIAL_TYPE_PLACEHOLDER: t('SELECT A CREDENTIAL TYPE')
|
||||
GROUP_TITLE: t.s('Type Details'),
|
||||
ORGANIZATION_PLACEHOLDER: t.s('SELECT AN ORGANIZATION'),
|
||||
CREDENTIAL_TYPE_PLACEHOLDER: t.s('SELECT A CREDENTIAL TYPE')
|
||||
};
|
||||
|
||||
ns.add = {
|
||||
PANEL_TITLE: t('NEW CREDENTIAL')
|
||||
PANEL_TITLE: t.s('NEW CREDENTIAL')
|
||||
};
|
||||
|
||||
ns.permissions = {
|
||||
TITLE: t('CREDENTIALS PERMISSIONS')
|
||||
TITLE: t.s('CREDENTIALS PERMISSIONS')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -4,48 +4,48 @@ function ComponentsStrings (BaseString) {
|
||||
let t = this.t;
|
||||
let ns = this.components;
|
||||
|
||||
ns.REPLACE = t('REPLACE');
|
||||
ns.REVERT = t('REVERT');
|
||||
ns.ENCRYPTED = t('ENCRYPTED');
|
||||
ns.OPTIONS = t('OPTIONS');
|
||||
ns.SHOW = t('SHOW');
|
||||
ns.HIDE = t('HIDE');
|
||||
ns.REPLACE = t.s('REPLACE');
|
||||
ns.REVERT = t.s('REVERT');
|
||||
ns.ENCRYPTED = t.s('ENCRYPTED');
|
||||
ns.OPTIONS = t.s('OPTIONS');
|
||||
ns.SHOW = t.s('SHOW');
|
||||
ns.HIDE = t.s('HIDE');
|
||||
|
||||
ns.message = {
|
||||
REQUIRED_INPUT_MISSING: t('Please enter a value.'),
|
||||
INVALID_INPUT: t('Invalid input for this type.')
|
||||
REQUIRED_INPUT_MISSING: t.s('Please enter a value.'),
|
||||
INVALID_INPUT: t.s('Invalid input for this type.')
|
||||
};
|
||||
|
||||
ns.form = {
|
||||
SUBMISSION_ERROR_TITLE: t('Unable to Submit'),
|
||||
SUBMISSION_ERROR_MESSAGE:t('Unexpected server error. View the console for more information'),
|
||||
SUBMISSION_ERROR_PREFACE: t('Unexpected Error')
|
||||
SUBMISSION_ERROR_TITLE: t.s('Unable to Submit'),
|
||||
SUBMISSION_ERROR_MESSAGE:t.s('Unexpected server error. View the console for more information'),
|
||||
SUBMISSION_ERROR_PREFACE: t.s('Unexpected Error')
|
||||
};
|
||||
|
||||
ns.group = {
|
||||
UNSUPPORTED_ERROR_PREFACE: t('Unsupported input type')
|
||||
UNSUPPORTED_ERROR_PREFACE: t.s('Unsupported input type')
|
||||
};
|
||||
|
||||
ns.label = {
|
||||
PROMPT_ON_LAUNCH: t('Prompt on launch')
|
||||
PROMPT_ON_LAUNCH: t.s('Prompt on launch')
|
||||
};
|
||||
|
||||
ns.select = {
|
||||
UNSUPPORTED_TYPE_ERROR: t('Unsupported display model type'),
|
||||
EMPTY_PLACEHOLDER: t('NO OPTIONS AVAILABLE')
|
||||
UNSUPPORTED_TYPE_ERROR: t.s('Unsupported display model type'),
|
||||
EMPTY_PLACEHOLDER: t.s('NO OPTIONS AVAILABLE')
|
||||
};
|
||||
|
||||
ns.textarea = {
|
||||
SSH_KEY_HINT: t('HINT: Drag and drop an SSH private key file on the field below.')
|
||||
SSH_KEY_HINT: t.s('HINT: Drag and drop an SSH private key file on the field below.')
|
||||
};
|
||||
|
||||
ns.lookup = {
|
||||
NOT_FOUND: t('That value was not found. Please enter or select a valid value.')
|
||||
NOT_FOUND: t.s('That value was not found. Please enter or select a valid value.')
|
||||
};
|
||||
|
||||
ns.truncate = {
|
||||
DEFAULT: t('Copy full revision to clipboard.'),
|
||||
COPIED: t('Copied to clipboard.')
|
||||
DEFAULT: t.s('Copy full revision to clipboard.'),
|
||||
COPIED: t.s('Copied to clipboard.')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -3,17 +3,49 @@ import defaults from '../../assets/default.strings.json';
|
||||
let i18n;
|
||||
|
||||
function BaseStringService (namespace) {
|
||||
let t = i18n._;
|
||||
|
||||
const ERROR_NO_NAMESPACE = t('BaseString cannot be extended without providing a namespace');
|
||||
const ERROR_NO_STRING = t('No string exists with this name');
|
||||
const ERROR_NO_NAMESPACE = 'BaseString cannot be extended without providing a namespace';
|
||||
const ERROR_NO_STRING = 'No string exists with this name';
|
||||
|
||||
if (!namespace) {
|
||||
throw new Error(ERROR_NO_NAMESPACE);
|
||||
}
|
||||
|
||||
this.t = t;
|
||||
this[namespace] = {};
|
||||
this.t = {};
|
||||
|
||||
/**
|
||||
* To translate a singular string by itself or a string with context data, use `translate`.
|
||||
* For brevity, this is renamed as `t.s` (as in "translate singular"). `t.s` serves a dual
|
||||
* purpose -- it's to mark strings for translation so they appear in the `.pot` file after
|
||||
* the grunt-angular-gettext task is run AND it's used to fetch the translated string at
|
||||
* runtime.
|
||||
*
|
||||
* NOTE: View ui/src/i18n.js for where these i18n methods are defined. i18n is a wrapper around
|
||||
* the library angular-gettext.
|
||||
*
|
||||
* @arg {string} string - The string to be translated
|
||||
* @arg {object=} context - A data object used to populate dynamic context data in a string.
|
||||
*
|
||||
* @returns {string} The translated string or the original string in the even the translation
|
||||
* does not exist.
|
||||
*/
|
||||
this.t.s = i18n.translate;
|
||||
|
||||
/**
|
||||
* To translate a plural string use `t.p`. The `count` supplied will determine whether the
|
||||
* singular or plural string is returned.
|
||||
*
|
||||
* @arg {number} count - The count of the plural object
|
||||
* @arg {string} singular - The singular version of the string to be translated
|
||||
* @arg {string} plural - The plural version of the string to be translated
|
||||
* @arg {object=} context - A data object used to populate dynamic context data in a string.
|
||||
*
|
||||
* @returns {string} The translated string or the original string in the even the translation
|
||||
* does not exist.
|
||||
*/
|
||||
this.t.p = i18n.translatePlural;
|
||||
|
||||
let t = this.t;
|
||||
|
||||
/*
|
||||
* These strings are globally relevant and configured to give priority to values in
|
||||
@ -26,9 +58,9 @@ function BaseStringService (namespace) {
|
||||
* Globally relevant strings should be defined here to avoid duplication of content across the
|
||||
* the project.
|
||||
*/
|
||||
this.CANCEL = t('CANCEL');
|
||||
this.SAVE = t('SAVE');
|
||||
this.OK = t('OK');
|
||||
this.CANCEL = t.s('CANCEL');
|
||||
this.SAVE = t.s('SAVE');
|
||||
this.OK = t.s('OK');
|
||||
|
||||
/**
|
||||
* This getter searches the extending class' namespace first for a match then falls back to
|
||||
@ -37,8 +69,16 @@ function BaseStringService (namespace) {
|
||||
*
|
||||
* If no match is found, an error is thrown to alert the developer immediately instead of
|
||||
* failing silently.
|
||||
*
|
||||
* The `t.s` and `t.p` calls should only be used where strings are defined in
|
||||
* <name>.strings.js` files. To use translated strings elsewhere, access them through this
|
||||
* common interface.
|
||||
*
|
||||
* @arg {string} name - The property name of the string (e.g. 'CANCEL')
|
||||
* @arg {number=} count - A count of objects referenced in your plural string
|
||||
* @arg {object=} context - An object containing data to use in the interpolation of the string
|
||||
*/
|
||||
this.get = name => {
|
||||
this.get = (name, ...args) => {
|
||||
let keys = name.split('.');
|
||||
let value;
|
||||
|
||||
@ -54,7 +94,7 @@ function BaseStringService (namespace) {
|
||||
}
|
||||
});
|
||||
|
||||
return value;
|
||||
return typeof value === 'string' ? value : value(...args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -40,6 +40,10 @@ export default
|
||||
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;
|
||||
|
||||
@ -5,30 +5,24 @@ function InventoryHostsStrings (BaseString) {
|
||||
let ns = this['inventory-hosts'];
|
||||
|
||||
ns.filter = {
|
||||
GROUP: t('group'),
|
||||
GROUPS: t('groups'),
|
||||
HOST: t('host'),
|
||||
HOSTS: t('hosts'),
|
||||
PROMOTE_GROUPS_HOSTS: t('Promote groups and hosts'),
|
||||
PROMOTE_GROUP_HOSTS: t('Promote group and hosts'),
|
||||
PROMOTE_GROUPS_HOST: t('Promote groups and host'),
|
||||
PROMOTE_GROUP_HOST: t('Promote group and host'),
|
||||
DELETE_GROUPS_HOSTS: t('Delete groups and hosts'),
|
||||
DELETE_GROUP_HOSTS: t('Delete group and hosts'),
|
||||
DELETE_GROUPS_HOST: t('Delete groups and host'),
|
||||
DELETE_GROUP_HOST: t('Delete group and host'),
|
||||
PROMOTE_GROUPS: t('Promote groups'),
|
||||
PROMOTE_GROUP: t('Promote group'),
|
||||
DELETE_GROUPS: t('Delete groups'),
|
||||
DELETE_GROUP: t('Delete group'),
|
||||
PROMOTE_HOSTS: t('Promote hosts'),
|
||||
PROMOTE_HOST: t('Promote host'),
|
||||
DELETE_HOSTS: t('Delete hosts'),
|
||||
DELETE_HOST: t('Delete host')
|
||||
GROUP: count => t.p(count, 'group', 'groups'),
|
||||
HOST: count => t.p(count, 'host', 'hosts'),
|
||||
PROMOTE_GROUPS_AND_HOSTS: data => t.s('Promote {{ group }} and {{ host }}', {
|
||||
group: this.get('GROUP', data.groups),
|
||||
host: this.get('HOST', data.hosts)
|
||||
}),
|
||||
DELETE_GROUPS_AND_HOSTS: data => t.s('Delete {{ group }} and {{ host }}', {
|
||||
group: this.get('GROUP', data.groups),
|
||||
host: this.get('HOST', data.hosts)
|
||||
}),
|
||||
PROMOTE_GROUP: count => t.p(count, 'Promote group', 'Promote groups'),
|
||||
DELETE_GROUP: count => t.p(count, 'Delete group', 'Delete groups'),
|
||||
PROMOTE_HOST: count => t.p(count, 'Promote host', 'Promote hosts'),
|
||||
DELETE_HOST: count => t.p(count, 'Delete host', 'Delete hosts'),
|
||||
};
|
||||
|
||||
ns.smartinventories = {
|
||||
TOOLTIP: t('Please click the icon to edit the host filter.')
|
||||
TOOLTIP: t.s('Please click the icon to edit the host filter.')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,10 @@ let source = [
|
||||
module.exports = {
|
||||
all: {
|
||||
options: {
|
||||
markerNames: ['_', 'N_', 't']
|
||||
markerNames: ['_', 'N_'],
|
||||
moduleName: 't',
|
||||
moduleMethodString: 's',
|
||||
moduleMethodPlural: 'p'
|
||||
},
|
||||
files: {
|
||||
'po/ansible-tower-ui.pot': source
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user