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

@transglot/runtime

v0.1.0

Published

Zero-dependency runtime i18n client for transglot: loads PUBLISHED translation bundles from the OTA/CDN endpoint with ETag/304 caching, interpolation and Intl.PluralRules plurals.

Downloads

185

Readme

@transglot/runtime

Zero-dependency, framework-agnostic runtime i18n client for transglot. It loads a project's published translation bundles from the OTA/CDN endpoint, caches them in memory with ETag/304 revalidation, interpolates params, and selects plural forms with Intl.PluralRules, so an app fetches strings at runtime and a published typo fix ships without a rebuild.

  • Zero runtime dependencies. ESM, Node >= 20 and the browser.
  • The real wire, pinned. Targets GET /v1/cdn/{project}/{locale} (and the immutable /v{n}), the X-Transglot-Cdn-Key auth, and the JSON-family bundle bodies, read off the server, not guessed.
  • Offline cold start + OTA. An optional persistent storage layer serves last-known-good strings before the network is reachable (React Native / offline), then revalidates; refreshIntervalMs and an onForeground hook make the active locale update over the air.

Install

npm install @transglot/runtime

Quickstart

import { createClient } from '@transglot/runtime';

const i18n = createClient({
  baseUrl: 'https://app.example.com', // your transglot origin (or a CDN in front of it)
  project: 42,                        // numeric project id
  cdnKey: 'taicdn_…',                 // read-only CDN key from the deploy hub
  locale: 'en',                       // initial locale
});

// Load (or ETag-revalidate) the active locale's bundle, then translate.
await i18n.loadLocale('en');

i18n.t('home.title');                       // "Welcome"
i18n.t('cart.summary', { name: 'Ada' });    // interpolates {name}
i18n.t('cart.items', { count: 3 });         // selects the plural form for the locale

// Switch locales, and subscribers re-render.
const stop = i18n.onChange((locale) => render(locale));
await i18n.setLocale('fr');

API

createClient(options)RuntimeClient

| option | required | meaning | | --- | --- | --- | | baseUrl | yes | origin of the app / CDN, e.g. https://app.example.com | | project | yes | numeric project id (the CDN URL segment) | | cdnKey | yes | read-only taicdn_… key | | locale | yes | initial locale | | version | no | pin an immutable …/v{n} version instead of "latest" | | authIn | no | 'header' (default, X-Transglot-Cdn-Key) or 'query' (?key=, skips a browser CORS preflight) | | fetchImpl | no | injected fetch (tests / non-browser) | | dev | no | dev-mode warnings for missing keys (default on unless NODE_ENV=production) | | storage | no | a persistent { get, set } store for last-known-good bundles (cold start). See Persistent cache | | refreshIntervalMs | no | background-revalidate the active locale every N ms (OTA). See Background OTA refresh | | onForeground | no | wire a "became visible / foregrounded" signal to a background revalidate | | scheduler | no | injected { setInterval, clearInterval } (tests / non-standard runtimes) |

RuntimeClient:

  • t(key, params?): interpolate {name} params; select plurals via Intl.PluralRules when params.count is a number. A missing key returns the key (plus a dev warning) and never throws.
  • loadLocale(locale): fetch or ETag-revalidate a locale's bundle into the cache. A 304 Not Modified keeps the cached bundle (no re-download).
  • setLocale(locale): load then switch the active locale; notifies onChange.
  • preload(locales): warm several locales without switching.
  • hydrate(locale?): populate the cache for a locale (default: active) from storage with no network call, so a cold start serves last-known-good immediately. Resolves true when a bundle is available. A no-op returning false when no storage was configured; never throws on a corrupt value.
  • refresh(): revalidate the active locale (the manual OTA primitive; an alias for loadLocale(getLocale())).
  • stop(): stop the refreshIntervalMs timer and detach the onForeground hook. Idempotent; call it on teardown/unmount.
  • getLocale(), hasLocale(locale), onChange(listener) -> unsubscribe.

Network/HTTP failures surface as a typed RuntimeError carrying a stable slug (cdn-key-invalid, not-published, network-error, ...) and a hint.

Persistent cache (offline cold start)

By default the client caches bundles in memory only, so a fresh process (a React Native cold start, a new browser tab) begins empty and must hit the network before it can translate. Pass a storage adapter and the client persists each locale's last-known-good bundle ({ etag, version, entries }, keyed per project and locale), so a cold start serves strings before the network is reachable, then revalidates:

const i18n = createClient({
  baseUrl: 'https://app.example.com',
  project: 42,
  cdnKey: 'taicdn_…',
  locale: 'en',
  storage: {
    get: (key) => localStorage.getItem(key),
    set: (key, value) => localStorage.setItem(key, value),
  },
});

// Cold start: serve last-known-good with NO network call, then revalidate.
if (await i18n.hydrate()) {
  render(); // already translated, offline-safe
}
await i18n.loadLocale('en'); // conditional GET: a 304 keeps the cached bundle,
                             // a new publish replaces it and re-persists

The in-memory Map stays the hot layer; storage is the cold layer, hydrated into it on a miss. get/set may be synchronous (localStorage) or return promises (React Native AsyncStorage, IndexedDB); the client awaits either. A read or write that throws, or a corrupt persisted value, is ignored (persistence is best-effort and never breaks t).

Background OTA refresh

refreshIntervalMs background-revalidates the active locale on a timer, and onForeground lets the host revalidate whenever the app becomes visible again, so a published change reaches a running app over the air:

const i18n = createClient({
  baseUrl: 'https://app.example.com',
  project: 42,
  cdnKey: 'taicdn_…',
  locale: 'en',
  refreshIntervalMs: 5 * 60_000, // revalidate every 5 minutes
  onForeground: (revalidate) => {
    const on = () => { if (!document.hidden) revalidate(); };
    document.addEventListener('visibilitychange', on);
    return () => document.removeEventListener('visibilitychange', on);
  },
});

i18n.onChange(() => render()); // a landed publish re-renders subscribers
// On teardown:
i18n.stop();

Both triggers revalidate in the background and never reject; a landed publish notifies onChange subscribers exactly like a setLocale.

React Native usage

React Native has no localStorage, unpredictable connectivity, and a foreground lifecycle via AppState. Wire AsyncStorage for offline cold start and AppState for OTA:

import { createClient } from '@transglot/runtime';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { AppState } from 'react-native';

export const i18n = createClient({
  baseUrl: 'https://app.example.com',
  project: 42,
  cdnKey: 'taicdn_…',
  locale: 'en',
  // AsyncStorage's getItem/setItem already match the { get, set } shape.
  storage: { get: AsyncStorage.getItem, set: AsyncStorage.setItem },
  refreshIntervalMs: 15 * 60_000,
  onForeground: (revalidate) => {
    const sub = AppState.addEventListener('change', (state) => {
      if (state === 'active') revalidate();
    });
    return () => sub.remove();
  },
});

// At app startup: paint last-known-good instantly (offline-safe), then revalidate.
await i18n.hydrate();
i18n.loadLocale('en').catch(() => {}); // fine to fail offline; the cache still serves

Supported delivery formats

The runtime SDK reads the JSON-family delivery formats: json_flat (default), json_nested, laravel_json and flutter_arb. All normalize to the same dotted-key space (home.title), so the key you call t() with is stable across formats. Plurals are carried by flutter_arb's ICU messages; the flat JSON formats drop plurals at publish time, so they contain only simple strings.