npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

ilenia

v9.13.0

Published

Components and utilities for translations and localization in React

Downloads

1,189

Readme

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.