Now.js Framework Documentation
I18nManager - Internationalization System
I18nManager - Internationalization System
Documentation for I18nManager, a multi-language (Internationalization/Localization) management system.
📋 Table of Contents
- Overview
- Installation and Import
- Basic Usage
- Translation Files
- HTML Integration
- Dynamic Translation
- Parameter Interpolation
- Locale Management
- Configuration
- Usage Examples
- API Reference
- Best Practices
Overview
I18nManager is a multi-language management system that helps applications support multiple languages easily.
Key Features
- ✅ Multiple Locales: Support for multiple languages
- ✅ Auto Detection: Automatically detect browser language
- ✅ HTML Integration: Auto-update DOM elements
- ✅ Parameter Interpolation: Insert variable values in translations
- ✅ Lazy Loading: Load translations when needed
- ✅ LocalStorage: Remember selected language
- ✅ Fallback: Use fallback when translation not found
- ✅ Nested Keys: Support nested object keys
- ✅ Event System: Emit events on language change
- ✅ No Translation Mode: Skip translation for English
Use Cases
✅ Suitable for:
- Multi-language applications
- Global web applications
- User preference localization
- Content management systems
- E-commerce platforms
- SaaS applications
Installation and Import
I18nManager loads with Now.js Framework:
// No need to import - ready to use immediately
console.log(window.I18nManager); // I18nManager object
// Access through Now.js
const i18n = Now.getManager('i18n');Dependencies
I18nManager requires these dependencies:
- ErrorManager - For error handling
- ApiService or simpleFetch - For loading translation files
- EventManager - For emitting events (optional)
Basic Usage
1. Initialization
// Basic initialization
await I18nManager.init({
enabled: true,
defaultLocale: 'en',
availableLocales: ['en', 'th', 'ja'],
storageKey: 'app_lang',
useBrowserLocale: true,
noTranslateEnglish: true
});
// Check current locale
console.log(I18nManager.getCurrentLocale()); // 'en'2. Change Language
// Change language to Thai
await I18nManager.setLocale('th');
// Change language and force update
await I18nManager.setLocale('en', true);3. Translate Text
// Translate using key
const greeting = I18nManager.translate('greeting.hello');
console.log(greeting); // 'Hello'
// Translate with parameters
const welcome = I18nManager.translate('greeting.welcome', {
name: 'John'
});
console.log(welcome); // 'Welcome John'4. Listen to Events
// Listen for locale change
Now.on('locale:changed', (data) => {
console.log('Locale changed to:', data.locale);
console.log('Forced:', data.forced);
});
// Listen for initialization
Now.on('i18n:initialized', () => {
console.log('I18n system ready');
});
// Listen for element updates
Now.on('i18n:elements:updated', (data) => {
console.log('Updated elements:', data.elementsUpdated);
console.log('Current locale:', data.locale);
});Translation Files
File Structure
Translation files must be in the translations/ folder in JSON format:
translations/
├── en.json
├── th.json
├── ja.json
└── zh.jsonTranslation File Format
// translations/en.json
{
"app": {
"name": "My Application",
"tagline": "The best app ever"
},
"greeting": {
"hello": "Hello",
"goodbye": "Goodbye",
"welcome": "Welcome {name}",
"welcomeBack": "Welcome back, {name}!"
},
"button": {
"save": "Save",
"cancel": "Cancel",
"delete": "Delete",
"confirm": "Confirm"
},
"validation": {
"required": "This field is required",
"email": "Please enter a valid email",
"minLength": "Minimum {min} characters required",
"maxLength": "Maximum {max} characters allowed"
},
"message": {
"success": "Operation completed successfully",
"error": "An error occurred",
"loading": "Loading..."
}
}// translations/th.json
{
"app": {
"name": "แอปพลิเคชันของฉัน",
"tagline": "แอปที่ดีที่สุด"
},
"greeting": {
"hello": "สวัสดี",
"goodbye": "ลาก่อน",
"welcome": "ยินดีต้อนรับ {name}",
"welcomeBack": "ยินดีต้อนรับกลับมา {name}"
},
"button": {
"save": "บันทึก",
"cancel": "ยกเลิก",
"delete": "ลบ",
"confirm": "ยืนยัน"
},
"validation": {
"required": "กรุณากรอกข้อมูลในช่องนี้",
"email": "กรุณากรอกอีเมลให้ถูกต้อง",
"minLength": "ต้องมีอย่างน้อย {min} ตัวอักษร",
"maxLength": "มีได้สูงสุด {max} ตัวอักษร"
},
"message": {
"success": "ดำเนินการสำเร็จ",
"error": "เกิดข้อผิดพลาด",
"loading": "กำลังโหลด..."
}
}Nested Keys
// Use dot notation for nested keys
I18nManager.translate('app.name'); // 'My Application'
I18nManager.translate('greeting.hello'); // 'Hello'
I18nManager.translate('validation.required'); // 'This field is required'HTML Integration
data-i18n Attribute
<!-- Use data-i18n for auto-translation -->
<h1 data-i18n="app.name">My Application</h1>
<p data-i18n="app.tagline">The best app ever</p>
<!-- Buttons -->
<button data-i18n="button.save">Save</button>
<button data-i18n="button.cancel">Cancel</button>
<button data-i18n="button.delete">Delete</button>
<!-- Input placeholders -->
<input type="text" placeholder="Email" data-i18n="form.email">
<textarea placeholder="Message" data-i18n="form.message"></textarea>Auto Translation
// When language changes, elements are auto-translated
await I18nManager.setLocale('th');
// <h1 data-i18n="app.name">แอปพลิเคชันของฉัน</h1>
// <button data-i18n="button.save">บันทึก</button>Update Specific Container
// Update only in container
const container = document.querySelector('#content');
await I18nManager.updateElements(container);
// Update entire page
await I18nManager.updateElements();Dynamic Translation
translate() Method
// Translate text in JavaScript
const greeting = I18nManager.translate('greeting.hello');
console.log(greeting); // 'Hello' or 'สวัสดี'
// Translate with fallback
const message = I18nManager.translate('unknown.key');
console.log(message); // 'unknown.key' (fallback to key)Translate with Locale
// Translate in specific locale (without changing current locale)
const enGreeting = I18nManager.translate('greeting.hello', {}, 'en');
const thGreeting = I18nManager.translate('greeting.hello', {}, 'th');
console.log(enGreeting); // 'Hello'
console.log(thGreeting); // 'สวัสดี'Get Translator Function
// Create translator function for specific locale
const t = I18nManager.getTranslator('th');
console.log(t('greeting.hello')); // 'สวัสดี'
console.log(t('button.save')); // 'บันทึก'
// With parameters
console.log(t('greeting.welcome', {name: 'John'})); // 'ยินดีต้อนรับ John'Parameter Interpolation
Basic Interpolation
// Translation with {key} placeholders
// "welcome": "Welcome {name}"
const message = I18nManager.translate('greeting.welcome', {
name: 'John'
});
console.log(message); // 'Welcome John'Multiple Parameters
// "userInfo": "User {name} has {count} items"
const info = I18nManager.translate('user.info', {
name: 'Alice',
count: 5
});
console.log(info); // 'User Alice has 5 items'Validation Messages
// "minLength": "Minimum {min} characters required"
// "maxLength": "Maximum {max} characters allowed"
const minMsg = I18nManager.translate('validation.minLength', {
min: 8
});
console.log(minMsg); // 'Minimum 8 characters required'
const maxMsg = I18nManager.translate('validation.maxLength', {
max: 100
});
console.log(maxMsg); // 'Maximum 100 characters allowed'Nested Parameter Keys
// Parameters can reference other keys
// "message": "Welcome to {app.name}"
const welcome = I18nManager.translate('greeting.message');
console.log(welcome); // 'Welcome to My Application'Locale Management
Get Current Locale
const currentLocale = I18nManager.getCurrentLocale();
console.log(currentLocale); // 'en'Get Available Translations
// Get all translations for current locale
const translations = I18nManager.getTranslations();
console.log(translations);
// {
// app: { name: 'My Application', ... },
// greeting: { hello: 'Hello', ... },
// ...
// }
// Get translations for specific locale
const thTranslations = I18nManager.getTranslations('th');Get Key Translations
// Get translations of a key across all locales
const translations = I18nManager.getKeyTranslations('greeting.hello');
console.log(translations);
// {
// en: 'Hello',
// th: 'สวัสดี',
// ja: 'こんにちは'
// }Check Translation Exists
// Check if translation exists
const exists = I18nManager.hasTranslation('greeting.hello');
console.log(exists); // true
const notExists = I18nManager.hasTranslation('unknown.key');
console.log(notExists); // false
// Check in specific locale
const hasThTranslation = I18nManager.hasTranslation('greeting.hello', 'th');Configuration
Configuration Options
const config = {
// Enable/disable i18n system
enabled: true,
// Default locale
defaultLocale: 'en',
// Supported locales
availableLocales: ['en', 'th', 'ja', 'zh'],
// localStorage key for storing selected locale
storageKey: 'app_lang',
// Use browser language as default
useBrowserLocale: true,
// Skip translation for English
// When true, English won't need to load translation file
noTranslateEnglish: true
};
await I18nManager.init(config);noTranslateEnglish Option
// When noTranslateEnglish = true
// English will return key directly without loading translation file
await I18nManager.init({
enabled: true,
defaultLocale: 'en',
availableLocales: ['en', 'th'],
noTranslateEnglish: true
});
// When locale is 'en', won't load en.json
await I18nManager.setLocale('en');
I18nManager.translate('greeting.hello'); // 'greeting.hello'
// When changed to 'th', will load th.json
await I18nManager.setLocale('th');
I18nManager.translate('greeting.hello'); // 'สวัสดี'Disable I18n
// Disable i18n system
await I18nManager.init({
enabled: false
});
// When disabled, all methods do nothing
await I18nManager.setLocale('th'); // does nothing
I18nManager.translate('key'); // returns 'key'Usage Examples
1. Multi-language Website
// Initialize i18n
await I18nManager.init({
enabled: true,
defaultLocale: 'en',
availableLocales: ['en', 'th', 'ja', 'zh'],
storageKey: 'website_lang',
useBrowserLocale: true
});
// HTML
/*
<nav>
<select id="lang-selector">
<option value="en">English</option>
<option value="th">ไทย</option>
<option value="ja">日本語</option>
<option value="zh">中文</option>
</select>
</nav>
<main>
<h1 data-i18n="page.title">Welcome</h1>
<p data-i18n="page.description">This is a multi-language website</p>
<button data-i18n="button.getStarted">Get Started</button>
</main>
*/
// Language selector
const selector = document.querySelector('#lang-selector');
selector.value = I18nManager.getCurrentLocale();
selector.addEventListener('change', async (e) => {
await I18nManager.setLocale(e.target.value);
});
// Listen for locale changes
Now.on('locale:changed', (data) => {
console.log('Language changed to:', data.locale);
// Update other UI as needed
updateUI();
});2. Form Validation with I18n
// Validation with translated messages
function validateForm(formData) {
const errors = [];
// Required field
if (!formData.email) {
errors.push(I18nManager.translate('validation.required'));
}
// Email format
if (formData.email && !isValidEmail(formData.email)) {
errors.push(I18nManager.translate('validation.email'));
}
// Min length
if (formData.password && formData.password.length < 8) {
errors.push(I18nManager.translate('validation.minLength', {
min: 8
}));
}
// Max length
if (formData.bio && formData.bio.length > 500) {
errors.push(I18nManager.translate('validation.maxLength', {
max: 500
}));
}
return errors;
}
// Usage
const formData = {
email: '',
password: '123',
bio: 'Some text...'
};
const errors = validateForm(formData);
errors.forEach(error => {
console.error(error);
});3. Dynamic Content Translation
// Translate content loaded from API
async function loadUserProfile(userId) {
const user = await fetchUser(userId);
// Translate UI
const container = document.querySelector('#profile');
container.innerHTML = `
<h2>${user.name}</h2>
<p data-i18n="profile.memberSince">Member since</p>
<p>${user.joinDate}</p>
<button data-i18n="button.edit">Edit</button>
<button data-i18n="button.save">Save</button>
`;
// Update translations
await I18nManager.updateElements(container);
}4. Notification Messages
// Create notification with translation
function showNotification(type, messageKey, params = {}) {
const message = I18nManager.translate(messageKey, params);
const notification = document.createElement('div');
notification.className = `notification notification-${type}`;
notification.textContent = message;
document.body.appendChild(notification);
setTimeout(() => notification.remove(), 3000);
}
// Usage
showNotification('success', 'message.success');
showNotification('error', 'message.error');
showNotification('info', 'user.welcomeBack', {name: 'John'});5. Shopping Cart with I18n
// E-commerce cart
class ShoppingCart {
constructor() {
this.items = [];
}
addItem(product, quantity) {
this.items.push({product, quantity});
const message = I18nManager.translate('cart.itemAdded', {
name: product.name,
quantity: quantity
});
showNotification('success', message);
}
removeItem(index) {
const item = this.items[index];
this.items.splice(index, 1);
const message = I18nManager.translate('cart.itemRemoved', {
name: item.product.name
});
showNotification('info', message);
}
getTotal() {
const total = this.items.reduce((sum, item) => {
return sum + (item.product.price * item.quantity);
}, 0);
return I18nManager.translate('cart.total', {
amount: total.toFixed(2)
});
}
render() {
const container = document.querySelector('#cart');
if (this.items.length === 0) {
container.innerHTML = `
<p data-i18n="cart.empty">Your cart is empty</p>
`;
} else {
container.innerHTML = `
<h2 data-i18n="cart.title">Shopping Cart</h2>
<ul>
${this.items.map(item => `
<li>
${item.product.name} x ${item.quantity}
<button data-i18n="button.remove">Remove</button>
</li>
`).join('')}
</ul>
<p>${this.getTotal()}</p>
<button data-i18n="button.checkout">Checkout</button>
`;
}
I18nManager.updateElements(container);
}
}6. Date and Time Localization
// Format dates by locale
function formatDate(date) {
const locale = I18nManager.getCurrentLocale();
const formatted = new Intl.DateTimeFormat(locale, {
year: 'numeric',
month: 'long',
day: 'numeric'
}).format(date);
return formatted;
}
// Relative time
function getRelativeTime(date) {
const now = new Date();
const diff = now - date;
const seconds = Math.floor(diff / 1000);
const minutes = Math.floor(seconds / 60);
const hours = Math.floor(minutes / 60);
const days = Math.floor(hours / 24);
if (days > 0) {
return I18nManager.translate('time.daysAgo', {days});
} else if (hours > 0) {
return I18nManager.translate('time.hoursAgo', {hours});
} else if (minutes > 0) {
return I18nManager.translate('time.minutesAgo', {minutes});
} else {
return I18nManager.translate('time.justNow');
}
}
// Usage
const date = new Date('2024-01-15');
console.log(formatDate(date)); // 'January 15, 2024' or '15 มกราคม 2024'
const postDate = new Date(Date.now() - 3600000); // 1 hour ago
console.log(getRelativeTime(postDate)); // '1 hour ago' or '1 ชั่วโมงที่แล้ว'7. Multi-language Modal
// Modal with i18n
class Modal {
constructor(contentKey, options = {}) {
this.contentKey = contentKey;
this.options = options;
}
show() {
const modal = document.createElement('div');
modal.className = 'modal';
modal.innerHTML = `
<div class="modal-overlay"></div>
<div class="modal-content">
<h2 data-i18n="${this.contentKey}.title">Title</h2>
<p data-i18n="${this.contentKey}.message">Message</p>
<div class="modal-actions">
<button class="btn-cancel" data-i18n="button.cancel">Cancel</button>
<button class="btn-confirm" data-i18n="button.confirm">Confirm</button>
</div>
</div>
`;
document.body.appendChild(modal);
// Translate
I18nManager.updateElements(modal);
// Events
modal.querySelector('.btn-cancel').addEventListener('click', () => {
this.close();
});
modal.querySelector('.btn-confirm').addEventListener('click', () => {
if (this.options.onConfirm) {
this.options.onConfirm();
}
this.close();
});
modal.querySelector('.modal-overlay').addEventListener('click', () => {
this.close();
});
this.modal = modal;
}
close() {
if (this.modal) {
this.modal.remove();
this.modal = null;
}
}
}
// Usage
const deleteModal = new Modal('modal.deleteConfirm', {
onConfirm: () => {
deleteItem();
}
});
deleteModal.show();8. Search with Autocomplete
// Search autocomplete with i18n
class SearchAutocomplete {
constructor(inputElement) {
this.input = inputElement;
this.results = [];
this.setupUI();
}
setupUI() {
// Placeholder
const placeholder = I18nManager.translate('search.placeholder');
this.input.setAttribute('placeholder', placeholder);
// Results container
this.container = document.createElement('div');
this.container.className = 'autocomplete-results';
this.input.parentElement.appendChild(this.container);
// Events
this.input.addEventListener('input', (e) => {
this.search(e.target.value);
});
// Update on locale change
Now.on('locale:changed', () => {
const placeholder = I18nManager.translate('search.placeholder');
this.input.setAttribute('placeholder', placeholder);
this.render();
});
}
async search(query) {
if (!query) {
this.results = [];
this.render();
return;
}
// Search API
this.results = await searchAPI(query);
this.render();
}
render() {
if (this.results.length === 0) {
this.container.innerHTML = `
<div class="no-results" data-i18n="search.noResults">
No results found
</div>
`;
} else {
this.container.innerHTML = `
<div class="results-header" data-i18n="search.resultsCount">
Found {count} results
</div>
<ul>
${this.results.map(result => `
<li data-id="${result.id}">${result.name}</li>
`).join('')}
</ul>
`;
}
I18nManager.updateElements(this.container);
}
}9. User Profile Settings
// User settings with language preference
class UserSettings {
constructor(user) {
this.user = user;
}
async saveLanguage(locale) {
// Save to database
await api.updateUser(this.user.id, {
language: locale
});
// Change language
await I18nManager.setLocale(locale);
// Show notification
const message = I18nManager.translate('settings.languageUpdated');
showNotification('success', message);
}
render() {
const container = document.querySelector('#settings');
container.innerHTML = `
<div class="settings-section">
<h3 data-i18n="settings.language">Language</h3>
<select id="language-select">
<option value="en">English</option>
<option value="th">ไทย</option>
<option value="ja">日本語</option>
</select>
</div>
<div class="settings-section">
<h3 data-i18n="settings.notifications">Notifications</h3>
<label>
<input type="checkbox" id="email-notifications">
<span data-i18n="settings.emailNotifications">Email notifications</span>
</label>
</div>
<button data-i18n="button.save">Save</button>
`;
// Translate
I18nManager.updateElements(container);
// Set current language
const select = container.querySelector('#language-select');
select.value = I18nManager.getCurrentLocale();
// Events
select.addEventListener('change', (e) => {
this.saveLanguage(e.target.value);
});
}
}10. Error Messages
// Error handling with i18n
class ErrorHandler {
static handle(error, context = {}) {
let messageKey = 'error.unknown';
let params = {};
// Map error types to translation keys
switch (error.code) {
case 'NETWORK_ERROR':
messageKey = 'error.network';
break;
case 'UNAUTHORIZED':
messageKey = 'error.unauthorized';
break;
case 'NOT_FOUND':
messageKey = 'error.notFound';
params = {resource: context.resource};
break;
case 'VALIDATION_ERROR':
messageKey = 'error.validation';
params = {field: context.field};
break;
case 'SERVER_ERROR':
messageKey = 'error.server';
break;
default:
messageKey = 'error.unknown';
}
const message = I18nManager.translate(messageKey, params);
// Show error
showErrorNotification(message);
// Log
console.error(message, error);
}
}
// Usage
try {
await api.deleteUser(userId);
} catch (error) {
ErrorHandler.handle(error, {
resource: 'user',
action: 'delete'
});
}API Reference
Configuration
{
enabled: boolean, // Enable/disable i18n system
defaultLocale: string, // Default locale
availableLocales: string[], // Supported locales
storageKey: string, // localStorage key
useBrowserLocale: boolean, // Use browser locale
noTranslateEnglish: boolean // Skip English translation
}Methods
Initialization
// Initialize i18n system
init(options?: object): Promise<I18nManager>Locale Management
// Set current locale
setLocale(locale: string, force?: boolean): Promise<void>
// Get current locale
getCurrentLocale(): stringTranslation
// Translate a key
translate(key: string, params?: object, locale?: string): string
// Get translator function
getTranslator(locale: string): (key: string, params?: object) => string
// Get translations for locale
getTranslations(locale?: string): object
// Get translations for a key across all locales
getKeyTranslations(key: string): object
// Check if translation exists
hasTranslation(key: string, locale?: string): booleanElement Updates
// Update translations in DOM
updateTranslations()
// Update specific elements
updateElements(container?: Element)Internal Methods
// Load translations from file
loadTranslations(locale: string): Promise<void>
// Get translation with fallback
getTranslation(key: string, translations: object, params?: object): string
// Get fallback translation
getFallbackTranslation(key: string, params: object): string
// Interpolate parameters
interpolate(text: string, params: object, translations?: object): string
// Load initial locale
loadInitialLocale(): Promise<void>Events
// I18n initialized
'i18n:initialized'
// Locale changed
'locale:changed' -> {
locale: string,
forced: boolean
}
// Elements updated
'i18n:elements:updated' -> {
container: Element,
elementsUpdated: number,
locale: string
}State
{
current: string | null, // Current locale
initialized: boolean, // Initialized
translations: Map, // Translation cache
disabled: boolean // System disabled
}Best Practices
1. ✅ Use Nested Keys
// ✅ Good: organized structure
{
"user": {
"profile": {
"name": "Name",
"email": "Email"
}
}
}
I18nManager.translate('user.profile.name');
// ❌ Bad: flat structure
{
"userProfileName": "Name",
"userProfileEmail": "Email"
}2. ✅ Use data-i18n for Static Content
<!-- ✅ Good: auto-translated -->
<h1 data-i18n="page.title">Welcome</h1>
<!-- ❌ Bad: manual translation required -->
<h1 id="title">Welcome</h1>
<script>
document.getElementById('title').textContent =
I18nManager.translate('page.title');
</script>3. ✅ Keep Translations in Separate Files
// ✅ Good: separate files
translations/
├── en.json
├── th.json
└── ja.json
// ❌ Bad: embedded in code
const translations = {
en: {...},
th: {...}
};4. ✅ Use Parameters for Dynamic Content
// ✅ Good: parameterized
{
"welcome": "Welcome {name}"
}
I18nManager.translate('welcome', {name: 'John'});
// ❌ Bad: string concatenation
{
"welcome": "Welcome "
}
I18nManager.translate('welcome') + name;5. ✅ Provide Fallback
// ✅ Good: use defaultLocale as fallback
await I18nManager.init({
defaultLocale: 'en',
availableLocales: ['en', 'th', 'ja']
});
// Missing translation will use key as fallback
I18nManager.translate('unknown.key'); // 'unknown.key'6. ✅ Handle Loading States
// ✅ Good: show loading
async function changeLanguage(locale) {
showLoading();
try {
await I18nManager.setLocale(locale);
} catch (error) {
showError(error);
} finally {
hideLoading();
}
}7. ✅ Use Consistent Key Naming
// ✅ Good: consistent naming
{
"button.save": "Save",
"button.cancel": "Cancel",
"button.delete": "Delete"
}
// ❌ Bad: inconsistent
{
"saveBtn": "Save",
"cancelButton": "Cancel",
"delete": "Delete"
}8. ✅ Update Elements After Dynamic Content
// ✅ Good: update after loading
async function loadContent() {
const data = await fetchData();
const container = document.querySelector('#content');
container.innerHTML = generateHTML(data);
// Update translations
await I18nManager.updateElements(container);
}9. ✅ Store User Preference
// ✅ Good: automatically stored
await I18nManager.init({
storageKey: 'app_lang' // Will remember selected language
});
// ✅ Good: sync with server
Now.on('locale:changed', async (data) => {
await api.updateUserPreference({
language: data.locale
});
});10. ✅ Test All Locales
// ✅ Good: test all languages
async function testTranslations() {
const locales = ['en', 'th', 'ja'];
for (const locale of locales) {
await I18nManager.setLocale(locale);
// Check important keys
const keys = [
'app.name',
'button.save',
'message.success'
];
keys.forEach(key => {
const translation = I18nManager.translate(key);
console.log(`${locale} - ${key}:`, translation);
});
}
}Summary
Key Features
| Feature | Supported | Notes |
|---|---|---|
| Multiple Locales | ✅ | Unlimited |
| Auto Detection | ✅ | Browser locale |
| HTML Integration | ✅ | data-i18n attribute |
| Parameter Interpolation | ✅ | {key} syntax |
| Lazy Loading | ✅ | Load when needed |
| LocalStorage | ✅ | Remember language |
| Fallback | ✅ | Use key or default locale |
| Nested Keys | ✅ | Dot notation |
| Event System | ✅ | locale:changed event |
| No Translation Mode | ✅ | noTranslateEnglish |
When to Use I18nManager
| Use Case | Use I18nManager? | Notes |
|---|---|---|
| Multi-language app | ✅ Yes | Primary use case |
| User language preference | ✅ Yes | LocalStorage + API |
| Dynamic content translation | ✅ Yes | translate() method |
| Static HTML translation | ✅ Yes | data-i18n attribute |
| Form validation messages | ✅ Yes | Parameterized messages |
| Error messages | ✅ Yes | Consistent error handling |
| Date/Time formatting | ⚠️ Partial | Use with Intl API |
| Currency formatting | ⚠️ Partial | Use with Intl API |