fusionjs / fusion-plugin-i18n-react

Migrated to https://github.com/fusionjs/fusionjs
MIT License
4 stars 15 forks source link
fusion fusionjs

fusion-plugin-i18n-react

Build status

Adds I18n (Internationalization) string support to a Fusion.js app.

This plugin looks for translations in the ./translations folder by default. Translations for each language are expected to be in a JSON file with a locale as a filename. For example, for U.S. English, translations should be in ./translations/en-US.json. Language tags are dictated by your browser, and likely follow the RFC 5646 specification.

For date I18n, consider using date-fns.


Table of contents


Installation

yarn add fusion-plugin-i18n-react

Usage

React component

If you are using React, we recommend using the supplied Translate component.

import React from 'react';
import {Translate, withTranslations} from 'fusion-plugin-i18n-react';

export default () => {
  return <Translate id="test" data={{name: 'world'}} />);
});

Higher order component

A higher order component is provided to allow passing translations to third-party or native components. If you are using the translate function directly, be aware that you can only pass in a string literal to this function. This plugin uses a babel transform and non-string literals (e.g. variables) will break.

import React from 'react';
import {Translate, withTranslations} from 'fusion-plugin-i18n-react';

export default withTranslations(['test'])(({translate}) => {
  return <input placeholder={translate('test', {name: 'world'})} />;
});

Examples of translation files

The default loader expects translation files to live in ./translations/{locale}.

./translations/en-US.json

{
  "HomeHeader": "Welcome!",
  "Greeting": "Hello, ${name}"
}

./translations/pt-BR.json

{
  "HomeHeader": "Bem-vindo!",
  "Greeting": "Olá, ${name}"
}

Usage:

<Translate id="HomeHeader" />
<Translate id="Greeting" data={{name: user.name}} />

Setup

// src/main.js
import React from 'react';
import App from 'fusion-react';
import I18n, {
  I18nToken,
  I18nLoaderToken,
  createI18nLoader,
} from 'fusion-plugin-i18n-react';
import {FetchToken} from 'fusion-tokens';
import fetch from 'unfetch';

export default () => {
  const app = new App(<div />);

  app.register(I18nToken, I18n);
  __NODE__
    ? app.register(I18nLoaderToken, createI18nLoader())
    : app.register(FetchToken, fetch);

  return app;
};

API

Registration API

I18n
import I18n from 'fusion-plugin-i18n-react';

The i18n plugin. Typically, it should be registered to I18nToken. Provides the i18n service

I18nToken
import {I18nToken} from 'fusion-plugin-i18n-react';

The canonical token for the I18n plugin. Typically, it should be registered with the I18n plugin.

Dependencies

I18nLoaderToken
import {I18nLoaderToken} from 'fusion-plugin-i18n-react';

A function that provides translations. Optional. Server-side only.

Types
type I18nLoader = {
  from: (ctx: Context) => {locale: string, translations: Object},
};
Default values

If no loader is provided, the default loader will read translations from ./translations/{locale}.json. See src/loader.js for more details.

HydrationStateToken
import {HydrationStateToken} from 'fusion-plugin-i18n-react';

Sets the hydrated state in the client, and can be useful for testing purposes. Optional. Browser only.

Types
type HydrationState = {
  chunks: Array,
  translations: Object,
};
Default values

If no hydration state is provided, this will be an empty object ({}) and have no effect.

FetchToken
import {FetchToken} from 'fusion-tokens';

A fetch implementation. Browser-only.

Types
type Fetch = (url: string, options: Object) => Promise<Response>;
Default values

If no fetch implementation is provided, window.fetch is used.

Service API

const translations: string = i18n.translate(
  key: string,
  interpolations: Object
);

React component

If you are using React, we recommend using the supplied Translate component.

import {Translate} from 'fusion-plugin-i18n-react';

<Translate id="key" data={interpolations} />;

Higher order component

A higher order component is provided to allow passing translations to third-party or native components. If you are using the translate function directly, be aware that you can only pass in a string literal to this function. This plugin uses a babel transform and non-string literals (e.g. variables) will break.

import {withTranslations} from 'fusion-plugin-i18n-react';

const TranslatedComponent = withTranslations(['key'])(Component);

Be aware that the withTranslations function expects an array of string literals. This plugin uses a babel transform and the argument to this function must be an inline value, i.e. you cannot pass a variable.

The original Component receives a prop called {translate} and the {localeCode}.

Types

type TranslateProp = {
  translate: (key: string, interpolations: Object) => string,
  localeCode: string
};
type WithTranslations = (
  translationKeys: Array<string>
) => (React.Component<Props>) => React.Component<Props & TranslateProp>;

Other examples

Custom translations loader example

// src/main.js
import React from 'react';
import App from 'fusion-react';
import I18n, {I18nToken, I18nLoaderToken} from 'fusion-plugin-i18n-react';
import {FetchToken} from 'fusion-tokens';
import fetch from 'unfetch';
import Hello from './hello';
import I18nLoader from './translations';

export default () => {
  const app = new App(<div></div>);

  app.register(I18nToken, I18n);
  __NODE__
    ? app.register(I18nLoaderToken, I18nLoader);
    : app.register(FetchToken, fetch);

  app.register(Hello);

  return app;
}

// src/hello.js
import {withServices} from 'fusion-react';
import {I18nToken} from 'fusion-plugin-i18n-react';

export default withServices({I18n: I18nToken})(({I18n}) => {
  return withMiddleware((ctx, next) => {
    if (__NODE__ && ctx.path === '/hello') {
      const i18n = I18n(ctx);
      ctx.body = {
        message: i18n.translate('test', {name: 'world'}), // hello world
      }
    }
    return next();
  });
});

// src/translation-loader.js
import {Locale} from 'locale';

const translationData = {
  'en-US': {
    test: "hello ${name}"
  }
}

export default (ctx) => {
  // locale could be determined in different ways,
  // e.g. from ctx.headers['accept-language'] or from a /en-US/ URL
  const locale = new Locale('en-US');
  const translations = translationData[locale];
  return {locale, translations};
}