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

@mikkjal/i18n

v0.3.1

Published

Frontend translation runtime for Lunnar projects.

Readme

@mikkjal/i18n

Frontend translation runtime for Lunnar projects.

Install

npm install @mikkjal/i18n

For local development with npm link:

cd packages/i18n
npm run build
npm link

cd /path/to/your-app
npm link @mikkjal/i18n

Core Usage

The root package is framework agnostic.

API mode

Fetches translations through the Lunnar API, which proxies to S3:

import { createI18nClient } from '@mikkjal/i18n';

const i18n = createI18nClient({
    url: 'https://your-lunnar-app.test',
    projectSlug: 'your-project',
    locale: 'en',
});

await i18n.setLocale('en');

i18n.t('welcome_message');
i18n.t('items_count', { count: 3 });

Storage mode

Fetches translations directly from S3-compatible storage (no API dependency):

import { createI18nClient } from '@mikkjal/i18n';

const i18n = createI18nClient({
    storageUrl: 'https://fsn1.your-objectstorage.com/lunnar-translate',
    projectSlug: 'your-project',
    locale: 'en',
});

await i18n.setLocale('en');

i18n.t('welcome_message');

Both modes can coexist — set storageUrl for direct S3 access with url as fallback.

Vue Usage

Use the Vue integration from @mikkjal/i18n/vue.

import type { I18nOptions } from '@mikkjal/i18n';
import { createI18n } from '@mikkjal/i18n/vue';

const options: I18nOptions = {
    storageUrl: 'https://fsn1.your-objectstorage.com/lunnar-translate',
    projectSlug: 'your-project',
    locale: 'en',
};

const i18n = createI18n(options);

app.use(i18n);
await i18n.setLocale(options.locale);

Then use it in components:

<script setup lang="ts">
import { useI18n } from '@mikkjal/i18n/vue';

const i18n = useI18n();
</script>

<template>
    <p>{{ i18n.t('welcome_message') }}</p>
</template>

The plugin also registers $t as a global property, so you can use it directly in any template without useI18n:

<template>
    <p>{{ $t('welcome_message') }}</p>
</template>

Dev tools

Install the dev tools plugin to inspect translated text in the browser during development:

import { createI18n } from '@mikkjal/i18n/vue';

const i18n = createI18n({
    url: 'https://your-lunnar-app.test',
    storageUrl: 'https://fsn1.your-objectstorage.com/lunnar-translate',
    projectSlug: 'your-project',
    locale: 'en',
});

if (import.meta.env.DEV) {
    const { devTools } = await import('@mikkjal/i18n/devtools');
    
    i18n.use(devTools());
}

When installed, the dev tools plugin adds temporary markers to $t()/i18n.t() output and installs a batched MutationObserver that converts those markers into metadata on the existing text container or translated attribute element. Hold Cmd on macOS/iOS, or Ctrl on Windows/Linux, and hover translated text to show a red overlay. Modifier-clicking an inspected translation opens that key in the project translations view with a key query parameter. The plugin requires url in the i18n options so it can open keys in Lunnar.

Keep dev tools for local development only. Text interpolation and translated attributes such as :placeholder="$t('users.index.search_placeholder')" are both supported. For zero production bundle impact, dynamically import the plugin before installing it.

For page-level providing, use provideI18n:

<script setup lang="ts">
import { onMounted } from 'vue';
import { provideI18n } from '@mikkjal/i18n/vue';

const i18n = provideI18n({
    storageUrl: 'https://fsn1.your-objectstorage.com/lunnar-translate',
    projectSlug: 'your-project',
    locale: 'en',
});

onMounted(() => {
    void i18n.setLocale('en');
});
</script>

API

  • createI18nClient(options) creates a framework-neutral client.
  • createI18n(options) creates a Vue plugin.
  • provideI18n(options) provides an i18n instance for descendant Vue components.
  • useI18n() injects the nearest Vue i18n instance.
  • i18n.use(plugin) installs an i18n plugin.
  • devTools() from @mikkjal/i18n/devtools creates the development tools plugin.
  • $t(key, params?) global template shortcut (Vue only, equivalent to useI18n().t).
  • i18n.t(key, params?) returns a translated string, or the key when missing.
  • i18n.setLocale(locale) loads translations for a locale.
  • getPluralForms(code) returns the CLDR plural categories for a locale.
  • selectPluralForm(code, n) returns the CLDR plural form (one, other, ...) for a count.

Behavior

  • Stale-while-revalidate. setLocale(locale) resolves immediately when an in-memory or localStorage cache entry exists, then revalidates the hash in the background. Translations update in place if the server hash changed.
  • In-memory cache. Repeat calls to setLocale for a previously-loaded locale are synchronous (no network, no localStorage read).
  • Plural rules. Backed by the runtime's Intl.PluralRules (CLDR-compliant) — supported in every modern browser and Node 13+. No bundled rules table.
  • ESM-only. The package ships ESM output and is tree-shakeable (sideEffects: false).