Skip to content

Use Gettext localizations in your React app with an ease!

License

Notifications You must be signed in to change notification settings

trucknet-io/react-targem

Repository files navigation

react-targem

Use Gettext localizations in your React app with an ease!

Build Status Coverage Status

<T
  message="Hey, {{ name }}, you have one thingy!"
  messagePlural="Hey, {{ name }}, you have {{ count }} thingies!"
  count={items.length}
  scope={{ name: "אלכס" }}
/>
// items.length === 1 => !היי אלכס, יש לך דבר אחד
// items.length === 7 => !היי אלכס, יש לך 7 גיזמוסים

Table of contents

Features

  • Context and plural
  • String interpolation using a {{ variable }} style syntax
  • Locale switching on the fly
  • Optional number formatting using Intl.NumberFormat
  • TypeScript support
  • SSR friendly

Installation

npm install --save react-targem
# ...or the shorter...
npm i -S react-targem

Usage

Below is an example app showing how to translate some text.
See TypeScript example here or better take a look at the tests: T.spec.tsx, TargemProvider.spec.tsx, TargemStatefulProvider.spec.tsx.

import React from 'react'
import ReactDOM from 'react-dom'
import { TargemProvider, T } from 'react-targem'

// translations.json below is a JSON file with all translations concatenated into one.
// It's just a map of `{ [locale: string]: ParsedPoFile }` where
// ParsedPoFile is an output of `po()` function call from "gettext-parser" package.
// See https://github.com/smhg/gettext-parser

// Also, you should definitely look at
// >>> https://github.com/goooseman/gettext-utils <<<
// as it can extract text from app to .po files and
// generate translations.json from .po files

import translationsJson from './src/i18n/translations.json'

function App({ name, numPotatoes }) {
  return (
    <TargemProvider
      locale="he"
      translations={translationsJson}
    >
      <div className="App">
        <h1><T>Potato inventory</T></h1>
        {/* => <h1>מלאי תפוחי אדמה</h1> */}

        <T
          message="Dear {{ name }}, there is one potato left"
          messagePlural="Dear {{ name }}, there are {{ count }} potatoes left"
          count={numPotatoes}
          scope={{ name }}
          component="span"
          formatNumbers
        />
        {/* => <span>אלכס היקר, נותרו 2 תפוחי אדמה</span> */}

        <T
          message="By more potatoes here!"
          component="a"
          componentProps={{ href="http://potatoes.com/buy" }}
        />
        {/* => <a href="http://potatoes.com/buy">לפי עוד תפוחי אדמה כאן!</a> */}

        <T
          count={1234.5678}
          formatNumbers={{ maximumFractionDigits: 2 }}
        />
        {/* => <span>1 234,57</span> */}
      </div>
    </TargemProvider>
  )
}

ReactDOM.render(
  <App name="אלכס" numPotatoes={Math.round(Math.random() * 3))} />,
  document.querySelector('.app-root')
)

Important note: each locale-representing object in translations that you pass to <TargemProvider/> must contain valid headers.plural-forms field (see Plural Forms), otherwise plural translation will be done according to English plural function. For example:

// translations.json
{
  "he": {
    "headers": {
      "plural-forms": "nplurals=4; plural=(n==1 ? 0 : n==2 ? 1 : n>10 && n%10==0 ? 2 : 3);"
    },
    "translations": { /*...*/ }
  }
}

<TargemProvider/>

import { TargemProvider } from "react-targem";

Creates localization context for all child <T /> components. This context can also be obtained using withLocale(Component).

Props:

  • translations (required: Object) – Translations as a map of { [locale: string]: ParsedPot } where ParsedPot is an output of po() function call from gettext-parser. See also gettext-utils.
  • locale (optional: string) – Current locale. If you don't pass this prop then detectLocale or defaultLocale is used (see below).
  • detectLocale (optional: boolean = true) - If locale prop is omitted targem will try to detect your locale based on navigator.language. If locale is not found there then defaultLocale is used as a fallback.
  • defaultLocale (optional: string) – Locale that is used as a fallback for detectLocale or when detectLocale is disabled and locale prop is empty.
  • direction (optional: "ltr" | "rtl") – Current text direction. When omitted direction is resolved based on the current locale. There is a predefined list of 12 locale codes for which react-targem knows that they are "rtl".
  • controlBodyDir (optional: boolean = true) – By default (if not SSR) when direction changes TargemProvider tries to do document.body.dir = direction. You can disable this by passing controlBodyDir={false}.
  • setBodyDir (optional: (dir: "ltr" | "rtl") => void) – When controlBodyDir is enabled you can pass your own function to override existing document.body.dir = direction behavior.

