v1.0.0

🌐 Translation System

Build multilingual applications with OnigiriJS's powerful i18n module. Support for plural forms, date/number formatting, and automatic DOM translation.

🍙 Quick Start

1

Initialize Translation Module

Load the module and configure your default locale:

// Load translation module
<script src="onigiri-translation.js"></script>

// Initialize with configuration
Onigiri.i18n.init({
    locale: 'en',
    fallbackLocale: 'en',
    autoDetect: true,
    missingTranslationWarning: true
});
2

Add Translations

Register translations for multiple languages:

// Add translations for English
Onigiri.i18n.addTranslations('en', {
    welcome: 'Welcome to OnigiriJS!',
    user: {
        profile: 'User Profile',
        settings: 'Settings'
    },
    messages: {
        one: 'You have {count} message',
        other: 'You have {count} messages'
    }
});

// Add translations for Spanish
Onigiri.i18n.addTranslations('es', {
    welcome: '¡Bienvenido a OnigiriJS!',
    user: {
        profile: 'Perfil de Usuario',
        settings: 'Configuración'
    },
    messages: {
        one: 'Tienes {count} mensaje',
        other: 'Tienes {count} mensajes'
    }
});
3

Use Translations

Translate strings in your JavaScript code:

// Simple translation
const welcome = Onigiri.t('welcome');
// "Welcome to OnigiriJS!"

// Nested keys
const profile = Onigiri.t('user.profile');
// "User Profile"

// With parameters
const greeting = Onigiri.t('hello', { name: 'Alice' });
// "Hello, Alice!"

// Plural forms
const msgCount = Onigiri.tc('messages', 5);
// "You have 5 messages"

🎯 Core Features

Basic Translation

Use the t() method for simple string translation:

// Basic usage
Onigiri.t('key')

// With specific locale
Onigiri.t('key', null, 'es')

// With parameters
Onigiri.t('greeting', { name: 'Bob', time: 'morning' })
// Translation: "Good {time}, {name}!"
// Result: "Good morning, Bob!"

Nested Translations

Organize translations with nested objects:

Onigiri.i18n.addTranslations('en', {
    nav: {
        home: 'Home',
        about: 'About Us',
        contact: {
            title: 'Contact',
            email: 'Email Us',
            phone: 'Call Us'
        }
    }
});

// Access nested translations
Onigiri.t('nav.home');                    // "Home"
Onigiri.t('nav.contact.email');           // "Email Us"

Plural Forms

Handle pluralization with the tc() method:

// Define plural translations
Onigiri.i18n.addTranslations('en', {
    items: {
        one: '{count} item',
        other: '{count} items'
    },
    apples: {
        zero: 'No apples',
        one: 'One apple',
        other: '{count} apples'
    }
});

// Use plural translation
Onigiri.tc('items', 1);      // "1 item"
Onigiri.tc('items', 5);      // "5 items"
Onigiri.tc('apples', 0);     // "No apples"
Onigiri.tc('apples', 1);     // "One apple"
Onigiri.tc('apples', 42);    // "42 apples"
🍙 Language Support: OnigiriJS includes plural rules for English, Spanish, French, German, Russian, Polish, Arabic, Japanese, Chinese, Korean, and more!

Automatic DOM Translation

Translate HTML elements using data attributes:

<!-- HTML -->
<h1 data-i18n="welcome"></h1>
<p data-i18n="user.greeting"></p>
<button data-i18n="actions.save"></button>
<input type="text" data-i18n-placeholder="form.name" />
<img data-i18n-alt="logo.description" />

<script>
// Translate all elements
Onigiri.i18n.translatePage();

// Or translate specific elements
O('[data-i18n]').translate();
</script>

🌍 Locale Management

Setting the Locale

// Set current locale
Onigiri.i18n.setLocale('es');

// Get current locale
const locale = Onigiri.i18n.getLocale();
// "es"

// Get available locales
const locales = Onigiri.i18n.getLocales();
// ["en", "es", "fr", "de"]

Locale Change Events

React to locale changes automatically:

document.addEventListener('onigiri:locale:changed', function(e) {
    console.log('Locale changed to:', e.detail.locale);
    
    // Update UI
    updateNavigationLabels();
    refreshDateFormats();
});

// When you change locale, the event fires automatically
Onigiri.i18n.setLocale('fr');
// Page automatically translates!

