@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/i18nFor local development with npm link:
cd packages/i18n
npm run build
npm link
cd /path/to/your-app
npm link @mikkjal/i18nCore 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/devtoolscreates the development tools plugin.$t(key, params?)global template shortcut (Vue only, equivalent touseI18n().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 orlocalStoragecache entry exists, then revalidates the hash in the background. Translations update in place if the server hash changed. - In-memory cache. Repeat calls to
setLocalefor a previously-loaded locale are synchronous (no network, nolocalStorageread). - 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).
