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

@sveltebase/i18n

v2.0.1

Published

Locale state, translations, and date formatting for Svelte 5. Built on [use-intl](https://github.com/amannn/use-intl) and `@sveltebase/state`.

Readme

@sveltebase/i18n

Locale state, translations, and date formatting for Svelte 5. Built on use-intl and @sveltebase/state.

Install

bun add @sveltebase/i18n

Quick start

Define your languages once and create an i18n instance:

// src/lib/i18n.ts
import { createI18n } from "@sveltebase/i18n";

export const languages = [
  {
    code: "en",
    label: "English",
    messages: {
      "app-title": "My app",
      "welcome": "Welcome, {name}",
      "just-now": "Just now",
      "minutes-ago": "{minutes} minutes ago",
      "hours-ago": "{hours} hours ago",
      "days-ago": "{days} days ago",
      "weeks-ago": "{weeks} weeks ago",
      "months-ago": "{months} months ago",
      "years-ago": "{years} years ago",
      "in-minutes": "in {minutes} minutes",
      "in-hours": "in {hours} hours",
      "in-days": "in {days} days",
      "in-weeks": "in {weeks} weeks",
      "in-months": "in {months} months",
      "in-years": "in {years} years",
      "today-at": "Today at {time}",
      "yesterday-at": "Yesterday at {time}"
    }
  },
  {
    code: "uz",
    label: "O'zbek",
    messages: {
      "app-title": "Mening ilovam",
      "welcome": "Xush kelibsiz, {name}",
      "just-now": "Hozirgina",
      "minutes-ago": "{minutes} daqiqa oldin",
      "hours-ago": "{hours} soat oldin",
      "days-ago": "{days} kun oldin",
      "weeks-ago": "{weeks} hafta oldin",
      "months-ago": "{months} oy oldin",
      "years-ago": "{years} yil oldin",
      "in-minutes": "{minutes} daqiqadan keyin",
      "in-hours": "{hours} soatdan keyin",
      "in-days": "{days} kundan keyin",
      "in-weeks": "{weeks} haftadan keyin",
      "in-months": "{months} oydan keyin",
      "in-years": "{years} yildan keyin",
      "today-at": "Bugun {time} da",
      "yesterday-at": "Kecha {time} da"
    }
  }
] as const;

export const i18n = createI18n(languages);
  • The first language is the fallback.
  • Locale is stored in a cookie named "locale" by default. Pass a second argument to change it: createI18n(languages, "my-locale").
  • Keep the same message keys across languages.

SvelteKit setup

Pass request cookies so SSR uses the user’s saved locale:

src/routes/+layout.server.ts

export function load({ cookies }) {
  return { cookies: cookies.getAll() };
}

src/routes/+layout.svelte

<script lang="ts">
  import { i18n } from "$lib/i18n";

  let { data } = $props();
  i18n.init(() => data.cookies);
</script>

{@render children()}

Call i18n.init() (with or without cookies) before any child uses getTranslations or getFormat. Without cookies, it still sets up context and uses the browser cookie or the fallback language.

Translating text

Prefer the instance methods — they work anywhere (components, <script module>, utils):

import { i18n } from "$lib/i18n";

i18n.t("app-title");
i18n.t("welcome", { name: "Jane" });
i18n.format(new Date());
i18n.format(createdAt, { preset: "relative" });
<script lang="ts">
  import { i18n } from "$lib/i18n";
</script>

<h1>{i18n.t("app-title")}</h1>
<p>{i18n.t("welcome", { name: "Jane" })}</p>

<button onclick={() => (i18n.locale = "en")}>English</button>
<button onclick={() => (i18n.locale = "uz")}>O'zbek</button>

In components you can still use context helpers after i18n.init(...):

<script lang="ts">
  import { getTranslations, getFormat } from "@sveltebase/i18n";

  const t = getTranslations();
  const format = getFormat();
</script>

Those must run during component initialization — not in <script module>. Use i18n.t / i18n.format there instead.

Messages support ICU placeholders via use-intl ("Welcome, {name}"{ name: "Jane" }).

Optional: typed message keys

Register your catalog so TypeScript knows valid keys:

// src/app.d.ts
import type { languages } from "$lib/i18n";

type AppMessages = (typeof languages)[number]["messages"];

declare module "use-intl/core" {
  interface AppConfig {
    Messages: AppMessages;
  }
}

Nested message objects become dot-separated keys (settings.account.title).

The i18n instance

i18n.languages;        // your language array
i18n.locale;           // get/set active locale (persisted to cookie)
i18n.currentLanguage;  // full definition of the active language
i18n.t(key, values?);  // translate (no context needed)
i18n.format(value, options?); // format dates (no context needed)
i18n.init(cookies?);   // set up context (+ optional SSR cookies)

Setting locale to an unknown code falls back to the first language.

Formatting dates

i18n.format(new Date());
i18n.format(createdAt, { withTime: true });
i18n.format(createdAt, { preset: "relative" });

Pass a Date, a millisecond timestamp, or a date string. Falsy values (undefined, "", 0) return undefined.

Presets

| Preset | What you get | | --- | --- | | default (default) | Short date; year omitted if it’s this year. withTime: true adds hour and minute. | | custom | Timeline-style: “just now”, “today at …”, weekday, then full date. | | relative | Always relative (“5 minutes ago”, “in 2 hours”). | | birthday | Full date, no time. | | month | Month only (or month + year if not this year). | | timestring | Time-only strings like "08:30:00". | | full | Full localized date; withTime: true adds time. |

format(date);                                    // default
format(date, { withTime: true });
format(date, { preset: "custom" });
format(date, { preset: "relative" });
format(birthday, { preset: "birthday" });
format(date, { preset: "month" });
format("08:30:00", { preset: "timestring" });
format(date, { preset: "full", withTime: true });

Relative and custom labels use message keys like just-now, minutes-ago, today-at, etc. Include those keys in every language if you use those presets (see the quick-start example).

License

ISC