diff --git a/I18n.md b/I18n.md
index e5757429c3f..62dcb9aa2f5 100644
--- a/I18n.md
+++ b/I18n.md
@@ -46,6 +46,25 @@ e.g:
LIST_DISPLAY
HEADERBAR_GO_PORTAL
+### Specific translation cases
+
+In some cases, you want to add some html markup or style to your translations. For this case, you can use Trans component
+https://react.i18next.com/components/trans-component.html
+
+```jsx
+import { Trans } from 'react-i18next';
+
+
+ Are you sure you want to remove the {{ resourceLabel: resourceInfo.resourceTypeLabel }}
+ {{ resourceName: resourceInfo.label }} ?
+
+```
+
+For this case, the translation json value is :
+`Are you sure you want to remove the <1>{{ resourceLabel }}1> <2><1>{{ resourceName }}1>2>?`
+
+More infos in the react-i18next's documentation
+
## Use i18n with UI in your App
### Create an instance of i18n
diff --git a/package.json b/package.json
index 39fe07cf5dc..33c37b3dd36 100644
--- a/package.json
+++ b/package.json
@@ -25,57 +25,42 @@
"build-storybook": "npm run test:demo && export ACTION='test:demo' && export TRAVIS_BRANCH='master' && export TRAVIS_BUILD_DIR=`pwd` && .travis/after_success_static.sh && .travis/after_success_demo.sh && .travis/after_success_coverage.sh",
"publish-storybook": "npm run build-storybook && cd .static && surge",
"changelog": "git log --pretty=\"format:%C(bold green)%ad%C(reset) %<(70,trunc)%s\" --date=short --color",
- "extract-i18n": "npm run extract-i18n-components && npm run extract-i18n-forms",
+ "extract-i18n": "npm run extract-i18n-components && npm run extract-i18n-forms && npm run extract-i18n-containers",
"extract-i18n-components": "i18next packages/components/src -r --default-values -o i18n/components -n tui-components -l en --write-old false --fileFilter '*.js' --directoryFilter '!__snapshots__'",
- "extract-i18n-forms": "i18next packages/forms/src -r --default-values -o i18n/forms -n tui-forms -l en --write-old false --fileFilter '*.js' --directoryFilter '!__snapshots__'"
+ "extract-i18n-forms": "i18next packages/forms/src -r --default-values -o i18n/forms -n tui-forms -l en --write-old false --fileFilter '*.js' --directoryFilter '!__snapshots__'",
+ "extract-i18n-containers": "i18next packages/containers/src -r --default-values -o i18n/containers -n tui-containers -l en --write-old false --fileFilter '*.js' --directoryFilter '!__snapshots__'"
},
"watch": {
"build-cmf": {
- "patterns": [
- "packages/cmf/src/**/*"
- ],
+ "patterns": ["packages/cmf/src/**/*"],
"extensions": "js"
},
"build-components": {
- "patterns": [
- "packages/components/src/**/*"
- ],
+ "patterns": ["packages/components/src/**/*"],
"extensions": "js,css,scss,svg"
},
"build-sagas": {
- "patterns": [
- "packages/sagas/src/**/*"
- ],
+ "patterns": ["packages/sagas/src/**/*"],
"extensions": "js"
},
"build-containers": {
- "patterns": [
- "packages/containers/src/**/*"
- ],
+ "patterns": ["packages/containers/src/**/*"],
"extensions": "js,css,scss,svg"
},
"build-forms": {
- "patterns": [
- "packages/forms/src/**/*"
- ],
+ "patterns": ["packages/forms/src/**/*"],
"extensions": "js,scss"
},
"build-icons": {
- "patterns": [
- "packages/icons/src/svg/*"
- ],
+ "patterns": ["packages/icons/src/svg/*"],
"extensions": "svg"
},
"build-logging": {
- "patterns": [
- "packages/logging/src/**/*"
- ],
+ "patterns": ["packages/logging/src/**/*"],
"extensions": "js"
},
"build-theme": {
- "patterns": [
- "packages/theme/src/**/*"
- ],
+ "patterns": ["packages/theme/src/**/*"],
"extensions": "css,scss"
}
},
@@ -83,7 +68,7 @@
"type": "git",
"url": "https://github.com/Talend/ui.git"
},
- "engines" : { "node" : ">=8.10.0 <9.0.0" },
+ "engines": { "node": ">=8.10.0 <9.0.0" },
"version": "0.0.0",
"private": true,
"workspaces": [
diff --git a/packages/containers/examples/ExampleDeleteResource.js b/packages/containers/examples/ExampleDeleteResource.js
index 5bb6d23f76d..759b262971b 100644
--- a/packages/containers/examples/ExampleDeleteResource.js
+++ b/packages/containers/examples/ExampleDeleteResource.js
@@ -1,4 +1,6 @@
import React from 'react';
+import { I18nextProvider } from 'react-i18next';
+import i18n, { LanguageSwitcher } from './config/i18n';
import { DeleteResource } from '../src';
/*
@@ -32,10 +34,12 @@ Also require two fields, uri it contains the uri to call and resourceType, the t
const views = {
uri: '/myEndpoint',
resourceType: 'myResourceType',
+ resourceTypeLabel: 'resource',
header: 'My header title',
'cancel-action': 'dialog:delete:cancel',
'validate-action': 'dialog:delete:validate',
routeParams: { id: 'myID' },
+ female: true,
};
const params = {
@@ -47,6 +51,18 @@ const props = {
params,
};
-export default function ExampleAction() {
- return ;
-}
+export default {
+ default: () => (
+
+ ;
+
+ ),
+ translated: () => (
+
+
+
+
+
+
+ ),
+};
diff --git a/packages/containers/examples/config/i18n.js b/packages/containers/examples/config/i18n.js
index 940b5974308..2b02b99c2a7 100644
--- a/packages/containers/examples/config/i18n.js
+++ b/packages/containers/examples/config/i18n.js
@@ -1,8 +1,19 @@
+import React from 'react';
import i18n from 'i18next';
import { I18N_DOMAIN_COMPONENTS } from '@talend/react-components';
+import I18N_DOMAIN_CONTAINERS from '../../src/constant';
i18n.init({
+ lng: 'en',
resources: {
+ en: {
+ [I18N_DOMAIN_CONTAINERS]: {
+ DELETE_RESOURCE_MESSAGE:
+ 'Are you sure you want to remove the <1>{{ resourceLabel }}1> <2><1>{{ resourceName }}1>2>?',
+ DELETE_RESOURCE_MESSAGE_female:
+ 'Are you sure you want to remove the <1>{{ resourceLabel }}1> <2><1>{{ resourceName }}1>2>?',
+ },
+ },
fr: {
[I18N_DOMAIN_COMPONENTS]: {
LIST_TOOLBAR_DISPLAY: 'Affichage :',
@@ -17,6 +28,12 @@ i18n.init({
LIST_FILTER_REMOVE: 'Supprimer le filtre',
VIRTUALIZEDLIST_NO_RESULT: 'Pas de résultat',
},
+ [I18N_DOMAIN_CONTAINERS]: {
+ DELETE_RESOURCE_MESSAGE:
+ 'Êtes-vous sûr(e) de vouloir supprimer le <1>{{ resourceLabel }}1> <2><1>{{ resourceName }}1>2> ?',
+ DELETE_RESOURCE_MESSAGE_female:
+ 'Êtes-vous sûr(e) de vouloir supprimer la <1>{{ resourceLabel }}1> <2><1>{{ resourceName }}1>2> ?',
+ },
},
it: {
[I18N_DOMAIN_COMPONENTS]: {
@@ -32,10 +49,41 @@ i18n.init({
LIST_FILTER_REMOVE: 'Rimuova il filtro',
VIRTUALIZEDLIST_NO_RESULT: 'Nessun risultato',
},
+ [I18N_DOMAIN_CONTAINERS]: {
+ DELETE_RESOURCE_MESSAGE: 'Sei sicuro di voler eliminare {{resourceLabel}} ',
+ },
},
},
- debug: false,
+ saveMissing: true,
+ debug: true,
wait: true, // globally set to wait for loaded translations in translate hoc
});
+export const LanguageSwitcher = () => {
+ const style = {
+ position: 'fixed',
+ bottom: 0,
+ width: '100vw',
+ textAlign: 'center',
+ zIndex: 100000,
+ };
+
+ function renderBtn(locale, isDefault) {
+ return (
+
+ );
+ }
+
+ return (
+
+ );
+};
+
export default i18n;
diff --git a/packages/containers/package.json b/packages/containers/package.json
index 9ef1ec65019..8a965cc2262 100644
--- a/packages/containers/package.json
+++ b/packages/containers/package.json
@@ -112,12 +112,14 @@
"bson-objectid": "1.1.5",
"classnames": "2.2.5",
"immutable": "3.8.1",
+ "i18next": "^9.0.0",
"invariant": "2.2.2",
"keycode": "2.2.0",
"lodash": "4.17.4",
"prop-types": "15.5.10",
"react": "^15.6.2",
"react-bootstrap": "0.31.5",
+ "react-i18next": "^5.2.0",
"react-redux": "5.0.5",
"reselect": "^2.5.4"
},
diff --git a/packages/containers/src/DeleteResource/DeleteResource.container.js b/packages/containers/src/DeleteResource/DeleteResource.container.js
index 4916b612441..da8e2e0ba5b 100644
--- a/packages/containers/src/DeleteResource/DeleteResource.container.js
+++ b/packages/containers/src/DeleteResource/DeleteResource.container.js
@@ -2,15 +2,18 @@ import React from 'react';
import PropTypes from 'prop-types';
import { componentState } from '@talend/react-cmf';
import { ConfirmDialog } from '@talend/react-components';
+import { translate, Trans } from 'react-i18next';
import { getActionsProps } from '../actionAPI';
import deleteResourceConst from './deleteResource.constants';
+import DEFAULT_I18N from '../translate';
+import I18N_DOMAIN_CONTAINERS from '../constant';
/**
* DeleteResource is used to delete a specific resource.
* When the component is mounted, it opens a confirm dialog.
* It uses the saga matching pattern to launch a race between the cancel and validate action.
*/
-export default class DeleteResource extends React.Component {
+export class DeleteResource extends React.Component {
static displayName = 'Container(DeleteResource)';
static propTypes = {
...componentState.propTypes,
@@ -19,11 +22,16 @@ export default class DeleteResource extends React.Component {
header: PropTypes.string,
uri: PropTypes.string.isRequired,
resourceType: PropTypes.string.isRequired,
+ resourceTypeLabel: PropTypes.string,
+ female: PropTypes.string,
};
static contextTypes = {
registry: PropTypes.object.isRequired,
store: PropTypes.object.isRequired,
};
+ static defaultProps = {
+ t: DEFAULT_I18N.t.bind(DEFAULT_I18N),
+ };
constructor(props, context) {
super(props, context);
@@ -49,6 +57,9 @@ export default class DeleteResource extends React.Component {
getResourceInfo() {
return {
resourceType: this.props.resourceType,
+ resourceTypeLabel: this.props.resourceTypeLabel
+ ? this.props.resourceTypeLabel
+ : this.props.resourceType,
uri: this.props.uri,
...this.getLabel(),
id: this.props.params.id,
@@ -70,6 +81,9 @@ export default class DeleteResource extends React.Component {
const resourceInfo = this.getResourceInfo();
const validateAction = this.getActions(deleteResourceConst.VALIDATE_ACTION, resourceInfo);
const cancelAction = this.getActions(deleteResourceConst.CANCEL_ACTION, resourceInfo);
+ const i18nKey = this.props.female
+ ? 'DELETE_RESOURCE_MESSAGE_female'
+ : 'DELETE_RESOURCE_MESSAGE';
return (
-
{resourceInfo.label}
+
+
+ Are you sure you want to remove the {{ resourceLabel: resourceInfo.resourceTypeLabel }}
+ {{ resourceName: resourceInfo.label }} ?
+
+
);
}
}
+
+export default translate(I18N_DOMAIN_CONTAINERS, { i18n: DEFAULT_I18N })(DeleteResource);
diff --git a/packages/containers/src/DeleteResource/DeleteResource.test.js b/packages/containers/src/DeleteResource/DeleteResource.test.js
index 1b392f4c8c0..b04437a0d66 100644
--- a/packages/containers/src/DeleteResource/DeleteResource.test.js
+++ b/packages/containers/src/DeleteResource/DeleteResource.test.js
@@ -3,7 +3,7 @@ import { shallow } from 'enzyme';
import { store } from '@talend/react-cmf/lib/mock';
import Immutable from 'immutable';
-import Container from './DeleteResource.container';
+import { DeleteResource } from './DeleteResource.container';
import Connected from './DeleteResource.connect';
const state = store.state();
@@ -40,10 +40,12 @@ describe('Container DeleteResource', () => {
resource: new Immutable.Map({ label: 'myLabel' }),
header: 'My header title',
params: { id: 'myResourceID' },
+ resourceTypeLabel: 'resourceLabel',
+ female: true,
'validate-action': 'dialog:delete:validate',
'cancel-action': 'dialog:delete:cancel',
};
- const wrapper = shallow(, { context });
+ const wrapper = shallow(, { context });
expect(wrapper.getElement()).toMatchSnapshot();
});
it('should render with wrong resourceInfo params', () => {
@@ -55,14 +57,14 @@ describe('Container DeleteResource', () => {
'validate-action': 'dialog:delete:validate',
'cancel-action': 'dialog:delete:cancel',
};
- const wrapper = shallow(, { context });
+ const wrapper = shallow(, { context });
expect(wrapper.getElement()).toMatchSnapshot();
});
});
describe('Connected DeleteResource', () => {
it('should connect TestGenerator', () => {
- expect(Connected.displayName).toBe(`Connect(CMF(${Container.displayName}))`);
- expect(Connected.WrappedComponent).toBe(Container);
+ expect(Connected.displayName).toBe('Connect(CMF(Translate(Container(DeleteResource))))');
+ expect(Connected.WrappedComponent).toBe(DeleteResource);
});
});
diff --git a/packages/containers/src/DeleteResource/README.md b/packages/containers/src/DeleteResource/README.md
index e34446b8cc5..c4a2704591f 100644
--- a/packages/containers/src/DeleteResource/README.md
+++ b/packages/containers/src/DeleteResource/README.md
@@ -69,9 +69,11 @@ Required :
* **redirectUrl** : is the url to redirect when delete is complete or cancel action is triggered
Optional :
+* **resourceLabel** : is the parameter to show the type to remove if the resourceType is not readable by the user
* **routerParamAttribute** : is the attribute defined in the route to give the resource id
* **resourcePath** : array of string, is appended to resourceType key to deep location of a subset of a collection element
the delete service will use it to check if the resource exist in your application state tree
+* **female** : Only for i18n, allow to set the i18nkey to tell of the resource type if female or not
example with resourceType only
```javascript
diff --git a/packages/containers/src/DeleteResource/__snapshots__/DeleteResource.test.js.snap b/packages/containers/src/DeleteResource/__snapshots__/DeleteResource.test.js.snap
index 4459f127121..9e2d916d980 100644
--- a/packages/containers/src/DeleteResource/__snapshots__/DeleteResource.test.js.snap
+++ b/packages/containers/src/DeleteResource/__snapshots__/DeleteResource.test.js.snap
@@ -13,6 +13,7 @@ exports[`Container DeleteResource should render with proper resourceInfo params
"id": "myResourceID",
"label": "myLabel",
"resourceType": "myResourceType",
+ "resourceTypeLabel": "resourceLabel",
"uri": "/myEndpoint",
},
},
@@ -33,6 +34,7 @@ exports[`Container DeleteResource should render with proper resourceInfo params
"id": "myResourceID",
"label": "myLabel",
"resourceType": "myResourceType",
+ "resourceTypeLabel": "resourceLabel",
"uri": "/myEndpoint",
},
},
@@ -41,7 +43,23 @@ exports[`Container DeleteResource should render with proper resourceInfo params
}
>
- myLabel
+
+ Are you sure you want to remove the
+ Object {
+ "resourceLabel": "resourceLabel",
+ }
+
+
+ Object {
+ "resourceName": "myLabel",
+ }
+
+
+ ?
+