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

@chipmobilesdk/rn-i18n

v0.1.1

Published

Reusable localization for ChipMobileSdk-family React Native apps: per-locale configuration, app-owned namespaced translations, typed keys, interpolation, pluralization, fallback chains, runtime locale switching with app-injected persistence, device-loc

Readme

@chipmobilesdk/rn-i18n

Reusable localization for ChipMobileSdk-family React Native apps: per-locale configuration, app-owned namespaced translations, typed keys, interpolation, pluralization, fallback chains, runtime locale switching with app-injected persistence, device-locale detection, locale-aware number/date/currency/unit formatting, and a Node CLI that extracts and synchronizes translation keys.

License: UNLICENSED. Published publicly for use by the owner's applications; no open-source license is granted.

  • Zero runtime dependencies. Formatting uses the Intl APIs built into Hermes; plural rules and unit conversion are package-owned.
  • No native code. Storage and (optionally) device-locale detection are injected by the consuming app.
  • Public package. Published under the @chipmobilesdk npm organization.
  • Version: 0.1.0
  • Entrypoints: @chipmobilesdk/rn-i18n and the Node-only @chipmobilesdk/rn-i18n/tooling

Installation

This package ships TypeScript sources and is consumed through the workspace or the public npm registry:

npm install @chipmobilesdk/rn-i18n

Host frameworks are peer dependencies:

// peerDependencies
"react": ">=19",
"react-native": ">=0.85"

Quick start

import { createI18n } from '@chipmobilesdk/rn-i18n';
import enUS from './locales/en-US.json';
import viVN from './locales/vi-VN.json';
import { storageAdapter } from './storage';
import type { AppI18nKey } from './keys.generated';

export const i18n = createI18n<AppI18nKey>({
  primaryLocale: 'en-US',
  locales: [
    {
      code: 'en-US',
      displayName: 'English (US)',
      direction: 'ltr',
      fallbackChain: [],
      defaultCurrency: 'USD',
      defaultUnit: 'mile',
      defaultDateFormat: { year: 'numeric', month: 'short', day: 'numeric' },
      defaultNumberFormat: { maximumFractionDigits: 2 },
    },
    {
      code: 'vi-VN',
      displayName: 'Tiếng Việt',
      direction: 'ltr',
      fallbackChain: ['en-US'],
      defaultCurrency: 'VND',
      defaultUnit: 'kilometer',
      defaultDateFormat: { day: '2-digit', month: '2-digit', year: 'numeric' },
      defaultNumberFormat: { maximumFractionDigits: 2 },
    },
  ],
  resources: { 'en-US': enUS, 'vi-VN': viVN },
  storage: storageAdapter,
});

await i18n.init(); // persisted -> device -> primary fallback

Wrap the app and use the hooks:

import { I18nProvider, useTranslation, useLocale } from '@chipmobilesdk/rn-i18n';

<I18nProvider i18n={i18n}>
  <App />
</I18nProvider>;

const { t } = useTranslation<AppI18nKey>();
const { locale, direction, supportedLocales, setLocale } = useLocale();

t('welcome.message', { name: 'Dung' });
t('cart.items', { count }, { count }); // plural variant by count

Public API

| Capability | Member | |------------|--------| | Setup + validation | createI18n(config), I18nConfigError | | Translation lookup | i18n.t, useTranslation | | Locale state + switching | i18n.getLocale, i18n.setLocale, useLocale | | Locale metadata (RTL/LTR, defaults) | i18n.getSupportedLocales | | Device-locale init | i18n.init, defaultDeviceLocaleProvider | | Formatting | i18n.formatNumber/formatDate/formatCurrency/formatUnit | | Unit conversion | i18n.convertUnit, convertUnit, getUnitSymbol, SUPPORTED_UNITS, UnitConversionError | | Runtime-only declarations | i18n.registerRuntimeEntries | | Persistence key | LOCALE_STORAGE_KEY | | React | I18nProvider |

