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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@casipe/react-i18n

v1.0.2

Published

React library for internationalization and localization

Readme

@casipe/react-i18n

aka react-i18n

Installation

publish-legacy

N/A

publish

N/A

publish-next

N/A


Handling translation and localization

The best approach is to create general dictionaries for languages and then extend then to create localization. The main language in the application, or the fallback language, should be American English to better readability.

We must use valid language codes because we get language from browser and the format is en|es|pt for general language or country specific en-GB|es-MX|pt-BR. So when exporting locale assets, this pattern must be followed.

Bellow we have the full example of organization and usage:

  • folder organization
src/assets
  └ locales
      ├ index.ts // Exports
      ├ en-gb.ts // British English (just localization, no extension)
      ├ es.ts // General Spanish (Spain)
      ├ es-mx.ts // Localization for Mexico
      ├ es-ar.ts // Localization for Argentina
      ├ es-ur.ts // Localization for Uruguay
      ├ pt.ts // General Portuguese (Brazil)
      ├ pt-pt.ts // Localization for Portugal

es.ts and pt.ts files indicates to spanish and portuguese respectivelly, they will contain general translation for these languages and every other file that has {languageCode}-{countryCode}.{extension} will be localization only.

Bellow will have a full demonstration:

  • es.ts
export default {
  'Statefull component': 'Componente con estado',
  'Hello <%= name %>!': 'Hola <%= name %>!',
  'Subway stations': 'Estaciones de metro',
}

and then in pt.ts

  • es-mx.ts
// get pt
import pt from './pt'

export default {
  ...es, // extend it
  // modify what is needed accordingly localization for mexico
  'Hello <%= name %>!': 'Olá <%= name %>!',
}

The only exception to language extension is English languages as the base language is already in English we don't have a en.ts file. So in that case we just put the sentences that we want to override, any word that we don't declare, will use the base sentence that is already right.

  • en-gb.ts
export default {
  'Subway station': 'Underground stations',
}

and finally at index.ts

  • index.ts
import { I18nAssets } from '@casipe/react-i18n';

export const localeAssets: I18nAssets {
  'en-gb': () => import('./en-gb'),
  es: () => import('./es'),
  'es-ar': () => import('./es-ar'),
  pt: () => import('./pt'),
  'pt-br': () => import('./pt-br')
}

We use dynamic imports to load just what is selected by user in the application or when it's not choosen, we use browser main language (navigator.language).

And then give it to I18n component:

  • I18n
import { localeAssets, translate, t, I18nContext } from '@/assets/locales'
;<I18n assets={localeAssets}>
  <div>
    <p>From here you can use translate method</p>
    <p>or even get I18nContext</p>
  </div>
</I18n>

Using with LanguageRouter from @casipe/react-app-context

It's the same approach to organize and export files as I18n is already abstracted. Instead of giving assets to I18n, you give it to LanguageRouter.

import { LanguageRouter } from '@casipe/react-app-context'
;<LanguageRouter assetsLocales={localeAssets}>
  <div>
    <p>From here you can use translate method</p>
    <p>or even get I18nContext</p>
  </div>
</LanguageRouter>

Known issues

  • Returning to default language When manually changing languages, that is a behavior that user usually won't do, to any language and then coming back to en that is the default, it won't translate back. Only with a total refresh or the addition of a en: () => import('./en') with all texts duplicated.

Components

I18n

I18n is a translation component to adapt your application based on given or browser language.

  • Props
interface TranslationVars {
  [key: string]: unknown;
}

interface I18nDictionary {
  [key: string]: string;
}

interface I18nAssetImported {
  default: I18nDictionary;
}

type I18nAssetAsync = () => Promise<I18nAssetImported>

interface I18nAssets {
  [key: string]: I18nAssetAsync;
}

// component interface
interface I18nProps {
  children: ReactNode | ReactNodeArray;
  lang?: string;
  country?: string;
  assets?: I18nAssets;
  onLoaded?: () => void;
}

