9.13.0 • Published 2 years ago

ilenia v9.13.0

Weekly downloads
1,409
License
MIT
Repository
github
Last release
2 years ago

ilenia

A library for localization in React. Simple, declarative and focused on components.

Named after our dear and glorious Localization Coordinator at Trustpilot. But she made us come up with an acronym, so here goes: intentional library extending natural internationalization algorithms.

Table of contents

How to install ?

npm install ilenia
// or
yarn add ilenia

The library only builds es modules and has full tree shaking capability.

Note: Node version ^14 is needed for server-side localization of numbers + dates

Using the library

  1. Wrap your app with the LocalizationProvider and pass current locale and translations. In the example we're merging the default language translations and the active one as selected by the user. That means there's a fallback if a string is missing.
import { LocalizationProvider, Text } from 'ilenia';

const locale = 'de-DE';
const enUS = {
  'header': 'Localized React app',
  'welcomeMessage': 'Welcome to this website!'
};
const deDE = {
  'header': 'Übersetzungen machen Spaß!'
};

const mergedTranslations = { ...enUS, ...deDE, };

const App = () => ({
  <LocalizationProvider locale={locale} translations={mergedTranslations}>
    <div className="app">
      <h1><Text id="header"/></h1>
      <Text id="welcomeMessage"/>
    </div>
  </LocalizationProvider>
});

Components

Text

Use the <Text> component to translate a string in place. See how to interpolate here.

import { Text } from 'ilenia';

const translations = {
  header: 'This is the header of our site',
  greeting: 'Welcome to [name]',
};

const interpolations = {
  name: 'Trustpilot',
};

const Header = () => (
  <div>
    <h1>
      <Text id="header" />
    </h1>
    <p>
      <Text id="greeting" interpolations={interpolations} />
    </p>
  </div>
);

You can also interpolate pairs of tags to render React components.

import { Text } from 'ilenia';

const translations = {
  first: 'A string with a [LINK-BEGIN]link[LINK-END] in it.',
  second: 'A string with a {{LINK-START}}link{{LINK-END}} in it.',
};

const CustomLink = ({ text }) => <a>{text}</a>

const App = () => (
  <div>
    <p><Text id="first" interpolations={{ link: (m) => <CustomLink text={m}/> }}/></p>
    <p>
      <Text
        id="second"
        interpolations={{ LINK: (m) => <CustomLink text={m}/> }}
        tag={{ start: '{{', end: '}}' }}
        suffix={{ begin: '-start', end: '-end' }}
      />
    </p>
  </div>
)

LinkText

Use <LinkText> to render a string with links in it. Any properties added to the link object will be added to the link element that is created.

import { LinkText } from 'ilenia';

const translations = {
  footer: 'Please check out or [LINK-BEGIN]awesome blog[LINK-END]',
};

const App = () => <LinkText id="footer" links={[{ href: 'https://tech.trustpilot.com/' }]} />;

Or if your link has different tokens:

import { LinkText } from 'ilenia';

const translations = {
  footer: 'Please check out or {mylink}awesome blog{/mylink}',
};

const App = () => (
  <LinkText
    id="footer"
    links={[
      {
        href: 'https://tech.trustpilot.com/',
        start: '{mylink}',
        end: '{/mylink}',
      },
    ]}
  />
);

It's possible to add click handlers to the created links as well (eg. a tracking event):

import { LinkText } from 'ilenia';

const translations = {
  bodyText: 'Click here to [LINK-BEGIN]read more[LINK-END]',
};

const link = {
  href: 'https://tech.trustpilot.com/',
  onClick: () => analytics.track(),
};

const App = () => <LinkText id="bodyText" links={[link]} />;

Add interpolation to your link text.

import { LinkText } from 'ilenia';

const translations = {
  footer: 'Please check out or [LINK-BEGIN]awesome blog[LINK-END]. Latest post: [date]',
};

const App = () => (
  <LinkText
    id="footer"
    links={[{ href: 'https://tech.trustpilot.com/' }]}
    interpolations={{ date: new Date() }}
  />
);

HtmlText

Use the <HtmlText> component to translate a string with html in it. See how to interpolate here.

NB. HtmlText doesn't work in node programs (SSR websites for example). In a node program, use something like DOMPurify or sanitize-html directly.

import { HtmlText } from 'ilenia';

const translations = {
  header: 'This is the [html1]header[html2] of our site',
  footer: 'The HTML can also be kept <em>in the string</em>.',
};

const interpolations = {
  html1: '<b>',
  html2: '</b>',
};

const Header = () => (
  <div>
    <h1>
      <HtmlText id="header" interpolations={interpolations} />
    </h1>
    <p>
      <HtmlText id="footer" />
    </p>
  </div>
);

LocaleNumber

Use the <LocaleNumber> component to localize a number. Set the decimal places with maxDecimals, truncates zeros.

import { LocaleNumber } from "ilenia";

<LocaleNumber number={1000000} />
<LocaleNumber number={142.069} maxDecimals={2} />

To localize a percentage, include the percentage prop. Requires decimal input.

import { LocaleNumber } from "ilenia";

<LocaleNumber number={0.59} percentage /> // ==> '59%' or similar

LocaleDate

Used for rendering a date in a localized format. Uses toLocaleDateString behind the scenes, using the locale from the provider.

