diff --git a/docs/i18n.md b/docs/i18n.md index 99f20d54a63..6f1a88b6e2e 100644 --- a/docs/i18n.md +++ b/docs/i18n.md @@ -84,3 +84,127 @@ the JSON to the repo. # build the JSON. NODE_APP_INSTANCE=[MY_APP] bin/build-locales ``` + +## Setting up translations + +To set up a component to be translated there are two pieces of code to know +about. + +### Jed + +We use [Jed](https://slexaxton.github.io/Jed/) as the API for providing +`gettext` functions inside React components. An initialized `Jed` instance +has all the `gettext` related functionality exposed as methods. There is a +fancy chained API but we've stuck to a more traditional approach. + +Before we get into how to make use of these functions let's take a look at +how the Jed instance is exposed to our components. + +### The Translation Provider + +The translation provider is used to pass down a Jed instance via context to +components lower down in the component hierarchy. This part is already done +for you in addons-frontend. So you should only need to worry +about wrapping your components as detailed in the next section. + +## The translate component wrapper. + +The translate Higher Order Component is a helper that wraps any component +and takes the Jed `i18n` instance from context and makes it available in +the wrapped component's props. + +Here's an example of a basic component setup for translation: + + +```javascript +import React, { PropTypes } from 'react'; +import translate from 'core/i18n/translate'; + + +export class MyTranslatedComponent extends React.Component { + static propTypes = { + i18n: PropTypes.object.isRequired, + } + + render() { + const { i18n } = this.props; + return ( +
+

{i18n.gettext('Something translated')}

+
+ ); + } +} + +export default translate()(MyTranslatedComponent); +``` + +That's pretty much all there is to it. + +## Using the Jed API + +Once you have `i18n` available to your component you can then use +any of the Jed methods exposed on the `i18n` object. + +```javascript +gettext = function ( key ) +dgettext = function ( domain, key ) +dcgettext = function ( domain, key, category ) +ngettext = function ( singular_key, plural_key, value ) +dngettext = function ( domain, singular_ley, plural_key, value ) +dcngettext = function ( domain, singular_key, plural_key, value, category ) +pgettext = function ( context, key ) +dpgettext = function ( domain, context, key ) +npgettext = function ( context, singular_key, plural_key, value ) +dnpgettext = function ( domain, context, singular_key, plural_key, value ) +dcnpgettext = function ( domain, context, singular_key, plural_key, value, category ) +sprintf = function ( string, substitutions) +``` + +### Using `sprintf` + +As you can see a sprintf function is also available. You can use this to +provide substitutions in gettext wrapped strings. + +There are two flavours to this, numbered placeholders or named ones. + +Here's the numbered approach: + +```javascript +i18n.sprintf(i18n.gettext('I like your %1$s %2$s.'), 'red', 'shirt')); +``` + +and here's the named arg approach: + +```javascript +i18n.sprintf(i18n.gettext('I like your %(colour)s %(garment)s.'), { colour: 'red', garment: 'shirt' })); +``` + +Both of these approaches allow for translators to re-order the substitution +vars. + +### Guidance on HTML in translations + +Generally we're looking to avoid having HTML in the middle of translation +strings as much as possible. + +If you need HTML it's better to use substitutions to add the HTML than +leave HTML in the translation. Take the following string as an example: + +```javascript +i18n.gettext('Take a look at the documentation'); +``` + +Using `sprintf` we can provide use start and end substitutions. This way +there's no HTML in the extracted string. + +```javascript +i18n.sprintf(i18n.gettext( + 'Take a look at the %(start_link)sdocumentation%(end_link)s'), + { start_link: '', end_link: '' }); +``` + +You can also use DOMPurify to sanitize strings that may contain HTML +following substitutions so that anything not explicitly allowed is removed. +DOMpurify will also help protect against malformed HTML in case opening +and closing tag substitutions vars get swapped around inadvertently.