interface I18nState {
  dictionary: I18nDictionary;
  isLoadingLanguage: boolean;
  lang: string;
}

type TranslateType = (text: string, vars?: TranslationVars) => string

// context interface
interface I18nContextProps {
  country: string;
  dictionary: I18nDictionary;
  lang: string;
  translate: TranslateType;
}
  • Usage
import { I18nAssets, I18n, translate, t } from '@casipe/react-i18n'

const assets: I18nAssets = {
  es: () => import('./es'),
  pt: () => import('./pt')
}

...
<I18n lang="es" assets={assets}>
  <p>{translate('Sentence')}</p>
  <p>{t('Sentence')}</p>
  <p>{t('Untranslated sentence')}</p>
  <p>{t('Hello <%= name %>!', { name: 'Alejandro' })}</p>
  <p>{t('Goodbye <%= name %>!', { name: 'Alejandro' })}</p>

  <hr />
  <h3 style={{ 'margin-bottom': 0 }}>
    Using <mark>I18nContext/Consumer.translate</mark> method
  </h3>
</I18n>
...
  • Inline Context consumption
import { I18n, I18nContext, t } from '@casipe/react-i18n';

...
<I18n lang="es" assets={assets}>
  <I18nContext.Consumer>
    {({ translate }) => {
      return (
        <>
          <p>{translate('Sentence')}</p>
          <p>{t('Sentence')}</p>
          <p>{t('Untranslated sentence')}</p>
          <p>{t('Hello <%= name %>!', { name: 'Alejandro' })}</p>
          <p>{t('Goodbye <%= name %>!', { name: 'Alejandro' })}</p>
        </>
      );
    }}
  </I18nContext.Consumer>
</I18n>
...
  • useContext(I18nContext)
import { I18nContext } from '@casipe/react-i18n';

const SomeComponent = () => {
  const { translate } = useContext(I18nContext);
  return (
    <>
      <p>{translate('Sentence')}</p>
      <p>{t('Sentence')}</p>
      <p>{t('Untranslated sentence')}</p>
      <p>{t('Hello <%= name %>!', { name: 'Alejandro' })}</p>
      <p>{t('Goodbye <%= name %>!', { name: 'Alejandro' })}</p>
    </>
  );
};

...
<I18n lang="es" assets={assets}>
  <SomeComponent />
</I18n>
...

Plurals

Use an array of strings instead a string in t function as the following example: t(['text', 'text'], vars)

{{ [KEY] | [NUMBER] | [HIDE] }}

  • KEY: from vars (the second parameter)
  • NUMBER: if the value of KEY is greater or equal then NUMBER use that template
  • HIDE: hide the value of KEY, useful when you want to use custom text
<p>
  {t(
    [
      'no product', // default
      '{{count|1}} product', // count >= 1
      '{{count|2}} products', // count >= 2
      '{{count|99|true}}to many products', // count >= 99 and hide value
    ],
    { count: 1 },
  )}
</p>
// <p>1 product</p>

L10n

L10n is a localization component to adapt your application based on country. Once you set your country in a I18n wrapper, you can put a L10n component in places you want to opt to different components based on country setted.

This component MUST be used in an application that also set the I18n component.

  • Props
interface L10nProps {
  [key: string]: unknown;
  components: { [key: string]: FC };
}
  • Usage
import { L10n, L18n, translate } from '@casipe/react-i18n'

const ComponentForMexico = ({ name }) => <p>Hola {name}</p>

// with template
const ComponentForBrasil = ({ name }) => (
  <p>{translate('Hello <%= name %>', { name })}</p>
)

const LocalizedComponent = () => (
  <I18n lang="es" assets={assets}>
    <L10n
      name="Name"
      anotherProp="some"
      components={{
        mx: ComponentForMexico,
        br: ComponentForBrasil,
      }}
    />
  </I18n>
)

// Additional props will be fowarded to the selected component