Public contract types also include the configuration, locale, translation, formatting, unit, provider/adapter, and hook result types exported by src/index.ts. Do not deep-import package internals. Node-only extraction and synchronization APIs must be imported from @chipmobilesdk/rn-i18n/tooling.

Storage adapter (required for persistence)

The package never bundles a storage backend (FR-046/FR-047). Inject one:

import type { LocaleStorageAdapter } from '@chipmobilesdk/rn-i18n';
import AsyncStorage from '@react-native-async-storage/async-storage';

export const storageAdapter: LocaleStorageAdapter = {
  getItem: key => AsyncStorage.getItem(key),
  setItem: (key, value) => AsyncStorage.setItem(key, value),
  removeItem: key => AsyncStorage.removeItem(key),
};

An MMKV-backed adapter (wrapping its synchronous API in Promise.resolve) works equally well. If persistence is enabled without an adapter, createI18n throws before any localized content is served.

Device-locale provider (optional)

The default reads Intl.DateTimeFormat().resolvedOptions().locale. Apps that need richer detection can inject deviceLocale (e.g. backed by react-native-localize); that dependency stays in the app, never the package.

Translations

App-owned JSON, organized by locale and namespace; nested dot-path keys, {{name}} interpolation, and plural groups:

{
  "welcome": { "message": "Welcome, {{name}}!" },
  "cart": { "items": { "one": "{{count}} item", "other": "{{count}} items" } }
}

Plural categories deliberately come from package-owned rules rather than depending on Intl.PluralRules, which keeps behavior consistent across the supported Hermes environments. Built-ins cover en (one/other), vi/ja (other-only), and a default count === 1 -> one rule; supply LocaleConfig.pluralRule for richer languages.

Extraction & synchronization CLI

Node-only, exposed via @chipmobilesdk/rn-i18n/tooling and a CLI. Add an app config (i18n-sync.config.json) and a script:

{
  "sourceGlobs": ["src/**/*.ts", "src/**/*.tsx"],
  "patterns": [{ "regex": "[^\\w.]t\\(\\s*'(?<key>[A-Za-z0-9_.-]+)'" }],
  "localesDir": "src/i18n/locales",
  "locales": ["en-US", "vi-VN", "ja-JP"],
  "runtimeEntriesFile": "src/i18n/runtime-keys.ts",
  "generateKeysFile": "src/i18n/keys.generated.ts",
  "keysTypeName": "AppI18nKey"
}
// package.json
"scripts": {
  "i18n:sync": "node --experimental-strip-types node_modules/@chipmobilesdk/rn-i18n/src/tooling/cli.ts --config i18n-sync.config.json"
}

Running it scans the source tree, then per locale: creates missing files, adds missing keys (with the placeholder policy), preserves existing translations, removes stale keys, protects declared runtime-only keys, regenerates the typed key contract, and prints a report. Exit codes: 0 success/warnings, 1 blocking findings (conflicts, malformed locale files), 2 invalid config.

Bind t() to the generated AppI18nKey so tsc --noEmit reports invalid or stale key usage before release.

Runtime-only keys

Keys resolved only at runtime (declared in runtimeEntriesFile) use the same lookup, fallback, interpolation, and missing-key behavior, and are never removed by synchronization. Policy add writes the default text to missing locales; report only lists them.

Compatibility

| Surface | Baseline | |---------|----------| | React / React Native | 19.x / 0.85+ (Hermes) | | TypeScript | 5.8+ | | Node (tooling) | >=22.11.0 | | Platforms | Android, iOS (no native code) |

Validation

npm test                     # package + demo suites
npm run typecheck:i18n       # tsc -p packages/rn-i18n/tsconfig.json --noEmit
npm run pack:i18n            # npm pack --workspace @chipmobilesdk/rn-i18n --dry-run
npm run i18n:sync            # extraction + synchronization

The demo integration lives in src/screens/I18nDemoScreen.tsx and uses src/i18n/ for setup, translations, persistence, and generated keys.

See CHANGELOG.md for release notes and adoption guidance.