Bulk Translation Loading

// Add multiple locales at once
Onigiri.i18n.addMessages({
    en: {
        title: 'My App',
        logout: 'Log Out'
    },
    es: {
        title: 'Mi Aplicación',
        logout: 'Cerrar Sesión'
    },
    fr: {
        title: 'Mon Application',
        logout: 'Se Déconnecter'
    }
});

📅 Date & Number Formatting

Date Formatting

Format dates according to locale conventions:

const date = new Date('2025-12-21');

// Short format
Onigiri.i18n.formatDate(date, 'short', 'en');
// "12/21/25"

// Medium format
Onigiri.i18n.formatDate(date, 'medium', 'en');
// "Dec 21, 2025"

// Long format
Onigiri.i18n.formatDate(date, 'long', 'es');
// "21 de diciembre de 2025"

// Full format
Onigiri.i18n.formatDate(date, 'full', 'fr');
// "dimanche 21 décembre 2025"

// Time only
Onigiri.i18n.formatDate(date, 'time');
// "12:00 AM"

// Date and time
Onigiri.i18n.formatDate(date, 'datetime');
// "Dec 21, 2025, 12:00 AM"

Number Formatting

// Basic number formatting
Onigiri.i18n.formatNumber(1234567.89, {}, 'en');
// "1,234,567.89" (US format)

Onigiri.i18n.formatNumber(1234567.89, {}, 'de');
// "1.234.567,89" (German format)

// Percentage
Onigiri.i18n.formatNumber(0.42, {
    style: 'percent'
});
// "42%"

// With decimal places
Onigiri.i18n.formatNumber(42.5, {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
});
// "42.50"

Currency Formatting

// Format currency
Onigiri.i18n.formatCurrency(1234.56, 'USD', 'en');
// "$1,234.56"

Onigiri.i18n.formatCurrency(1234.56, 'EUR', 'de');
// "1.234,56 €"

Onigiri.i18n.formatCurrency(1234.56, 'JPY', 'ja');
// "¥1,235"

Onigiri.i18n.formatCurrency(1234.56, 'GBP', 'en-GB');
// "£1,234.56"

🔧 Advanced Usage

Namespaced Translations

Organize translations by namespace/module:

// Add translations with namespace
Onigiri.i18n.addTranslations('en', {
    save: 'Save',
    cancel: 'Cancel',
    delete: 'Delete'
}, 'admin');

Onigiri.i18n.addTranslations('en', {
    save: 'Save Post',
    publish: 'Publish'
}, 'blog');

// Access namespaced translations
Onigiri.t('admin.save');    // "Save"
Onigiri.t('blog.save');     // "Save Post"

Check Translation Existence

// Check if translation exists
if (Onigiri.i18n.has('user.profile')) {
    const profile = Onigiri.t('user.profile');
}

// With specific locale
if (Onigiri.i18n.has('welcome', 'es')) {
    const welcome = Onigiri.t('welcome', null, 'es');
}

Get All Translations

// Get all translations for current locale
const allTranslations = Onigiri.i18n.getTranslations();

// Get translations for specific locale
const spanishTranslations = Onigiri.i18n.getTranslations('es');

🎨 Real-World Example

<!-- HTML -->
<div id="app">
    <nav>
        <h1 data-i18n="app.title"></h1>
        <select id="language-selector">
            <option value="en">English</option>
            <option value="es">Español</option>
            <option value="fr">Français</option>
        </select>
    </nav>
    
    <main>
        <h2 data-i18n="dashboard.welcome"></h2>
        <p id="message-count"></p>
        <p id="last-login"></p>
        <button data-i18n="actions.refresh"></button>
    </main>
</div>

<script>
// Initialize translations
Onigiri.i18n.init({ locale: 'en' });

// Add English translations
Onigiri.i18n.addTranslations('en', {
    app: { title: 'My Dashboard' },
    dashboard: { 
        welcome: 'Welcome back!',
        lastLogin: 'Last login: {date}'
    },
    messages: {
        one: 'You have {count} new message',
        other: 'You have {count} new messages'
    },
    actions: { refresh: 'Refresh' }
});

