Phase 2 i18n Template Integration Guide#
This document explains how to integrate the newly completed Phase 2 i18n template functions into the Smokesignal application.
✅ Completed Features#
Phase 2 implementation provides the following MiniJinja template functions:
Core Translation Functions#
-
t(key, **args)- Main translation function{{ t('welcome') }} {{ t('hello-user', name='Alice') }} -
tl(locale, key, **args)- Translation with explicit locale{{ tl('es-ES', 'welcome') }} {{ tl('fr-FR', 'hello-user', name='Bob') }} -
plural(count, key, **args)- Pluralization helper{{ plural(1, 'item-count', item='book') }} {{ plural(5, 'item-count', item='books') }}
Utility Functions#
-
current_locale()- Get current localeCurrent language: {{ current_locale() }} -
has_locale(locale)- Check locale availability{% if has_locale('es-ES') %} <a href="/es">Español</a> {% endif %} -
format_number(number, style?)- Number formatting{{ format_number(1234.56) }} {{ format_number(total, 'currency') }} -
format_date(date, format?)- Date formatting (placeholder){{ format_date(event.date, 'short') }}
🔧 Integration Instructions#
Step 1: Update Template Environment Setup#
Modify the template environment builders in src/http/templates.rs:
use crate::i18n::template_helpers::{register_i18n_functions, I18nTemplateContext};
// In reload_env module:
pub fn build_env(http_external: &str, version: &str, i18n_context: I18nTemplateContext) -> AutoReloader {
// ... existing code ...
AutoReloader::new(move |notifier| {
let mut env = Environment::new();
// ... existing setup ...
// Register i18n functions
register_i18n_functions(&mut env, i18n_context.clone());
Ok(env)
})
}
// In embed_env module:
pub fn build_env(http_external: String, version: String, i18n_context: I18nTemplateContext) -> Environment<'static> {
let mut env = Environment::new();
// ... existing setup ...
// Register i18n functions
register_i18n_functions(&mut env, i18n_context);
env
}
Step 2: Create I18nTemplateContext in Application Setup#
In your application setup (likely in main.rs or wherever templates are initialized):
use std::sync::Arc;
use unic_langid::LanguageIdentifier;
use crate::i18n::{create_supported_languages, Locales};
use crate::i18n::template_helpers::I18nTemplateContext;
// Initialize i18n system
let languages = create_supported_languages();
let locales = Arc::new(Locales::new(languages.clone()));
// Create template context
let i18n_context = I18nTemplateContext::new(
locales,
LanguageIdentifier::from_str("en-US").unwrap(), // Current locale (from request)
LanguageIdentifier::from_str("en-US").unwrap(), // Fallback locale
);
// Pass to template environment builders
let template_env = build_env(http_external, version, i18n_context);
Step 3: Request-Level Locale Context#
For per-request locale handling, you'll need to create the I18nTemplateContext based on the user's locale preference:
// In your request handlers
fn get_user_locale(request: &Request) -> LanguageIdentifier {
// Extract from Accept-Language header, user settings, etc.
// Fallback to default
LanguageIdentifier::from_str("en-US").unwrap()
}
// Create context per request
let user_locale = get_user_locale(&request);
let i18n_context = I18nTemplateContext::new(
locales.clone(),
user_locale,
LanguageIdentifier::from_str("en-US").unwrap(),
);
📝 Template Migration Examples#
Before (Hardcoded Strings)#
<h1>Welcome to Smokesignal</h1>
<p>You have 5 new messages</p>
After (i18n Functions)#
<h1>{{ t('welcome-title') }}</h1>
<p>{{ plural(message_count, 'new-messages') }}</p>
Conditional Locale Content#
{% if has_locale('es-ES') %}
<a href="/set-locale/es-ES">Español</a>
{% endif %}
<p>{{ t('current-language') }}: {{ current_locale() }}</p>
Number and Date Formatting#
<span class="price">{{ format_number(price, 'currency') }}</span>
<time>{{ format_date(event.date, 'medium') }}</time>
🧪 Testing#
The template functions include comprehensive tests in src/i18n/template_helpers.rs. Run tests with:
cargo test i18n::template_helpers
Example test patterns:
- Function registration verification
- Locale detection and switching
- Argument passing and conversion
- Error handling for missing translations
📋 Next Steps (Phase 3)#
- Gender-aware translations - Add support for gendered message variants
- ICU message formatting - Enhanced pluralization and number formatting
- Real-time locale switching - Dynamic template re-rendering
- Translation management - Admin interface for managing translations
- Performance optimization - Caching and lazy loading of translations
🔍 Implementation Details#
Architecture#
- Template Functions: Registered with MiniJinja environment
- Context Management: Per-request locale handling via I18nTemplateContext
- Value Conversion: Automatic conversion between MiniJinja and Fluent types
- Error Handling: Graceful fallbacks for missing translations
- Type Safety: Full Rust type safety with proper error propagation
Key Files#
src/i18n/template_helpers.rs- Template function implementationssrc/i18n/mod.rs- Core i18n module with enhanced APIssrc/i18n/errors.rs- Extended error handlingexamples/i18n_template_example.rs- Usage examples