import { LocaleDate } from 'ilenia';

<LocaleDate date={new Date()} />; // renders something like 21/9/2018 depending on the locale

It is also possible to specify formatting options:

import { LocaleDate } from 'ilenia';

<LocaleDate
  date={new Date()}
  format={{
    day: 'numeric',
    month: 'short',
    year: 'numeric',
  }}
/>; // renders something like Sep 21, 2018 depending on the locale

LocaleTime

Like LocaleDate, but uses toLocaleTimeString behind the scenes. This allows for rendering only the time component of a date.

import { LocaleTime } from 'ilenia';

<LocaleTime date={new Date()} />; // renders something like 10:37:33 AM depending on the locale

It is also possible to specify formatting options:

import { LocaleTime } from 'ilenia';

<LocaleTime
  date={new Date()}
  format={{
    hour: 'numeric',
    minute: 'numeric',
  }}
/>; // renders something like 10:37 AM depending on the locale

TimeAgo

Use this component for relative dates (1 year ago, 2 minutes ago etc.):

import { TimeAgo } from 'ilenia';

const date = new Date(2018, 1, 15)
<TimeAgo date={date}/> // renders someting like "6 months ago"

HumanizeTime

The component accepts a number of milliseconds and renders it to a human readable text. It renders the same as <TimeAgo> but without the 'ago' postfix.

If needed, the component has an optional type prop, which allows for any custom logic for formatting time intervals or setting one of the built-in ones from javascript-time-ago.

import { HumanizeTime } from 'ilenia';

<HumanizeTime milliseconds={600000}/>  // renders "10 minutes"

const yesterday = new Date().setDate(new Date().getDate() + -1); //Returns ms since 1970, 1 day ago
const oneDayMS = Date.now() - yesterday; // 86400000 ms
<HumanizeTime milliseconds={oneDayMS}/> // renders "1 day"
<HumanizeTime milliseconds={oneDayMS} type={"mini-minute"} /> // renders "1d"

useTranslations

Get access to the raw translations data from the context with the useTranslations custom hook:

function App() {
  const [translations, locale] = useTranslations();

  return (
    <div>
      <h1>
        {translations.welcome} in {locale}
      </h1>
    </div>
  );
}

withTranslations

To get access to raw translations data or the current locale in a component, use the withTranslations HOC:

const TextRenderer = ({ locale, translations, isFirstVisit, visitorNumber }) => {
  const stringToRender = isFirstVisit
    ? translations['welcomeFirstVisit']
    : translations['welcomeBack'];
  const visitorNumberDisplay = visitorNumber.toLocaleString(locale);
  return <WelcomeMessage message={stringToRender} numberDisplay={visitorNumberDisplay} />;
};

export default withTranslations(TextRenderer);

Interpolate

An interpolate function is exposed from this library. This function can be used to replace tokens in a translation string. The components in the library use this function internally. The interpolate function is meant to be used with the withTranslations HOC. It returns an array of React elements, there will only be one element in the result if your interpolation items are strings but it can have multiple elements if you are interpolating React components.

import { interpolate } from 'ilenia';

let output = interpolate('Value with a [token] in it', { token: 'cookie' });
<p>{output}</p>;

output = interpolate('Value with a [component] in it', {
  component: <LocaleNumber number={123.25} />,
});
<p>{output}</p>;

If you use a different placeholder syntax in your translations object, you can use the optional argument tag:

import { interpolate } from 'ilenia';

const inputString = 'This is the [[html1]]header[[html2]] of our site';

const interpolations = {
  html1: '<b>',
  html2: '</b>',
};

const tag = {
  start: '[[',
  end: ']]',
};

const [finishedString] = interpolate(inputString, interpolations, tag);

console.log(finishedString); // logs 'This is the <b>header</b> of our site'

The examples above describe and as well. The difference is, that the variables are sent as props instead of function arguments:

<Text id="string" interpolations={interpolationsObject} tag={tags}/>
<HtmlText id="string" interpolations={interpolationsObject} tag={tags}/>

How to contribute?

This repo enforces commit style so that the release process is automatic. Commits must look like:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

Check conventional commits for more details.

Found a problem ?

Please open an issue or submit a PR, we will be more than happy to help.

9.13.0

2 years ago

9.12.1

2 years ago

9.12.0

2 years ago

9.11.2

2 years ago

9.11.1

3 years ago

9.11.0

3 years ago

9.10.0

3 years ago

9.9.0

3 years ago

9.8.0

3 years ago

9.7.0

4 years ago

9.6.0

4 years ago

9.5.1

4 years ago

9.5.0

4 years ago

9.4.0

4 years ago

9.3.0

4 years ago

9.2.1

4 years ago

9.2.0

5 years ago

9.1.0

5 years ago

9.0.4

5 years ago

9.0.3

5 years ago

9.0.2

5 years ago

9.0.1

5 years ago

9.0.0

5 years ago

8.4.0

5 years ago

8.3.0

5 years ago

8.2.0

5 years ago

8.1.0

5 years ago

8.0.0

5 years ago

7.1.0

5 years ago

7.0.2

5 years ago

7.0.1

5 years ago

7.0.0

5 years ago

6.0.1

5 years ago

6.0.0

6 years ago

0.0.1

6 years ago