Skip to content

Commit

Permalink
Add script to extract messages for translation
Browse files Browse the repository at this point in the history
Use babel-plugin-react-intl and a custom script to extract
messages (`<FormattedMessage...`, `intl.formatMessage(...)`,
etc.) from source code and provide them in a single JSON file
for easier management / discovery.

The config for the script allows us to specify which locales
to generate the output JSON files for (one per locale).

Any stale strings will be removed, and new strings added with
'' placeholder for easier identifaction. Any existing strings
that have already been translated will remain untouched by the
script.

Strings in the output JSON files are also sorted alphabetically.
  • Loading branch information
AlanGreene authored and tekton-robot committed Sep 3, 2019
1 parent df5b0b2 commit c9cfa97
Show file tree
Hide file tree
Showing 16 changed files with 269 additions and 168 deletions.
3 changes: 1 addition & 2 deletions .storybook/Container.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ import React from 'react';

import './Container.scss';
import { IntlProvider } from "react-intl";
import { messages } from "../src/constants";

export default function Container({ story }) {
return (
<IntlProvider locale='en' defaultLocale='en' messages={messages.en}>
<IntlProvider locale='en' defaultLocale='en'>
<div
data-floating-menu-container
role="main"
Expand Down
6 changes: 6 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,12 @@ Note: If modifying any of the sub-packages (e.g. components or utils in https://

Run `npm run build` to build the project. The build artifacts will be stored in the `dist/` directory. This will perform a production build of the static resources. It correctly bundles React in production mode and optimizes the build for the best performance. Filenames include hashes to facilitate long-term caching.

### i18n

This project uses `react-intl` for internationalization, and provides a script to automatically extract messages to bundles for translation. Run `npm run i18n:extract` from the root of the project to update the message bundles which can be found in `src/nls/`.

Note: `src/nls/messages_en.json` should **NOT** be edited manually, instead edit the defaultMessage in the code and re-run the script.

### Running unit tests

Run `npm test` to execute the unit tests via [Jest](https://jestjs.io/) in interactive watch mode. This also generates a code coverage report by default.
Expand Down
7 changes: 6 additions & 1 deletion config_frontend/config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
{
"API_DOMAIN": "http://localhost:9097",
"PORT": "8000"
"PORT": "8000",
"locales": {
"default": "en",
"supported": ["en"],
"build": ["en"]
}
}
19 changes: 19 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"build_ko": "webpack --config webpack.prod.js --output-path='./cmd/dashboard/kodata/web' ",
"clean": "lerna clean --yes && lerna run clean && rimraf node_modules",
"eslint:check": "eslint --print-config . | eslint-config-prettier-check",
"i18n:extract": "node scripts/i18n/extractMessages.js",
"lerna:publish": "lerna publish --no-git-tag-version --no-push --preid alpha",
"lint": "eslint --ignore-path .gitignore .",
"lint:fix": "npm run lint -- --fix",
Expand Down Expand Up @@ -62,6 +63,7 @@
"babel-eslint": "^10.0.1",
"babel-jest": "^24.5.0",
"babel-loader": "^8.0.5",
"babel-plugin-react-intl": "^4.1.14",
"clean-webpack-plugin": "^2.0.1",
"css-loader": "^2.1.1",
"eslint": "^5.3.0",
Expand All @@ -75,11 +77,14 @@
"eslint-plugin-react": "^7.12.4",
"fetch-mock": "^7.3.1",
"file-loader": "^3.0.1",
"glob": "^7.1.4",
"html-webpack-plugin": "^3.2.0",
"husky": "^1.3.1",
"jest": "^24.5.0",
"lerna": "^3.16.4",
"lint-staged": "^8.1.5",
"lodash.difference": "^4.5.0",
"lodash.omit": "^4.5.0",
"mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.11.0",
"prettier": "1.16.4",
Expand Down
36 changes: 22 additions & 14 deletions packages/components/src/components/Log/Log.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,6 @@ const LogLine = ({ data, index, style }) => (
</div>
);

const trailers = {
Completed: {
id: 'dashboard.pipelineRun.stepCompleted',
defaultMessage: 'Step completed'
},
Error: {
id: 'dashboard.pipelineRun.stepFailed',
defaultMessage: 'Step failed'
}
};

export class LogContainer extends Component {
state = { loading: true };

Expand Down Expand Up @@ -79,6 +68,25 @@ export class LogContainer extends Component {
);
};

getTrailerMessage = trailer => {
const { intl } = this.props;

switch (trailer) {
case 'Completed':
return intl.formatMessage({
id: 'dashboard.pipelineRun.stepCompleted',
defaultMessage: 'Step completed'
});
case 'Error':
return intl.formatMessage({
id: 'dashboard.pipelineRun.stepFailed',
defaultMessage: 'Step failed'
});
default:
return null;
}
};

initPolling = () => {
const { stepStatus } = this.props;
if (!this.timer && stepStatus && !stepStatus.terminated) {
Expand Down Expand Up @@ -113,16 +121,16 @@ export class LogContainer extends Component {
};

logTrailer = () => {
const { stepStatus, intl } = this.props;
const { stepStatus } = this.props;
const { reason } = (stepStatus && stepStatus.terminated) || {};
const trailer = trailers[reason];
const trailer = this.getTrailerMessage(reason);
if (!trailer) {
return null;
}

return (
<div className="log-trailer" data-status={reason}>
{intl.formatMessage(trailer)}
{trailer}
</div>
);
};
Expand Down
14 changes: 7 additions & 7 deletions packages/components/src/components/PipelineRun/PipelineRun.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,13 +209,13 @@ export /* istanbul ignore next */ class PipelineRunContainer extends Component {
kind="error"
hideCloseButton
lowContrast
title={intl.formatMessage({
id: 'dashboard.pipelineRun.failedMessage',
message: pipelineRunError.reason,
defaultMessage: `Unable to load PipelineRun details: ${
pipelineRunError.reason
}`
})}
title={intl.formatMessage(
{
id: 'dashboard.pipelineRun.failedMessage',
defaultMessage: 'Unable to load PipelineRun details: {reason}'
},
{ reason: pipelineRunError.reason }
)}
subtitle={pipelineRunError.message}
/>
</>
Expand Down
47 changes: 21 additions & 26 deletions packages/components/src/components/Step/Step.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,24 +49,38 @@ class Step extends Component {
}

statusLabel() {
const { intl, labels, reason, status } = this.props;
const { running, succeeded, failed, waiting, notRun } = labels;
const { intl, reason, status } = this.props;

if (status === 'running') {
return intl.formatMessage(running);
return intl.formatMessage({
id: 'dashboard.taskRun.status.running',
defaultMessage: 'Running'
});
}

if (status === 'terminated') {
if (reason === 'Completed') {
return intl.formatMessage(succeeded);
return intl.formatMessage({
id: 'dashboard.taskRun.status.succeeded',
defaultMessage: 'Completed'
});
}
return intl.formatMessage(failed);
return intl.formatMessage({
id: 'dashboard.taskRun.status.failed',
defaultMessage: 'Failed'
});
}
if (status === 'waiting') {
return intl.formatMessage(waiting);
return intl.formatMessage({
id: 'dashboard.taskRun.status.waiting',
defaultMessage: 'Waiting'
});
}
// task is done, step did not run
return intl.formatMessage(notRun);
return intl.formatMessage({
id: 'dashboard.taskRun.status.notRun',
defaultMessage: 'Not run'
});
}

render() {
Expand Down Expand Up @@ -94,25 +108,6 @@ class Step extends Component {
}

Step.defaultProps = {
labels: {
failed: { id: 'dashboard.taskRun.status.failed', defaultMessage: 'Failed' },
notRun: {
id: 'dashboard.taskRun.status.notRun',
defaultMessage: 'Not run'
},
running: {
id: 'dashboard.taskRun.status.running',
defaultMessage: 'Running'
},
succeeded: {
id: 'dashboard.taskRun.status.succeeded',
defaultMessage: 'Completed'
},
waiting: {
id: 'dashboard.taskRun.status.waiting',
defaultMessage: 'Waiting'
}
},
stepName: 'unknown'
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,39 @@ class StepDetailsHeader extends Component {
}

statusLabel() {
const { intl, labels, reason, status, taskRun } = this.props;
const { running, succeeded, failed, waiting, notRun } = labels;
const { intl, reason, status, taskRun } = this.props;

if (status === 'running') {
return intl.formatMessage(running);
return intl.formatMessage({
id: 'dashboard.taskRun.status.running',
defaultMessage: 'Running'
});
}
if (status === 'terminated') {
if (reason === 'Completed') {
return intl.formatMessage(succeeded);
return intl.formatMessage({
id: 'dashboard.taskRun.status.succeeded',
defaultMessage: 'Completed'
});
}
return intl.formatMessage(failed);
return intl.formatMessage({
id: 'dashboard.taskRun.status.failed',
defaultMessage: 'Failed'
});
}
// no status, task still running means waiting
const { reason: taskReason, status: taskStatus } = getStatus(taskRun);
if (taskStatus === 'Unknown' && taskReason === 'Pending') {
return intl.formatMessage(waiting);
return intl.formatMessage({
id: 'dashboard.taskRun.status.waiting',
defaultMessage: 'Waiting'
});
}
// task is done, step did not run
return intl.formatMessage(notRun);
return intl.formatMessage({
id: 'dashboard.taskRun.status.notRun',
defaultMessage: 'Not run'
});
}

render() {
Expand All @@ -86,25 +100,6 @@ class StepDetailsHeader extends Component {
}

StepDetailsHeader.defaultProps = {
labels: {
failed: { id: 'dashboard.taskRun.status.failed', defaultMessage: 'Failed' },
notRun: {
id: 'dashboard.taskRun.status.notRun',
defaultMessage: 'Not run'
},
running: {
id: 'dashboard.taskRun.status.running',
defaultMessage: 'Running'
},
succeeded: {
id: 'dashboard.taskRun.status.succeeded',
defaultMessage: 'Completed'
},
waiting: {
id: 'dashboard.taskRun.status.waiting',
defaultMessage: 'Waiting'
}
},
taskRun: {}
};

Expand Down
Loading

0 comments on commit c9cfa97

Please sign in to comment.