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

tokimeki-i18n

v0.2.0

Published

Tiny, flash-free, race-free i18n runtime for Svelte 5 and beyond

Downloads

342

Readme

tokimeki-i18n

Tiny, flash-free, race-free i18n runtime for Svelte 5 and beyond.

  • ~1 KB gzipped runtime, zero dependencies. No ICU parser, no merge library, no memoization layers.
  • No text flash, ever. The translator store only emits formatters bound to fully loaded dictionaries. A locale switch is a single atomic swap after its dictionaries are ready.
  • No races, by construction. setLocale calls are serialized with a generation token — the last call deterministically wins. There is no implicit initialLocale that can finish loading later and overwrite your choice.
  • Only the current locale (+ fallback) is ever downloaded. Dictionaries are lazy import()ed, loaded in parallel, cached once, and non-active locales are evicted from memory after a switch.
  • Familiar $_('key') template notation, so migrating a large existing codebase is mostly an import swap.
  • Works with any framework that understands the Svelte store contract; no runtime dependency on Svelte itself.

Install

npm install tokimeki-i18n

Quick start

// src/lib/i18n.ts — imported once, for its side effect
import { setupI18n } from 'tokimeki-i18n';

setupI18n({
    fallback: 'en',
    locales: {
        en: [() => import('./locales/en.json')],
        ja: [() => import('./locales/ja.json'), () => import('./locales/extra/ja.json')],
        'pt-BR': 'pt',                       // alias: shares pt's dictionaries
        pt: [() => import('./locales/pt.json')],
    },
});
// SvelteKit: +layout.ts — gate first render on the resolved locale
import '$lib/i18n';
import { setLocale } from 'tokimeki-i18n';

export async function load() {
    await setLocale(savedLanguage ?? navigator.language);
}
<script>
    import { _, locale } from 'tokimeki-i18n';
</script>

<h1>{$_('hello', { name: 'World' })}</h1>
<p>current locale: {$locale}</p>

API

| Export | Description | | --- | --- | | setupI18n(config) | Registers locales and the fallback. Pure registration — nothing loads until setLocale. Calling it again fully resets the runtime (tests, HMR). | | addLocales(locales) | Additive registration for component libraries: merges dictionary sources into the host app's registry instead of resetting it. Already-loaded locales are hot-merged and re-emitted atomically. Creates a minimal registry (fallback en) when the host has not called setupI18n. | | setLocale(tag) | Resolves tag (exact → BCP-47 subtag narrowing → fallback), loads the locale and fallback dictionaries in parallel, then applies them in one atomic swap. Resolves to the applied locale. If everything is already cached the swap is synchronous. Last concurrent call wins. | | preloadLocale(tag) | Speculatively warms the dictionary cache (e.g. when a language selector opens) so the following setLocale is synchronous. Load errors are swallowed; setLocale will retry. | | getLocale() | Current applied locale, synchronously (undefined before the first setLocale). | | t(key, params?) | Synchronous translation for plain .ts/.js code. | | _ | Store of the translator function: $_('key'), $_('key', { name }). | | locale | Read-only store of the applied locale: $locale. Writes go through setLocale. |

Messages

Dictionaries are flat JSON: { "hello": "Hello {name}" }. Placeholders are {param}; params are passed flat: $_('hello', { name: 'World' }). A missing key falls back to the fallback locale's message, then to the key itself (hook onMissing in setupI18n for diagnostics). No ICU MessageFormat — that is what keeps the runtime ~1 KB. Dictionary sources can also be plain objects instead of loader functions (inline a critical subset for zero-network first paint).

Dictionary tree-shaking (optional Vite plugin)

Unused message keys can be pruned from dictionary chunks at build time:

// vite.config.ts
import { pruneMessages } from 'tokimeki-i18n/vite';

plugins: [
    pruneMessages({
        dictionaries: 'src/lib/i18n/locales/**/*.json',
        mode: 'report',            // start here: logs prunable keys, changes nothing
        // mode: 'prune',          // then enable pruning
        // keepKeys: [/^external_/], // keys resolved from data unknown at build time
        // reportFile: 'i18n-prune-report.json',
    }),
]

The scan is conservative: a key is kept if it appears as a string literal anywhere in your sources (so $_(preview.key) is safe as long as the key string exists somewhere, e.g. where preview is built). Keys that only arrive from network data must be listed in keepKeys or excluded per dictionary via exclude.

For library authors

A component library that ships its own translations must NOT call setupI18n — that would reset the host app's registry. Use addLocales instead:

// your-lib/src/i18n.ts — imported for its side effect by your components
import { addLocales, getLocale, setLocale } from 'tokimeki-i18n';
import en from './locales/en.json';
import ja from './locales/ja.json';

addLocales({ en: [en], ja: [ja] });
if (!getLocale()) setLocale(navigator.language);
  • Embedded in a host app that uses tokimeki-i18n: your keys merge into the host registry and your UI follows the host's setLocale automatically. Namespace your keys (myLib.save) to avoid collisions.
  • Standalone (host has no tokimeki-i18n setup): addLocales creates a minimal registry (fallback en) and the setLocale(navigator.language) fallback kicks in because getLocale() is still undefined.
  • Ordering: the host's setupI18n must run before your addLocales (app bootstrap before lazily loaded components — the natural order). Declare tokimeki-i18n as a peerDependency so the host and your library share one runtime instance.

SSR

The runtime is a module-level singleton, designed for client-rendered apps (ssr = false in SvelteKit). It is safe to import on the server, but per-request locale isolation is not provided.

Publishing (maintainer notes)

npm run check && npm test && npm run build
npm publish        # prepublishOnly runs check + test + build

License

MIT