// Add Spanish translations
Onigiri.i18n.addTranslations('es', {
    app: { title: 'Mi Panel' },
    dashboard: { 
        welcome: '¡Bienvenido de nuevo!',
        lastLogin: 'Último acceso: {date}'
    },
    messages: {
        one: 'Tienes {count} mensaje nuevo',
        other: 'Tienes {count} mensajes nuevos'
    },
    actions: { refresh: 'Actualizar' }
});

// Create dashboard component
const dashboard = new Onigiri.prototype.Component({
    data: {
        messageCount: 5,
        lastLogin: new Date('2025-12-21T10:30:00')
    },
    
    methods: {
        updateUI() {
            // Update message count with plural
            const msgText = Onigiri.tc('messages', this.messageCount, {
                count: this.messageCount
            });
            O('#message-count').text(msgText);
            
            // Update last login with formatted date
            const loginDate = Onigiri.i18n.formatDate(
                this.lastLogin, 
                'datetime'
            );
            const loginText = Onigiri.t('dashboard.lastLogin', {
                date: loginDate
            });
            O('#last-login').text(loginText);
        }
    },
    
    mounted() {
        // Initial translation
        Onigiri.i18n.translatePage();
        this.updateUI();
        
        // Language selector
        O('#language-selector').on('change', (e) => {
            Onigiri.i18n.setLocale(e.target.value);
        });
        
        // Auto-update on locale change
        document.addEventListener('onigiri:locale:changed', () => {
            this.updateUI();
        });
    }
});

dashboard.mount('#app');
</script>

⚙️ Configuration Options

Option Type Default Description
locale String 'en' Default locale
fallbackLocale String 'en' Fallback when translation not found
autoDetect Boolean true Auto-detect locale from browser
storageKey String 'onigiri_locale' Storage key for locale preference
missingTranslationWarning Boolean true Warn about missing translations
🍙 Pro Tip: Load translations asynchronously from JSON files to keep your main bundle small! Use Onigiri.ajax to fetch translation files on demand.

🔗 Integration Examples

Loading Translations from JSON

// Load translations from external files
async function loadTranslations(locale) {
    try {
        const response = await fetch(`/locales/${locale}.json`);
        const translations = await response.json();
        Onigiri.i18n.addTranslations(locale, translations);
        return true;
    } catch (error) {
        console.error('Failed to load translations:', error);
        return false;
    }
}

// Initialize and load
Onigiri.i18n.init({ locale: 'en' });
await loadTranslations('en');
await loadTranslations('es');

Onigiri.i18n.translatePage();

HumHub Integration

// Create multilingual HumHub module
Onigiri.humhub('myModule', {
    data: {
        items: []
    },
    
    created() {
        // Load HumHub translations
        if (typeof humhub !== 'undefined') {
            const locale = humhub.config.get('language');
            Onigiri.i18n.setLocale(locale);
        }
    },
    
    mounted() {
        Onigiri.i18n.translatePage();
        this.loadItems();
    },
    
    methods: {
        loadItems() {
            // Use translated strings
            const loading = Onigiri.t('module.loading');
            console.log(loading);
        }
    }
});

✅ Development Roadmap

Track the progress of OnigiriJS modules. Tasks are marked complete by the development team.

OnigiriJS Module Roadmap

Implementation progress of planned modules

6 / 21 completed (29%)
onigiri-state
Shared global & scoped state management
onigiri-directives
Declarative DOM bindings (o-show, o-model, etc.)
onigiri-resource
REST-style data models over AJAX
onigiri-observe
Intersection & Mutation observer helpers
onigiri-humhub-ui
Standard HumHub UI abstractions (modal, notify, confirm)
onigiri-lifecycle
Component lifecycle hooks
onigiri-guard
Debounce, throttle, single-run guards
onigiri-scroll
Scroll save/restore & helpers (PJAX-friendly)
onigiri-permission
Client-side permission awareness
onigiri-portal
DOM teleport / overlay mounting
onigiri-router
Micro router (non-SPA, PJAX-first)
onigiri-sanitize
HTML & input sanitization
onigiri-shortcut
Keyboard shortcut manager
onigiri-queue
Sequential async task runner
onigiri-gesture
Touch & swipe helpers
onigiri-devtools
Debugging & inspection helpers
onigiri-plugin
Plugin registration system
onigiri-time
Relative time & timezone utilities
onigiri-emojis
Emoji Picker and Manager
onigiri-tasks
Task Management
onigiri-polls
Polls creation and management
Note: Task completion is managed by the OnigiriJS development team.