@mantaray0/i18n
v3.0.0
Published
Internationalization support for React applications with translation management
Maintainers
Readme
@mantaray0/i18n
Internationalization support for React applications with translation management. Works with any React framework including Next.js, Remix, Gatsby, Vite, Create React App, and any other React-based application.
Features
- Lightweight: Minimal bundle size with zero runtime dependencies
- Flexible: Support for nested translation keys and variable interpolation
- HTML Support: Optional HTML parsing for rich text translations
- Type Safe: Full TypeScript support
- Dynamic Language Switching: Change languages at runtime
- Simple API: Clean and intuitive translation hook
Installation
npm install @mantaray0/i18n
# or
pnpm add @mantaray0/i18n
# or
yarn add @mantaray0/i18nWhat is this package?
When building React applications, you often need to support multiple languages. This package provides a simple and flexible way to manage translations with support for:
- Nested translation keys
- Variable interpolation
- HTML parsing
- Dynamic language switching
- TypeScript support
Usage
Basic Setup
Wrap your application with the TranslationProvider:
import { TranslationProvider, useTranslation } from '@mantaray0/i18n';
const translations = {
en: {
welcome: 'Welcome to our app!',
greeting: 'Hello, {name}!',
description: 'This is a <strong>great</strong> app.',
nested: {
key: 'This is a nested translation'
}
},
de: {
welcome: 'Willkommen in unserer App!',
greeting: 'Hallo, {name}!',
description: 'Das ist eine <strong>tolle</strong> App.',
nested: {
key: 'Das ist eine verschachtelte Übersetzung'
}
}
};
function App() {
return (
<TranslationProvider
translations={translations}
locale="en">
<YourApp />
</TranslationProvider>
);
}Using Translations
Use the useTranslation hook in any component:
import { useTranslation } from '@mantaray0/i18n';
function WelcomeComponent() {
const { t, changeLanguage } = useTranslation();
return (
<div>
<h1>{t('welcome')}</h1>
<p>{t('greeting', { name: 'John' })}</p>
<div>{t('description')}</div>
<p>{t('nested.key')}</p>
<button onClick={() => changeLanguage('de')}>Switch to German</button>
</div>
);
}API Reference
TranslationProvider
The main provider component that wraps your application and provides translation context.
Props
| Prop | Type | Required | Description |
| -------------- | --------------------- | -------- | ---------------------------------------------------------- |
| translations | Record<string, any> | ✅ | Object containing translations for all supported languages |
| locale | string | ✅ | Initial language code (e.g., 'en', 'de', 'fr') |
| reloadKey | string \| number | ❌ | Optional key to force reload translations |
| children | ReactNode | ✅ | Your application components |
Example
<TranslationProvider
translations={translations}
locale="en"
reloadKey={reloadKey} // Optional
>
{children}
</TranslationProvider>useTranslation Hook
Returns translation functions and language utilities.
Returns
| Property | Type | Description |
| ---------------- | ---------------------------------------------------------------------------- | --------------------------------------- |
| t | (key: string, variables?: Record<string, any>, parseHtml?: boolean) => any | Translation function |
| changeLanguage | (lang: string) => void | Function to change the current language |
Translation Function Parameters
| Parameter | Type | Default | Description |
| ----------- | --------------------- | ------- | -------------------------------------------------------- |
| key | string | - | Translation key (supports nested keys with dot notation) |
| variables | Record<string, any> | {} | Variables to interpolate into the translation |
| parseHtml | boolean | true | Whether to parse HTML in the translation |
Advanced Usage
Nested Translation Keys
You can organize your translations in nested objects and access them using dot notation:
const translations = {
en: {
common: {
buttons: {
save: 'Save',
cancel: 'Cancel',
delete: 'Delete'
},
messages: {
success: 'Operation completed successfully',
error: 'An error occurred'
}
}
}
};
// Usage
const { t } = useTranslation();
t('common.buttons.save'); // "Save"
t('common.messages.success'); // "Operation completed successfully"Variable Interpolation
You can include variables in your translations using curly braces:
const translations = {
en: {
greeting: 'Hello, {name}!',
items: 'You have {count} items in your cart',
welcome: 'Welcome back, {firstName} {lastName}!'
}
};
// Usage
const { t } = useTranslation();
t('greeting', { name: 'John' }); // "Hello, John!"
t('items', { count: 5 }); // "You have 5 items in your cart"
t('welcome', { firstName: 'John', lastName: 'Doe' }); // "Welcome back, John Doe!"HTML Parsing
By default, HTML in translations is automatically parsed. You can disable this behavior:
const translations = {
en: {
description: 'This is a <strong>bold</strong> text with <em>emphasis</em>.',
link: 'Click <a href="/help">here</a> for help.'
}
};
// Usage
const { t } = useTranslation();
t('description'); // Renders as HTML: This is a <strong>bold</strong> text with <em>emphasis</em>.
t('description', {}, false); // Returns raw string: "This is a <strong>bold</strong> text with <em>emphasis</em>."Dynamic Language Switching
You can change the language at runtime:
function LanguageSwitcher() {
const { changeLanguage } = useTranslation();
return (
<div>
<button onClick={() => changeLanguage('en')}>English</button>
<button onClick={() => changeLanguage('de')}>Deutsch</button>
<button onClick={() => changeLanguage('fr')}>Français</button>
</div>
);
}Controlled Reloading
Use the reloadKey prop to force a reload of translations:
function App() {
const [reloadKey, setReloadKey] = useState(0);
const handleReloadTranslations = () => {
setReloadKey((prev) => prev + 1);
};
return (
<TranslationProvider
translations={translations}
locale="en"
reloadKey={reloadKey}>
<YourApp />
<button onClick={handleReloadTranslations}>Reload Translations</button>
</TranslationProvider>
);
}Framework Integration
This package works with any React framework. Here are examples for popular frameworks:
Next.js
App Router (Next.js 13+)
For Next.js 13+ with the app directory:
// app/layout.tsx
'use client';
import { TranslationProvider } from '@mantaray0/i18n';
export default function RootLayout({
children
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
<TranslationProvider
translations={translations}
locale="en">
{children}
</TranslationProvider>
</body>
</html>
);
}Pages Router
For traditional Next.js pages:
// pages/_app.tsx
import { TranslationProvider } from '@mantaray0/i18n';
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return (
<TranslationProvider
translations={translations}
locale="en">
<Component {...pageProps} />
</TranslationProvider>
);
}Remix
// app/root.tsx
import { TranslationProvider } from '@mantaray0/i18n';
export default function App() {
return (
<html>
<body>
<TranslationProvider
translations={translations}
locale="en">
<Outlet />
</TranslationProvider>
</body>
</html>
);
}Vite / Create React App
// src/main.tsx or src/index.tsx
import { TranslationProvider } from '@mantaray0/i18n';
import React from 'react';
import ReactDOM from 'react-dom/client';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<TranslationProvider
translations={translations}
locale="en">
<App />
</TranslationProvider>
</React.StrictMode>
);Gatsby
// gatsby-browser.js or gatsby-ssr.js
import { TranslationProvider } from '@mantaray0/i18n';
import React from 'react';
export const wrapRootElement = ({ element }) => (
<TranslationProvider
translations={translations}
locale="en">
{element}
</TranslationProvider>
);Any React Application
Since this package is framework-agnostic, you can use it anywhere React components are used:
import { TranslationProvider } from '@mantaray0/i18n';
function App() {
return (
<TranslationProvider
translations={translations}
locale="en">
<YourApp />
</TranslationProvider>
);
}TypeScript Support
Full TypeScript support is included. You can type your translations for better development experience:
interface Translations {
en: {
welcome: string;
greeting: string;
nested: {
key: string;
};
};
de: {
welcome: string;
greeting: string;
nested: {
key: string;
};
};
}
const translations: Translations = {
en: {
welcome: 'Welcome!',
greeting: 'Hello, {name}!',
nested: {
key: 'Nested translation'
}
},
de: {
welcome: 'Willkommen!',
greeting: 'Hallo, {name}!',
nested: {
key: 'Verschachtelte Übersetzung'
}
}
};Best Practices
1. Organize Your Translations
Keep your translations well-organized and use consistent naming conventions:
const translations = {
en: {
common: {
buttons: {
/* button texts */
},
messages: {
/* status messages */
},
errors: {
/* error messages */
}
},
pages: {
home: {
/* home page texts */
},
about: {
/* about page texts */
}
}
}
};2. Use Meaningful Keys
Choose descriptive and consistent translation keys:
// Good
t('common.buttons.save');
t('pages.home.welcome.title');
// Avoid
t('btn1');
t('text1');3. Missing Translation Handling
The hook automatically handles missing translations by:
- Returning
[key]as a fallback when a translation is missing - Logging a warning in development (localhost) to help identify missing translations
- Providing clear visual feedback in the UI
const { t } = useTranslation();
// If 'welcome.message' is missing, it will return '[welcome.message]'
// and log a warning in development
t('welcome.message'); // Returns '[welcome.message]' if missing4. Performance Considerations
- Keep your translation objects as small as possible
- Consider code-splitting translations by route or feature
- Use the
reloadKeyprop sparingly
Migration Guide
Migrating from @beluga-labs/i18n or beluga-i18n
This package was previously published as beluga-i18n (v1.x) and @beluga-labs/i18n (v2.x). It is now available as @mantaray0/i18n.
# Remove old package
npm uninstall @beluga-labs/i18n # or beluga-i18n
# Install new package
npm install @mantaray0/i18nUpdate all imports:
// Before
import { TranslationProvider, useTranslation } from '@beluga-labs/i18n'; // or 'beluga-i18n'
// After
import { TranslationProvider, useTranslation } from '@mantaray0/i18n';Migrating from v1.x to v2.x
Version 2.0.0 introduced several breaking changes:
Component Rename
The main provider component was renamed from TranslationsProvider (plural) to TranslationProvider (singular).
// Before
<TranslationsProvider translations={translations} locale="en">
// After
<TranslationProvider translations={translations} locale="en">Context and Type Names
All related types and context names were updated to use singular form:
TranslationsContext→TranslationContextTranslationsContextProps→TranslationContextPropsTranslationsProviderProps→TranslationProviderProps
Summary of Changes
| Item | v1.x | v2.x |
| ------------------ | ---------------------- | --------------------- |
| Package name | beluga-i18n | @mantaray0/i18n |
| Provider component | TranslationsProvider | TranslationProvider |
| Context | TranslationsContext | TranslationContext |
| Build system | tsup | rollup |
Migration Checklist
- [ ] Update package name in
package.jsonto@mantaray0/i18n - [ ] Update all imports to
@mantaray0/i18n - [ ] Rename
TranslationsProvidertoTranslationProviderin all files - [ ] Update any direct usage of context or types
- [ ] Test your application thoroughly
Contributing
We welcome contributions! Please see our contributing guidelines for more details.
License
MIT License - see LICENSE file for details.
