Skip to content

Commit

Permalink
Bug 1992730: Fix i18n for dynamic plugins
Browse files Browse the repository at this point in the history
* Add plugin namespaces when initializing i18next
* Add react-i18next to the shared modules
* Update the demo plugin to use translations
  • Loading branch information
spadgett committed Aug 24, 2021
1 parent 3da6656 commit 45128f9
Show file tree
Hide file tree
Showing 12 changed files with 1,357 additions and 118 deletions.
2 changes: 1 addition & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
**/node_modules
frontend/node_modules
19 changes: 19 additions & 0 deletions frontend/dynamic-demo-plugin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,3 +83,22 @@ Following commands should be executed in Console repository root.
```

Update and apply `oc-manifest.yaml` to use a custom plugin image.

## i18n

The demo plugin demonstrates how you can translate messages in a dynamic plugin
with [react-i18next](https://react.i18next.com/). The i18n namespace must match
the name of the `ConsolePlugin` resource with the `plugin__` prefix to avoid
naming conflicts. For example, the demo plugin uses the
`plugin__console-demo-plugin` namespace. You can use the `useTranslation` hook
with this namespace as follows:

```tsx
conster Header: React.FC = () => {
const { t } = useTranslation('plugin__console-demo-plugin');
return <h1>{t('Hello, World!')}</h1>;
};
```
Running `yarn i18n` updates the JSON files in the `locales` folder of the
dynamic plugin when adding or changing messages.
21 changes: 21 additions & 0 deletions frontend/dynamic-demo-plugin/console-extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,27 @@
}
}
},
{
"type": "console.navigation/section",
"properties": {
"id": "dev-demo-section",
"perspective": "dev",
"name": "Demo Plugin"
}
},
{
"type": "console.navigation/href",
"properties": {
"id": "test-consumer",
"perspective": "dev",
"section": "dev-demo-section",
"name": "Test Consumer",
"href": "/test-consumer"
},
"flags": {
"required": ["OPENSHIFT"]
}
},
{
"type": "console.page/route",
"properties": {
Expand Down
8 changes: 8 additions & 0 deletions frontend/dynamic-demo-plugin/i18next-parser.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
createOldCatalogs: false,
keySeparator: false,
locales: ['en'],
namespaceSeparator: '~',
reactNamespace: false,
useKeysAsDefaultValue: true,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"Extensions of type Console.flag/Model": "Extensions of type Console.flag/Model",
"Model Flag: {{flag}}": "Model Flag: {{flag}}",
"Model Group, Version, Kind:": "Model Group, Version, Kind:"
}
6 changes: 3 additions & 3 deletions frontend/dynamic-demo-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
"build": "yarn clean && NODE_ENV=production yarn ts-node ./node_modules/.bin/webpack --mode=production",
"build-dev": "yarn clean && yarn ts-node ./node_modules/.bin/webpack --mode=development",
"http-server": "./http-server.sh ./dist",
"i18n": "i18next \"src/**/*.{js,jsx,ts,tsx}\" [-oc] -c i18next-parser.config.js",
"ts-node": "ts-node -O '{\"module\":\"commonjs\"}' -I '/node_modules/(?!(@console)/)/'"
},
"dependencies": {
"react": "17.0.1"
},
"devDependencies": {
"@console/dynamic-plugin-sdk": "link:../packages/console-dynamic-plugin-sdk/dist",
"@types/react": "16.8.13",
"copy-webpack-plugin": "^6.4.1",
"http-server": "0.12.x",
"i18next-parser": "^3.3.0",
"ts-loader": "6.2.2",
"ts-node": "5.0.1",
"typescript": "3.8.3",
Expand Down
17 changes: 10 additions & 7 deletions frontend/dynamic-demo-plugin/src/components/ExtensionConsumer.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import * as React from 'react';
import * as _ from 'lodash';
import { useTranslation } from 'react-i18next';
import { isModelFeatureFlag, ModelFeatureFlag } from '@console/dynamic-plugin-sdk';
import { useResolvedExtensions } from '@console/dynamic-plugin-sdk/api';

const ExtensionConsumer: React.FC = () => {
const { t } = useTranslation('plugin__console-demo-plugin');
const [extensions] = useResolvedExtensions<ModelFeatureFlag>(isModelFeatureFlag);

return !_.isEmpty(extensions) ? (
<div>
<h2>Extensions of type Console.flag/Model</h2>
<h2>{t('Extensions of type Console.flag/Model')}</h2>
<div>
{extensions.map((ext) => (
<ModelRenderer
Expand All @@ -22,17 +24,18 @@ const ExtensionConsumer: React.FC = () => {
) : null;
};

const ModelRenderer: React.FC<ModelRendererProps> = ({ model, flag }) => (
<div>
<div>Model Flag: {flag} </div>
<div>Model Group, Version, Kind: </div>
const ModelRenderer: React.FC<ModelRendererProps> = ({ model, flag }) => {
const { t } = useTranslation('plugin__console-demo-plugin');
return <div>
<div>{t('Model Flag: {{flag}}', { flag })}</div>
<div>{t('Model Group, Version, Kind:')}</div>
<ul>
<li>{model.group}</li>
<li>{model.version}</li>
<li>{model.kind}</li>
</ul>
</div>
);
</div>;
};

type ModelRendererProps = {
model: {
Expand Down
11 changes: 10 additions & 1 deletion frontend/dynamic-demo-plugin/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import * as webpack from 'webpack';
import * as path from 'path';
import { ConsoleRemotePlugin } from '@console/dynamic-plugin-sdk/webpack';

const CopyWebpackPlugin = require('copy-webpack-plugin');

const config: webpack.Configuration = {
mode: 'development',
context: path.resolve(__dirname, 'src'),
Expand Down Expand Up @@ -31,7 +33,14 @@ const config: webpack.Configuration = {
},
],
},
plugins: [new ConsoleRemotePlugin()],
plugins: [
new ConsoleRemotePlugin(),
new CopyWebpackPlugin({
patterns: [
{ from: path.resolve(__dirname, 'locales'), to: 'locales' },
],
}),
],
externals: {
'@console/dynamic-plugin-sdk/api': 'api',
},
Expand Down
Loading

0 comments on commit 45128f9

Please sign in to comment.