smokesignal API Reference#
Template Rendering System#
TemplateRenderer#
The TemplateRenderer is the core component of smokesignal's unified template rendering system. It provides automatic context enrichment with i18n, HTMX, and gender data.
Basic Usage#
use smokesignal::http::template_renderer::TemplateRenderer;
use smokesignal::http::macros::create_renderer;
// Create renderer with all context
let renderer = TemplateRenderer::new(
template_engine,
i18n_context,
language,
is_htmx
).with_gender_context(gender_context);
// Render template
let html = renderer.render("template_name", &context)?;
Constructor Methods#
new()#
pub fn new(
template_engine: &'a Environment<'a>,
i18n_context: &'a I18nTemplateContext,
language: Language,
is_htmx: bool,
) -> Self
Creates a new TemplateRenderer with basic context.
Parameters:
template_engine: minijinja Environment for template renderingi18n_context: I18n context for translation supportlanguage: Current user language (Language wrapper)is_htmx: Whether this is an HTMX request
with_gender_context()#
pub fn with_gender_context(self, gender_context: Option<&'a GenderContext>) -> Self
Adds gender context for personalized content.
Parameters:
gender_context: Optional gender context for gendered translations
Rendering Methods#
render()#
pub fn render(&self, template_name: &str, context: &impl Serialize) -> Result<String, TemplateError>
Renders a template with automatic context enrichment.
Parameters:
template_name: Name of template (without extension)context: Template context data
Returns: Rendered HTML string or error
render_error()#
pub fn render_error(&self, template_name: &str, context: &impl Serialize, error_context: Value) -> Result<String, TemplateError>
Renders error templates with merged context.
Parameters:
template_name: Error template namecontext: Base template contexterror_context: Additional error-specific context
Context Enrichment#
The TemplateRenderer automatically adds the following to all template contexts:
// Base context automatically added
{
"locale": "en-us", // Current language
"is_htmx": false, // HTMX request detection
"gender": "neutral", // User gender preference
"tr": TranslationFunction, // Translation function
"current_locale": LocaleFunction, // Current locale function
"has_locale": HasLocaleFunction, // Locale availability check
}
Template Selection#
Templates are automatically selected based on:
- Language:
template.{locale}.html - Request Type:
.partial.htmlfor HTMX requests.bare.htmlfor bare requests.htmlfor full page requests
- Fallback: Falls back to English if locale template missing
Template Naming Convention#
templates/
├── home.en-us.html # Full English template
├── home.en-us.partial.html # HTMX partial
├── home.en-us.bare.html # Bare template (no layout)
├── home.fr-ca.html # Full French template
├── home.fr-ca.partial.html # HTMX partial (French)
└── error.en-us.html # Error template
Macros#
create_renderer!#
create_renderer!(template_engine, i18n_context, language, is_htmx, gender_context)
Convenience macro for creating TemplateRenderer instances.
contextual_error!#
contextual_error!(renderer, "error_template", error_context)
Renders error templates with context preservation.
I18n Integration#
I18nTemplateContext#
Provides dynamic locale support for templates.
use smokesignal::i18n::I18nTemplateContext;
// Create context
let i18n_context = I18nTemplateContext::new(loader);
// Use in templates via TemplateRenderer
let renderer = TemplateRenderer::new(engine, &i18n_context, language, is_htmx);
Translation Functions#
Templates have access to several i18n functions:
tr(key, args)#
<!-- Basic translation -->
{{ tr("welcome-message") }}
<!-- Translation with arguments -->
{{ tr("user-greeting", {"name": user.name}) }}
<!-- Gender-aware translation (French) -->
{{ tr("welcome-user", {"name": user.name, "gender": user.gender}) }}
current_locale()#
<!-- Get current locale -->
<html lang="{{ current_locale() }}">
has_locale(locale)#
<!-- Check if locale is available -->
{% if has_locale("fr-ca") %}
<a href="/fr-ca/">Français</a>
{% endif %}
Language and Locale Management#
Language Wrapper#
The Language type wraps LanguageIdentifier for consistent handling:
use smokesignal::i18n::Language;
// Create from identifier
let language = Language(langid!("en-US"));
// Access identifier
let id = language.0;
Supported Languages#
use smokesignal::i18n::SUPPORTED_LANGUAGES;
// Available languages
const SUPPORTED_LANGUAGES: &[&str] = &["en-us", "fr-ca"];
Language Detection#
use smokesignal::http::middleware_i18n::{
detect_language_from_headers,
detect_language_from_cookie,
language_matches_any
};
// Detect from Accept-Language header
let language = detect_language_from_headers(&headers)?;
// Detect from cookie
let language = detect_language_from_cookie(&cookie_value)?;
// Check if language is supported
let is_supported = language_matches_any(&language);
Error Handling#
TemplateError#
use smokesignal::http::template_renderer::TemplateError;
pub enum TemplateError {
RenderError(minijinja::Error),
ContextError(String),
}
Error Context#
Error templates receive merged context:
// Base context + error context
{
"error_message": "Translation key failed",
"error_code": "TEMPLATE_001",
"debug_info": {...},
// ... plus all base template context
}
HTMX Integration#
HTMX Detection#
use smokesignal::http::middleware_i18n::{HX_REQUEST, HX_TRIGGER};
// Check headers
let is_htmx = headers.get(HX_REQUEST).is_some();
let trigger = headers.get(HX_TRIGGER);
Partial Rendering#
HTMX requests automatically use .partial.html templates:
// Automatically selects:
// - home.en-us.partial.html for HTMX
// - home.en-us.html for full requests
let html = renderer.render("home", &context)?;
Gender Context#
GenderContext#
use smokesignal::i18n::gender::{Gender, GenderContext};
// Create gender context
let gender_context = GenderContext {
user_gender: Some(Gender::Female),
target_gender: None,
};
// Use in renderer
let renderer = renderer.with_gender_context(Some(&gender_context));
Gender Values#
pub enum Gender {
Male, // "male"
Female, // "female"
Neutral, // "neutral"
}
Gender values are automatically available in templates as strings.
Performance Considerations#
Compile-Time Optimizations#
- Static Translation Loading: All translations compiled into binary
- Template Validation: Templates validated at compile time
- Zero Runtime I/O: No file system access for translations
Runtime Optimizations#
- HTMX Header Caching: Constants for faster header parsing
- Early Exit Language Detection: Optimized language matching
- Context Reuse: Efficient context composition
Memory Usage#
- Shared References: Template engines and i18n contexts are shared
- Strategic Cloning: Only clone when necessary for API compatibility
- Minimal Allocations: Efficient string handling in translations
Migration Guide#
From Old System#
The new system is backwards compatible, but for optimal performance:
-
Replace direct template calls:
// Old template_engine.render("template", &context)?; // New let renderer = create_renderer!(engine, i18n, lang, htmx, gender); renderer.render("template", &context)?; -
Use unified error handling:
// Old if let Err(e) = result { return render_error_template(&e); } // New contextual_error!(renderer, "error_template", error_context) -
Leverage automatic context:
// Old let mut context = minijinja::context! { ... }; context.insert("locale", &locale); context.insert("is_htmx", is_htmx); // New - automatic renderer.render("template", &base_context)?;
Best Practices#
- Use create_renderer! macro for concise renderer creation
- Leverage automatic context instead of manual context building
- Use contextual_error! for consistent error handling
- Test with multiple locales to ensure fallback behavior
- Validate gender variants for French Canadian content
Testing#
Unit Tests#
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_template_rendering() {
let renderer = create_test_renderer();
let html = renderer.render("test", &context!{}).unwrap();
assert!(html.contains("expected content"));
}
}
Integration Tests#
# Test entire i18n system
cargo test i18n
# Test template rendering
cargo test template_renderer
# Test specific language
cargo test i18n -- fr_ca