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

@suckless/i18n

v0.6.0

Published

Type-safe internationalization with BCP 47 locale resolution

Readme

@suckless/i18n

Minimal, type-safe internationalization with BCP 47 locale resolution.

Install

npm install @suckless/i18n

Usage

Define translations as plain strings or functions:

// locales/en.ts
import type { Dict } from "@suckless/i18n"

export default {
	home: "Home",
	greeting: (p: { name: string }) => `Hello, ${p.name}!`,
	items: (p: { count: number }) =>
		p.count === 1 ? `${p.count} item` : `${p.count} items`,
} satisfies Dict

Use strings for static text, functions when you need interpolation or logic.

Type contract

The base locale defines the shape. Enforce it on other locales with satisfies:

// locales/es.ts
import type en from "./en"

export default {
	home: "Inicio",
	greeting: (p: { name: string }) => `Hola, ${p.name}!`,
	items: (p: { count: number }) =>
		p.count === 1 ? `${p.count} elemento` : `${p.count} elementos`,
} satisfies typeof en
// ^ Adding a key to en without adding it here is a compile error.

Partial overrides with merge

Use merge for regional variants without duplicating the full dictionary:

// locales/es-ar.ts
import es from "./es"
import { merge } from "@suckless/i18n"

export default merge(es, {
	greeting: (p: { name: string }) => `Ché, ${p.name}!`,
	// everything else inherited from es
})

Resolve and translate

import { resolve, translate } from "@suckless/i18n"

const loaders = {
	en: () => import("./locales/en").then((m) => m.default),
	es: () => import("./locales/es").then((m) => m.default),
	"es-AR": () => import("./locales/es-ar").then((m) => m.default),
}

const tag = resolve(loaders, "en", navigator.language)
const dict = await loaders[tag]()
const t = translate(dict)

t("greeting", { name: "World" }) // type-safe key + params
t("home") // no params needed for string entries

resolve only reads the keys of the object you pass — values are ignored. This lets you pass a loaders record, a dict record, or any object whose keys are locale tags.

Fallback chain

Locale resolution follows BCP 47 prefix stripping:

  • es-AR → exact match if registered
  • es-VE → no es-VE → tries es → match
  • pt-BR → no pt-BR → tries pt → no pt → fallback locale

API

translate(dict)

Wraps a dictionary in a type-safe translate function.

  • dict — A Dict object (string or function entries).
  • ReturnsTranslateFn<D> with autocomplete on keys and type-checked parameters.

resolve(locales, fallback, locale)

Resolves a locale string via BCP 47 prefix stripping.

  • locales — Object whose keys are supported locale tags. Values are ignored.
  • fallback — Key in locales used when no match is found (compile-time and runtime checked).
  • locale — The locale string to resolve.
  • Returns — The matched key from locales.

merge(base, overrides)

Merges a base dictionary with partial overrides.

  • base — The full dictionary to extend.
  • overrides — A partial dictionary. Only keys from base are allowed, with matching types.
  • Returns — A new dictionary with the same type as base.

Types

type Entry = string | ((...args: never[]) => string)
type Dict = Record<string, Entry>
type TranslateFn<D extends Dict> = <K extends keyof D & string>(
	key: K,
	...args: D[K] extends (...args: infer A) => string ? A : []
) => string

License

MIT