<TargemStatefulProvider/>

import { TargemStatefulProvider } from "react-targem";

A thin wrapper around <TargemProvider /> that allows you to store and change current locale. When <TargemStatefulProvider /> is used, wrapping your component with withLocale(Component) also provides it with changeLocale(locale: string) function. See withLocale.

Props:


<T/>

import { T } from "react-targem";

Exposes a set of props that make it easy to translate and interpolate your content.

Props:

  • message | children (required: string) – Message to translate (msgid in pot).
  • messagePlural (optional: string) – Plural version of the message (msgid_plural in pot).
  • count (optional: number) – Used to translate pluralized message and also interpolates into messagePlural and message as {{ count }}.
  • scope (optional: Object) – Used as variables source when interpolating message and messagePlural.
  • context (optional: string) – Translation context (msgctxt in pot).
  • component (optional: React.ReactType) – Component or element type to wrap your translation string with.
  • componentProps (optional: Object) – Props to be passed to your wrapper component.
  • formatNumbers (optional: boolean | Intl.NumberFormatOptions = false) – Whether to format count and all numbers in scope object using Intl.NumberFormat. If browser (or Node) doesn't support Intl.NumberFormat then formatting fallbacks to Number.prototype.toLocaleString().
    You can omit message prop and use count with formatNumbers to just format a number like this:
    <T count={1234.5678} formatNumbers={{ maximumFractionDigits=2 }} />

withLocale(Component)

import { withLocale } from "react-targem";

or as a hook

import { useLocale } from "react-targem";

Provides Component with the react-targem context variables as props.

These props are:

  • locale : string – Current locale.
  • direction : "ltr" | "rtl" – Current text direction.
  • changeLocale : undefined | (locale: string) => void – This function is passed only when <TargemStatefulProvider /> is used. It changes current locale.
  • t : (message: string, scope: Object = {}, context?: string) => string – Translates and interpolates message. See the usage below.
  • tn : (message: string, messagePlural: string, count: number, scope: Object = {}, context?: string) => string – Translates and interpolates pluralized message. See the usage below.
  • tf – Same as t but also formats all numbers. See formatNumbers in <T/> props above.
  • tnf – Same as tn but also formats all numbers. See formatNumbers in <T/> props above.
import { withLocale } from "react-targem";

function Head({ locale, t, tn }) {
  const messagesCount = 3;
  const sender = "Alex";

  return (
    <ReactHelmet>
      <html lang={locale} />
      <title>
        {tn(
          "New message from {{ name }}",
          "{{ count }} new messages from {{ name }}",
          messagesCount,
          { name: sender },
          "head title",
        )}
      </title>
      <meta name="description" content={t("Some description")} />
    </ReactHelmet>
  );
}

export default withLocale(Head);

Locale switching

react-targem makes it possible to change locale and have all the application's translations instantly update to those of the new locale. <TargemProvider> will trigger a re-render of all <T> components and components wrapped in withLocale() whenever its locale or translations props change.

Note: For performance reasons, and in favour of immutability, this check is done using shallow equality, which means you need to pass an entirely new object reference as translations for it to trigger the re-render. If this is an issue for you, simply make sure you create a new object when you get new translations.

Size

      6.02 kB: index.min.mjs
      2.54 kB: index.min.mjs.gz
      2.29 kB: index.min.mjs.br

      7.53 kB: index.umd.min.js
      2.93 kB: index.umd.min.js.gz
      2.65 kB: index.umd.min.js.br

See also

  • gettext-utils - A set of utils to simplify translation flow in your project.

About

Use Gettext localizations in your React app with an ease!

Resources

License

Stars

Watchers

Forks

Packages

No packages published