Skip to content

CreateWheel/mini-i18n

Repository files navigation

mini-i18n

visitors npm version npm downloads bundle JSDocs License

🌍 A lightweight internationalization (i18n) module for browser and Node.js environments, with a size of only ~2KB!

✨ Features

  • ✅ Zero dependencies, ultra-lightweight
  • 📦 Supports nested access (e.g., settings.theme.light)
  • 🔄 Supports string interpolation (Hello, {name})
  • 🌐 Dynamic language switching
  • ➕ Dynamic language addition
  • ⚡ Internal caching mechanism for better performance
  • 🧩 Built-in event system (e.g., listen to language changes)

🔧 Type Support

Automatically generates language key path types. Built-in type inference support for IDE smart hints.

📦 Installation

Using npm:

npm install mini-i18n

Using CDN:

<script src="https://cdn.jsdelivr.net/npm/mini-i18n"></script>
<!-- or -->
<script src="https://unpkg.com/mini-i18n"></script>

<script>
const i18n = new miniI18n.I18n({ .. })
</script>

🚀 Usage Example

import { I18n } from 'mini-i18n'

const languages = {
  en: {
    settings: {
      title: 'Settings',
      theme: { light: 'Light', dark: 'Dark' },
      tags: ['a', 'b'],
    },
    greeting: 'Hello, {name}!',
  },
  zh: {
    settings: {
      title: '设置',
      theme: { light: '浅色', dark: '深色' },
      tags: ['甲', '乙'],
    },
    greeting: '你好, {name}!',
  },
  // 🔁 If you plan to add new languages later (e.g., 'jp'), you can define an empty object in advance to avoid TS errors
  jp: {} // TIP: Define placeholder objects in advance
} as const // If using TypeScript, it's recommended to add `as const`

const i18n = new I18n({
  defaultLanguage: 'en',
  language: 'en',
  languages,
})

// Get translations
i18n.t('settings.title') // => "Settings"
i18n.t('settings.tags.0') // => "a"

i18n.setLanguage('zh')
i18n.t('settings.title') // => "设置"

// Using interpolation
i18n.t('greeting', { params: { name: 'Lete' } }) // => "你好, Lete!"

// Listen to language changes
i18n.on('language:changed', (payload) => {
  console.log('Language changed to:', payload.language)
})
i18n.on('language:added', (payload) => {})

// Cancel the listener
const unlistenMissingKey = i18n.on('missingKey', (payload) => {})
unlistenMissingKey()

⚙️ Configuration Options

new I18n(options)

Parameter Type Description
defaultLanguage keyof T The default language
language keyof T The current language
languages Record<string, object> The collection of language data
interpolation (optional) { prefix: string; suffix: string } Prefix and suffix for interpolation (default: {})

🧩 API

t(key: string, options?: { params?: object, defaultValue?: string })

Gets the translation content, supports nested access and interpolation.

i18n.t('settings.theme.light') // => "浅色"
i18n.t('greeting', { params: { name: 'World' } }) // => "你好, World!"
i18n.t('unknown.key', { defaultValue: 'Not found' }) // => "Not found"

setLanguage(language: keyof T)

Sets the specified language and clears the cache. Will trigger the language:changed event.

getLanguage(): keyof T

Gets the current language.

addLanguage(language: keyof T, languageData: T[keyof T])

Dynamically adds a new language package.

clearCache()

Clears the translation cache.

📣 Events

on(event: 'language:changed', listener: ({ language: keyof T }) => void): () => void

Listen for language change events.

i18n.on('language:changed', (payload) => {
  console.log(`Language changed to: ${payload.language}`)
})

once(event: 'language:changed', listener: ({ language: keyof T }) => void): () => void

Listen for a language change only once.

i18n.once('language:changed', (payload) => {
  console.log('One-time language switch:', payload.language)
})

off(event: 'language:changed', listener: ({ language: keyof T }) => void)

Remove a previously registered event listener.

function fn() {}
i18n.on('language:changed', fn)
i18n.off('language:changed', fn)

clear(event?: 'language:changed')

Clear all or specific event listeners.

i18n.clear() // Clear all listeners
i18n.clear('language:changed') // Clear only 'change' listeners

📚 EventEmitter (Optional Utility)

You can also use the built-in event system separately:

import { EventEmitter } from 'mini-i18n'

const emitter = new EventEmitter()

const listener = () => console.log('triggered')
emitter.on('custom', listener)
emitter.emit('custom') // => triggered

📄 License

MIT License © Lete114