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

v0.4.4

Published

Simple i18n utilities for Svelte 5 apps.

Readme

@sveltebase/i18n

Simple i18n utilities for Svelte 5 apps.

@sveltebase/i18n gives you a small API for:

  • defining your supported languages
  • storing the active locale
  • reading translations in components
  • formatting dates and times for the current locale

It is designed to stay lightweight and work nicely with Svelte 5 runes.

Install

Install the package with Bun:

bun add @sveltebase/i18n

What it exports

  • createI18n
  • getTranslations
  • getFormat

Quick start

Create a shared i18n module:

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‘zbekcha",
    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, "locale");

Then initialize it before using translations or formatters.

In SvelteKit, the recommended quick start is to load all cookies in +layout.server.ts, pass them to +layout.svelte, and initialize i18n there. That lets the package restore the saved locale before your UI reads translations, so the correct language loads right away instead of first rendering with the fallback locale and switching later.

In +layout.server.ts:

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

Then in +layout.svelte:

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

  let { data } = $props();

  i18n.init(() => data.cookies);
</script>

Basic usage in a Svelte component

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

  const t = getTranslations();
  const format = getFormat();

  function switchLocale(locale: string) {
    i18n.locale = locale;
  }
</script>

<h1>{t("app-title")}</h1>
<p>{t("welcome", { name: "Jane" })}</p>
<p>{format(new Date(), { preset: "full", withTime: true })}</p>

<button onclick={() => switchLocale("en")}>English</button>
<button onclick={() => switchLocale("uz")}>O‘zbekcha</button>

Creating your language list

Each language should have:

  • code: locale code
  • label: readable language name
  • messages: translation dictionary

Example:

const languages = [
  {
    code: "en",
    label: "English",
    messages: {
      "app-title": "My app",
      "nav.home": "Home",
      "nav.settings": "Settings"
    }
  },
  {
    code: "uz",
    label: "O‘zbekcha",
    messages: {
      "app-title": "Mening ilovam",
      "nav.home": "Bosh sahifa",
      "nav.settings": "Sozlamalar"
    }
  }
] as const;

You can also import messages from JSON or split them across files if that fits your app better.

Initialization

Call init() before using getTranslations() or getFormat().

Without cookies

If you do not have cookies available yet, you can initialize normally:

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

i18n.init();

With cookies in SvelteKit for faster first render

In SvelteKit, the recommended approach is to load all cookies in +layout.server.ts, return them from load, and then pass that data to i18n.init(() => data.cookies) in +layout.svelte.

This lets @sveltebase/i18n restore the saved locale before your UI reads translations, so the correct language is available immediately and you avoid rendering the fallback language first.

In +layout.server.ts:

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

Then in +layout.svelte:

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

  let { data } = $props();

  i18n.init(() => data.cookies);
</script>

<slot />

The function passed to i18n.init(...) should return an array of cookie objects in this shape:

type Cookie = {
  name: string;
  value: string;
};

API

createI18n(languages, localeStorageKey?)

Creates an i18n instance.

Parameters

  • languages: an array of language definitions
  • localeStorageKey?: the key used to persist the locale, defaults to "locale"

Returns

An object with:

  • languages
  • locale
  • currentLanguage
  • init(cookies?)

Example

import { createI18n } from "@sveltebase/i18n";

const languages = [
  {
    code: "en",
    label: "English",
    messages: {
      hello: "Hello"
    }
  },
  {
    code: "uz",
    label: "O‘zbekcha",
    messages: {
      hello: "Salom"
    }
  }
] as const;

const i18n = createI18n(languages, "locale");

getTranslations()

Returns a translation function for the current locale.

Example

import { getTranslations } from "@sveltebase/i18n";

const t = getTranslations();

t("hello");
t("welcome", { name: "Jane" });

getFormat()

Returns a formatter function for locale-aware display.

Example

import { getFormat } from "@sveltebase/i18n";

const format = getFormat();

format(new Date(), { preset: "full" });
format(new Date(), { preset: "custom", withTime: true });
format(Date.now() - 1000 * 60 * 5, { preset: "relative" });
format("13:45:00", { preset: "timestring" });

Locale switching

You can switch the active locale by assigning to i18n.locale:

i18n.locale = "en";

You can also read the current language object:

console.log(i18n.currentLanguage.label);

Formatting presets

getFormat() supports these presets:

  • default
  • custom
  • relative
  • birthday
  • month
  • timestring
  • full

Preset notes

  • relative always returns relative text for both past and future values. It does not fall back to an absolute date.
  • custom can still mix relative labels such as just-now or today-at with locale-aware absolute dates for older values.
  • full returns a full locale-aware date and optionally time.
  • timestring is for time-only string values such as "08:30:00".

Example

const format = getFormat();

format(new Date(), { preset: "month" });
format(new Date(), { preset: "birthday" });
format(new Date(), { preset: "full", withTime: true });
format(Date.now() - 1000 * 60 * 5, { preset: "relative" });
format("08:30:00", { preset: "timestring" });

Required locale strings for relative formatting

If you use preset: "relative", make sure every locale provides these message keys:

  • just-now
  • minutes-ago
  • hours-ago
  • days-ago
  • weeks-ago
  • months-ago
  • years-ago
  • in-minutes
  • in-hours
  • in-days
  • in-weeks
  • in-months
  • in-years

Example:

const languages = [
  {
    code: "en",
    label: "English",
    messages: {
      "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"
    }
  },
  {
    code: "uz",
    label: "O‘zbekcha",
    messages: {
      "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"
    }
  }
] as const;

Type safety

When your language array is declared with as const, locale codes are inferred automatically.

const languages = [
  {
    code: "en",
    label: "English",
    messages: { hello: "Hello" }
  },
  {
    code: "uz",
    label: "O‘zbekcha",
    messages: { hello: "Salom" }
  }
] as const;

That improves typing for values like:

  • i18n.locale
  • i18n.currentLanguage
  • language code parameters in your own functions

Notes

  • Call init() before using getTranslations() or getFormat().
  • Passing cookies into init(cookies) during the initial render helps the correct locale load faster and avoids rendering the fallback language first.
  • The first language in the array is used as the fallback locale.
  • Locale state is persisted using @sveltebase/state.
  • Date formatting includes locale-specific behavior for Uzbek.
  • This package is intended for Svelte 5 apps.

License

ISC