Blazing-fast, dependency-free i18n library for Vue 3
, React
and modern JS/TS apps
.
Uses native Intl APIs
and modern features for blazing performance, dynamic locale loading, caching
, and type-safe
keys.
- Higher speed β no unnecessary dependencies, works on pure
Intl API
. - Minimal size β lightweight and compact code.
-** TypeScript support** β
type-safe
translation keys and autocomplete. - Dynamic loading
and caching
β convenient for working with large projects. - Easy integration β React plugin and Vue 3 plugin with provide/inject and hooks
- Full support β For
plural
andformatting
β numbers, dates, currencies, units.
- Native Intl APIs:
Intl.NumberFormat
,Intl.DateTimeFormat
,Intl.PluralRules
,Intl.RelativeTimeFormat
- Language detection (
localStorage
,cookie
,browser language
) - Dynamic locale loading via ESM dynamic import
- Local caching of translation bundles in
localStorage
(7-day TTL) - Vue 3 plugin with
provide
/inject
and global$t
function - TypeScript-friendly with
type-safe
translation keys and autocompletion
npm install swift-i18n
Create a locales
folder in your src
directory:
src/
ββ locales/
β ββ en.json
β ββ ua.json
{
"common": {
"hello": "Hello!",
"items_one": "{count} item",
"items_other": "{count} items"
},
"home": {
"title": "Welcome",
"description": "This is the home page"
}
}
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { createVueI18n } from 'swift-i18n/vue-plugin';
import { SwiftI18n } from 'swift-i18n';
import { loadLocale } from './locale-loader.ts';
const app = createApp(App);
const i18n = new SwiftI18n({
defaultLang: 'en',
supportedLangs: ['en', 'uk'],
loader: loadLocale,
cacheTtlMs: 1000 * 60 * 60 * 24 * 7, // 7 days
});
app.use(createVueI18n(i18n));
app.mount('#app');
<script setup lang="ts">
import { useI18n } from 'swift-i18n/vue-plugin';
const { t, plural, changeLanguage, lang } = useI18n();
</script>
<template>
<h1>Current language: {{ lang }}</h1>
<div>{{ t('common.hello') }}</div>
<div>{{ plural('common.items', 5) }}</div>
<button @click="changeLanguage('uk')">UK</button>
<button @click="changeLanguage('en')">EN</button>
</template>
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import './index.css';
import { loadLocale } from './locale-loader.ts';
import { SwiftI18n } from 'swift-i18n';
import { createReactI18n } from 'swift-i18n/react-plugin';
const i18n = new SwiftI18n({
defaultLang: 'en',
supportedLangs: ['en', 'uk'],
loader: loadLocale,
cacheTtlMs: 1000 * 60 * 60 * 24 * 7, // 7 days
});
const I18nProvider = createReactI18n(i18n);
createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<I18nProvider>
<App />
</I18nProvider>
</React.StrictMode>
);
import React from 'react';
import { useI18n } from 'swift-i18n/react-plugin';
export default function App() {
const { i18n, lang } = useI18n();
return (
<>
<div>{i18n.t('common.hello')}</div>
<div>{i18n.plural('common.items', 3)}</div>
<button onClick={() => i18n.changeLanguage('uk')}>πΊπ¦</button>
<button onClick={() => i18n.changeLanguage('en')}>π¬π§</button>
<p>Current lang: {lang}</p>
</>
);
}
import type { LocaleBundle } from 'swift-i18n';
const localeModules = import.meta.glob('./locales/*.json');
export async function loadLocale(lang: string = 'en') {
const importer = localeModules[`./locales/${lang}.json`];
if (!importer) {
throw new Error(`Locale ${lang} not found`);
}
const module = await importer();
return (module as { default: LocaleBundle; }).default;
}
import { formatCurrency, formatDate, formatRelativeTime, formatNumber, formatUnit } from 'swift-i18n';
formatNumber(1234567.89, 'en-US'); // "1,234,567.89"
formatCurrency(1234.5, 'USD', 'en-US'); // "$1,234.50"
formatUnit(10, 'kilometer-per-hour', 'en-US'); // "10 km/h"
formatDate(new Date(), 'en-US'); // "8/11/2025"
formatRelativeTime(-2, 'day', 'en-US'); // "2 days ago"
The plural(baseKey: string, count: number, vars?: Record<string, any>)
method returns the correct plural form translation:
{
"common": {
"items_one": "{count} item",
"items_few": "{count} items",
"items_many": "{count} items",
"items_other": "{count} items"
}
}
plural('common.items', 1); // "1 item"
plural('common.items', 3); // "3 items"
Pass variables into translations via the vars object:
{
"greeting": "Hello, {name}!"
}
t('greeting', { name: 'Alice' }); // "Hello, Alice!"
plural('common.items', 5, { name: 'Alice' });
- Translations are dynamically loaded via ESM
import()
- Cached in
localStorage
for 7 days ( default ) - Automatic loading when calling
changeLanguage()
.
Add type definitions for autocompletion:
- Create
src/types/swift-i18n.d.ts
:
import 'swift-i18n';
declare module 'swift-i18n' {
// Merge interface β put YOUR key scheme here
interface Translations {
common: {
hello: string;
items_one: string;
items_other: string;
};
home: {
title: string;
description: string;
};
}
}
- Add to
tsconfig.json
:
{
"include": [
"src/types/**/*"
]
}
Welcome to contribute to swift-i18n
!
- Fork the repository.
- Create a branch with new features or fixes.
- Write tests for new features.
- Send a pull request with a detailed description.
- Sign commits according to Conventional Commits.
Contact me if you need help or ideas.