
Security News
New React Server Components Vulnerabilities: DoS and Source Code Exposure
New DoS and source code exposure bugs in React Server Components and Next.js: what’s affected and how to update safely.
swift-i18n-vue
Advanced tools
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, and type-safe keys.
Intl API.type-safe translation keys and autocomplete.React plugin and Vue 3 plugin with provide/inject and hooksplural and formatting — numbers, dates, currencies, units.Intl.NumberFormat, Intl.DateTimeFormat, Intl.PluralRules, Intl.RelativeTimeFormatlocalStorage, cookie, browser language)ESM dynamic importprovide/inject and global $t functiontype-safe translation keys and autocompletionnpm install swift-i18n
Create a locales folder in your src directory:
src/
├─ locales/
│ ├─ en.json
│ └─ uk.json
en.json:{
"common": {
"hello": "Hello!",
"items_one": "{count} item",
"items_other": "{count} items"
},
"home": {
"title": "Welcome",
"description": "This is the home page"
}
}
Vue 3 Integration with Viteimport { createApp } from 'vue';
import App from './App.vue';
import { createSwiftI18n } from 'swift-i18n/vue-plugin';
const app = createApp(App);
const i18n = await createSwiftI18n({
defaultLang: 'en',
supportedLangs: ['en', 'uk'],
loader: async (lang) => {
const module = await import(`./locales/${lang}.json`)
return module.default
}
});
app.use(i18n);
app.mount('#app');
<script setup>)<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>
React Integrationimport React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App.tsx';
import { createSwiftI18n } from 'swift-i18n/react-plugin';
async function bootstrap() {
const I18nProvider = await createSwiftI18n({
defaultLang: 'en',
supportedLangs: ['en', 'uk'],
loader: async (lang) => {
const module = await import(`./locales/${lang}.json`)
return module.default
}
});
createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<I18nProvider>
<App />
</I18nProvider>
</React.StrictMode>
)
}
bootstrap()
import React from 'react';
import { useI18n } from 'swift-i18n/react-plugin';
export default function App() {
const { t, lang, changeLanguage, plural } = useI18n();
return (
<>
<div>{t('common.hello')}</div>
<div>{plural('common.items', 3)}</div>
<button onClick={() => changeLanguage('uk')}>🇺🇦</button>
<button onClick={() => changeLanguage('en')}>🇬🇧</button>
<p>Current lang: {lang}</p>
</>
);
}
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:
JSON structure:{
"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' });
fallbackLang: 'en' to choose which language to use when your preferred language lacks a translation.
Sometimes some items will not be translated into some languages. In this example, the item hello is available in English but not Japanese:
{
"en": {
"hello": "Hello, world!"
},
"ja": {
}
}
If you want to use (say) en items when an item is not available in your desired locale, set the fallbackLang option in the createSwiftI18n:
const i18n = await createSwiftI18n({
defaultLang: 'ja',
fallbackLang: 'en',
loader: async (lang) => {
const module = await import(`./locales/${lang}.json`)
return module.default
}
});
If there’s a locale messages key that will always have the same concrete text as another one you can just link to it.
To link to another locale messages key, all you have to do is to prefix its contents with an @:key sign followed by the full name of the locale messages key including the namespace you want to link to.
{
"en": {
"message": {
"the_world": "the world",
"dio": "DIO:",
"linked": "@:message.dio @:message.the_world !!!!"
}
}
}
It’s en locale that has hierarchical structure in the object.
The message.the_world has the_world and message.dio. The message.linked has @:message.dio @:message.dio @:message.the_world !!!!, and it’s linked to the locale messages key with message.dio and message.the_world.
$t() or t() in a template:<p>{{ $t('message.linked') }}</p>
The first argument is message.linked as the locale messages key as a parameter to t.
<p>DIO: the world !!!!</p>
To help mitigate XSS risks when using HTML messages, Vue I18n provides escape parameter options. When enabled, this option escapes interpolation parameters and sanitizes the final translated HTML.
// enable `escapeParameter` globally
const i18n = createI18n({
locale: 'en',
escapeParameter: true,
})
// or enable it per translation
t('message.welcome', { name }, { escapeParameter: true })
When the escape parameter option is enabled:
<, >, ", ', &, /, =) in interpolation parameters are escapedonclick, onerror, etc.) are neutralizedconst input = '<img src=x onerror=alert(1)>'
// Without escape parameter (DANGEROUS):
$t('message.hello', { name: input })
// Result: Hello <strong><img src=x onerror=alert(1)></strong>!
// With escape parameter (SAFE):
$t('message.hello', { name: input }, { escapeParameter: true })
// Result: Hello <strong><img src=x onerror=alert(1)></strong>!
import()changeLanguage().Type-safe TranslationsAdd type definitions for autocompletion:
src/types/swift-i18n.d.ts:[Manual schema definition]
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;
};
}
}
[Derive schema directly from a JSON locale file]
Alternatively, you can generate the type definition automatically from an existing locale (e.g. en.json).
This approach ensures the types always stay in sync with your translation files.
import 'swift-i18n';
import en from '../locales/en.json'
type MessageSchema = typeof en;
declare module 'swift-i18n' {
interface Translations extends MessageSchema {};
}
[!TIP] Use the manual schema if you want strict control.
Use the derived schema if you prefer automatic synchronization.
tsconfig.json:{
"include": [
"src/types/**/*"
]
}
[!TIP] Supported Versions 1.3+
If you want to use a message format like ICU Message Format, you can use a custom format by implementing the message compiler yourself.
[!WARNING] This topic requires understanding Swift I18n message format compilation and how formats are resolved.
[!CAUTION] The feature is experimental. It may receive breaking changes or be removed in the future.
You can make a message compiler by implementing functions with the following interfaces.
The following is a TypeScript type definition:
export type MessageCompiler = (
message: string | unknown,
ctx: {
locale: string;
key: string;
onError?: (err: CompileError) => void;
}
) => MessageFunction;
The following is an example of a message compiler implementation that uses intl-messageformat to support the ICU Message format.
import IntlMessageFormat from "intl-messageformat";
import type { MessageCompiler, CompileError, MessageContext } from "swift-i18n";
export const messageCompiler: MessageCompiler = (
message,
{ locale, key, onError }
) => {
if (typeof message === "string") {
/**
* You can tune your message compiler performance more with your cache strategy or also memoization at here
*/
const formatter = new IntlMessageFormat(message, locale);
return (ctx: MessageContext) => {
return formatter.format(ctx.values);
};
} else {
/**
* for AST.
* If you would like to support it,
/**
* You need to transform locale messages such as `json`, `yaml`, etc. with the bundle plugin.
*/
if (onError) {
onError(
new Error("AST format for messages is not supported") as CompileError
);
}
return () => key;
}
};
After implementing message compiler, set the messageCompiler option of createSwiftI18n as follows, and you can use your message format for the messages option:
import { createSwiftI18n } from "swift-i18n";
import { messageCompiler } from "./compilation";
const i18n = createSwiftI18n({
locale: "en",
messageCompiler,
});
// the below your something to do ...
// ...
Example in the translation file:
{
"common": {
"hello": "Hello {name}, you have {count, plural, one {# message} other {# messages}}"
}
}
Example of use and substitution in a template:
<h1>{{ t('common.Hello', { name: "John", count: 5 }) }}</h1>
Result obtained:
Hello John, you have 5 messages
[!NOTE] You can get the code for the tutorial below on examples/message-format.
swift-i18n supports the runtime key warnings mechanism, which helps find problems with translation keys during development.
This allows you to quickly detect errors in localization keys that TypeScript cannot check statically.
console.warn if one of the following occurs during the call to t():By default, warnOnMissing is enabled. To disable it, pass warnOnMissing: false to the swift-i18n configuration.
Welcome to contribute to swift-i18n!
Contact me if you need help or ideas.
FAQs
Fast & Lightweight swift-i18n Library
The npm package swift-i18n-vue receives a total of 0 weekly downloads. As such, swift-i18n-vue popularity was classified as not popular.
We found that swift-i18n-vue demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
New DoS and source code exposure bugs in React Server Components and Next.js: what’s affected and how to update safely.

Security News
Socket CEO Feross Aboukhadijeh joins Software Engineering Daily to discuss modern software supply chain attacks and rising AI-driven security risks.

Security News
GitHub has revoked npm classic tokens for publishing; maintainers must migrate, but OpenJS warns OIDC trusted publishing still has risky gaps for critical projects.