From ba597afa956dcc5785db4a70bc803581ff2d7bfb Mon Sep 17 00:00:00 2001 From: Pavel Lang Date: Thu, 28 Apr 2016 17:57:12 +0200 Subject: [PATCH] Updated docs Closes #623 Closes #612 Closes #610 Closes #595 Closes #173 Many thanks to @tobiasmuehl and @tomByrer and @bravo_kernel for reviewing. --- CONTRIBUTING.md | 1 + README.md | 19 +++++ docs/README.md | 2 + docs/recipes/feature-react-intl.md | 122 +++++++++++++++++++++++++++++ docs/recipes/feature-redux.md | 56 +++++++++++++ 5 files changed, 200 insertions(+) create mode 100644 docs/recipes/feature-react-intl.md create mode 100644 docs/recipes/feature-redux.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 701723713..875486870 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -49,6 +49,7 @@ forked repo, check that it meets these guidelines: * [Squash](http://stackoverflow.com/questions/5189560/squash-my-last-x-commits-together-using-git) your commits into one for each PR. * Run `npm test` to make sure that your code style is OK and there are no any regression bugs. +* When contributing to an opt-in feature, apply the `[feature/...]` tag as a prefix to your PR title #### Style Guide diff --git a/README.md b/README.md index 9f0be03ec..bdd8441dd 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,25 @@ expenses via [OpenCollective](https://opencollective.com/react-starter-kit) or +### Feature branches + +Some features aren't provided by default, but you can optionally add them. +To do so, simply merge the corresponding feature branch. +These branches should be in sync with master and all other features branches +so there should not be any merging conflicts. +If conflicts occur, please [report to us](https://github.com/kriasoft/react-starter-kit/issues). + + * [feature/redux](https://github.com/kriasoft/react-starter-kit/tree/feature/redux) – isomorphic redux support. + Use [`connect()`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) + higher order component to access state in redux store and to get actions mapped on dispatch. + You can see [LanguageSwitcher](https://github.com/kriasoft/react-starter-kit/blob/86eadfd3d11d804cf858aa21f657022fcc098752/src/components/LanguageSwitcher/LanguageSwitcher.js) component how to use `connect()` +
+ [Read full recipe](./docs/recipes/feature-redux.md) + + * [feature/react-intl](https://github.com/kriasoft/react-starter-kit/tree/feature/react-intl) – [`react-intl`](https://github.com/yahoo/react-intl#react-intl) integration based on `feature/redux` +
+ [Read full recipe](./docs/recipes/feature-react-intl.md) + ### Learn More * [Getting Started with React.js](http://facebook.github.io/react/) diff --git a/docs/README.md b/docs/README.md index a3c529cf7..c6ede3cc6 100644 --- a/docs/README.md +++ b/docs/README.md @@ -15,4 +15,6 @@ ### Recipes * [How to Implement Routing and Navigation](./recipes/how-to-implement-routing.md) +* [How to Integrate Redux](./recipes/feature-redux.md) +* [How to Integrate React-Intl](./recipes/feature-react-intl.md) * [How to Integrate Disqus](./recipes/how-to-integrate-disqus.md) diff --git a/docs/recipes/feature-react-intl.md b/docs/recipes/feature-react-intl.md new file mode 100644 index 000000000..023bc3ea0 --- /dev/null +++ b/docs/recipes/feature-react-intl.md @@ -0,0 +1,122 @@ +## Integrating [React-Intl](https://github.com/yahoo/react-intl#react-intl) + + 1. Merge `feature/react-intl` branch with git. + Because react-intl integration is built on top of `feature/redux`, you'll also get all the features. + + 2. Adjust `INTL_REQUIRE_DESCRIPTIONS` constant in `tools/webpack.config.js` around line 17: + ```js + const INTL_REQUIRE_DESCRIPTIONS = true; + ``` + When this boolean is set to true, the build will only succeed if a `description` is set for every message descriptor. + + 3. Adjust `locales` settings in `src/config.js`: + ```js + // default locale is the first one + export const locales = ['en-GB', 'cs-CZ']; + ``` + Note that you should follow + [BCP 47](https://tools.ietf.org/html/bcp47) + ([RFC 5646](https://tools.ietf.org/html/rfc5646)). + + 4. Add locale support in `src/client.js`: + ```js + import en from 'react-intl/locale-data/en'; + import cs from 'react-intl/locale-data/cs'; + ... + + [en, cs].forEach(addLocaleData); + ``` + + 5. Execute `npm run extractMessages` or `npm start` to strip out messages. + Message files are created in `src/messages` directory. + + 6. Edit `src/messages/*.json` files, change only `message` property. + + 7. Execute `npm run build`, + your translations should be copied to `build/messages/` directory. + + +## How to write localizable components + +Just import the appropriate [component](https://github.com/yahoo/react-intl/wiki#the-react-intl-module) from `react-intl` + +- For localizable text use +[``](https://github.com/yahoo/react-intl/wiki/Components#formattedmessage). +- You can also use it with +the [`defineMessages()`](https://github.com/yahoo/react-intl/wiki/API#definemessages) helper. + +- For date and time: +[``](https://github.com/yahoo/react-intl/wiki/Components#formatteddate) +[``](https://github.com/yahoo/react-intl/wiki/Components#formattedtime) +[``](https://github.com/yahoo/react-intl/wiki/Components#formattedrelative) + +- For numbers and currencies: +[``](https://github.com/yahoo/react-intl/wiki/Components#formattednumber) +[``](https://github.com/yahoo/react-intl/wiki/Components#formattedplural) + +- If possible, do not use ``, see how to use *Rich Text Formatting* with +[``](https://github.com/yahoo/react-intl/wiki/Components#formattedmessage) + +- When you need an imperative formatting API, use the [`injectIntl`](https://github.com/yahoo/react-intl/wiki/API#injectintl) High-Order Component. + +### Example + +```jsx +import { defineMessages, FormattedMessage, injectIntl, intlShape } from 'react-intl'; + +const messages = defineMessages({ + text: { + id: 'example.text', + defaultMessage: 'Example text', + description: 'Hi Pavel', + }, + textTemplate: { + id: 'example.text.template', + defaultMessage: 'Example text template', + description: 'Hi {name}', + }, +}); + +function Example(props) { + const text = props.intl.formatMessage(messages.textTemplate, { name: 'Pavel'}); + return ( +
+ + + Pavel + }} + /> +
+ ); +} + +Example.propTypes = { + intl: intlShape, +} + +export default injectIntl(Example); +``` + +## Updating translations + +When running the development server, every source file is watched and parsed for changed messages. + +Messages files are updated on the fly. +If a new definition is found, this definition is added to the end of every used `src/messages/xx-XX.json` file so when commiting, new translations will be at the tail of file. + +When an untranslated message is removed and its `message` field is empty as well, the message will be deleted from all translation files. This is why the `files` array is present. + +When editiong a translation file, it should be copied to `build/messages/` directory. + +## Other References + + * [`Intl documentation on MDN`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Intl) + * [express-request-language](https://github.com/tinganho/express-request-language#readme) + – for more details how initial language negotiation works. diff --git a/docs/recipes/feature-redux.md b/docs/recipes/feature-redux.md new file mode 100644 index 000000000..dd3bfb9e6 --- /dev/null +++ b/docs/recipes/feature-redux.md @@ -0,0 +1,56 @@ +## Integrating [Redux](http://redux.js.org/index.html) + +Merge `feature/redux` branch with git. +If you are interested in `feature/react-intl`, +merge that branch instead as it also includes Redux. + +**If you don't know redux well, you should [read about it first](http://redux.js.org/docs/basics/index.html).** + + +## Creating Actions + + 1. Go to `src/constants/index.js` and define action name there. + + 2. Go to `src/actions/` and create file with appropriate name. + You can copy `src/actions/runtime.js` as a template. + + 3. If you need async actions, use [`redux-thunk`](https://github.com/gaearon/redux-thunk#readme). + For inspiration on how to create async actions you can look at + [`setLocale`](https://github.com/kriasoft/react-starter-kit/blob/feature/react-intl/src/actions/intl.js) + action from `feature/react-intl`. + See [Async Flow](http://redux.js.org/docs/advanced/AsyncFlow.html) for more information on this topic. + + +## Creating Reducer (aka Store) + + 1. Go to [`src/reducers/`](https://github.com/kriasoft/react-starter-kit/tree/feature/redux/src/reducers) and create new file there. + + You can copy [`src/reducers/runtime.js`](https://github.com/kriasoft/react-starter-kit/tree/feature/redux/src/reducers/runtime.js) as a template. + + - Do not forget to always return `state`. + - Never mutate provided `state`. + If you mutate state, rendering of connected component will not be triggered because of `===` equality. + Always return new value if you perform state update. + You can use this construct: `{ ...state, updatedKey: action.payload.value, }` + - Keep in mind that store state *must* be repeatable by replaying actions on it. + For example, when you store timestamp, pass it into *action payload*. + If you call REST API, do it in action. *Never do this in reducer!* + + 2. Edit [`src/reducers/index.js`](https://github.com/kriasoft/react-starter-kit/tree/feature/redux/src/reducers/index.js), import your reducer and add it to root reducer created by + [`combineReducers`](http://redux.js.org/docs/api/combineReducers.html) + + +## Connecting Components + +You can use [`connect()`](https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options) High-Order Component from [`react-redux`](https://github.com/reactjs/react-redux#readme) package. + +See [Usage With React](http://redux.js.org/docs/basics/UsageWithReact.html) on redux.js.org. + +For an example you can look at +[``](https://github.com/kriasoft/react-starter-kit/blob/feature/react-intl/src/components/LanguageSwitcher/LanguageSwitcher.js) +component from `feature/react-intl` branch. It demonstrates both subscribing to store and dispatching actions. + + +## Dispatching Actions On Server + +See source of `src/server.js`