# smokesignal An event and RSVP management system based on ATproto - **Backend**: Rust with Axum web framework - **Database**: PostgreSQL with SQLx - **Cache**: Redis/Valkey for session management - **Templates**: Minijinja with fluent-templates for i18n - **Frontend**: HTMX + Bulma CSS - **Containerization**: Docker with devcontainer supportent application built with Rust, featuring modern internationalization and unified template rendering. ## Features - **Event Management**: Create, view, and manage events with full internationalization - **Advanced Filtering**: Locale-aware event filtering with translated facets and smart caching - **RSVP System**: Allow users to respond to events in their preferred language - **Internationalization**: - Complete i18n support with fluent-templates (English, French Canadian) - Automatic language detection from browser preferences - Gender-aware translations for French Canadian - Locale-specific date/time formatting and pluralization - **Modern UI**: HTMX-powered interactive interface with Bulma CSS - **Template System**: Unified template rendering with automatic i18n context enrichment - **Performance**: - Compile-time translation loading for zero runtime overhead - Locale-aware caching with intelligent cache key generation - Optimized facet calculation with pre-computed display names - **Authentication**: OAuth-based user authentication - **Real-time Updates**: Dynamic content updates with HTMX and proper language context ## Architecture ### I18n System smokesignal features a production-ready internationalization architecture built on `fluent-templates`: - **Compile-time Loading**: Translations are embedded in the binary for zero runtime overhead - **Automatic Language Detection**: Smart detection from Accept-Language headers, URL parameters, and user preferences - **Locale-aware Caching**: Intelligent cache key generation that includes locale context - **Performance Optimized**: Pre-calculated facet display names and cached translation lookups - **Fallback System**: Graceful fallback to English when translations are missing - **Gender Support**: Complete gender-aware content support for French Canadian - **HTMX Integration**: Seamless language context propagation for dynamic content updates ### Template Rendering The application features a centralized template rendering system that automatically enriches templates with: - **Internationalization**: Automatic locale detection and translation injection - **HTMX Context**: Smart detection of HTMX requests for partial rendering - **Gender Context**: Personalized content based on user gender preferences - **Error Handling**: Consistent error templates with proper context ### Technology Stack - **Backend**: Rust with Axum web framework - **Database**: PostgreSQL with SQLx - **Cache**: Redis/Valkey for session management - **Templates**: Minijinja with fluent-templates for i18n - **Frontend**: HTMX + Bulma CSS - **Containerization**: Docker with devcontainer support ## Quick Start ### Using Devcontainers (Recommended) 1. Install [Visual Studio Code](https://code.visualstudio.com/) and the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) 2. Clone this repository 3. Open in VS Code and select "Reopen in Container" 4. Run database migrations: `sqlx migrate run` 5. Start the server: `cargo run --bin smokesignal` ### Local Development Prerequisites: - Rust 1.86+ - PostgreSQL - Redis or Valkey ```bash # Install dependencies cargo build # Set up database sqlx migrate run # Run the application cargo run --bin smokesignal # Run tests cargo test ``` ## Configuration Copy `keys.example.json` to `keys.json` and configure: - Database connection strings - OAuth provider credentials - Redis/Valkey connection - External service URLs ## Internationalization ### Supported Languages - **en-us**: English (United States) - **fr-ca**: French (Canada) with gender support ### Adding Translations 1. Add `.ftl` files to `i18n/{locale}/` directories 2. Use Fluent syntax for translations 3. Test with `cargo test i18n` ### Translation Structure ``` i18n/ ├── en-us/ │ ├── common.ftl # Common UI strings │ ├── errors.ftl # Error messages │ ├── forms.ftl # Form labels and validation │ ├── actions.ftl # Button and action text │ └── ui.ftl # Interface elements └── fr-ca/ └── (same structure with French translations) ``` ## Development ### Common Commands ```bash # Build cargo build # Run tests cargo test # Run specific test suites cargo test i18n cargo test template cargo test middleware_i18n # Format and lint cargo fmt cargo clippy # Run with debug logging RUST_LOG=debug cargo run --bin smokesignal ``` ### Build Features - `embed`: Embed templates in binary (production) - `reload`: Enable template reloading (development) ```bash # Production build with embedded templates cargo build --release --no-default-features --features embed # Development build with template reloading cargo build --no-default-features --features reload ``` ## Template Development ### Template Renderer The `TemplateRenderer` provides a unified API for rendering templates with automatic context enrichment: ```rust use smokesignal::http::template_renderer::TemplateRenderer; // Create renderer with automatic context let renderer = TemplateRenderer::new(template_engine, i18n_context, language, is_htmx) .with_gender_context(gender_context); // Render template with enriched context let html = renderer.render("template_name", &context)?; ``` ### Template Macros Convenient macros for common operations: ```rust // Create renderer quickly let renderer = create_renderer!(engine, i18n, lang, htmx, gender); // Render error templates with context preservation contextual_error!(renderer, "error_template", error_context); ``` ## API Documentation ### Core Modules - `src/http/template_renderer.rs`: Unified template rendering system - `src/i18n/`: Internationalization with fluent-templates - `src/http/middleware_i18n.rs`: Language detection and context injection - `src/http/macros.rs`: Convenience macros for handlers ### I18n API ```rust use smokesignal::i18n::{get_translation, I18nTemplateContext}; // Get translation with arguments let message = get_translation(&locale, "message-key", Some(args)); // Template context for dynamic locale support let context = I18nTemplateContext::new(loader); ``` ## Contributing 1. Fork the repository 2. Create a feature branch 3. Make changes with tests 4. Run `cargo test` and `cargo clippy` 5. Submit a pull request ### Translation Contributions Translation improvements are welcome! Please ensure: - Complete coverage across all `.ftl` files - Gender variants for French Canadian - Consistent terminology and tone ## License MIT This project is licensed under the terms specified in the LICENSE file. ## Documentation ### Core Documentation - [Build Instructions](BUILD.md) - [Local Development Guide](playbooks/localdev.md) - [Release Process](playbooks/release.md) ### I18n and API Documentation - **[API Documentation](docs/api/LOCALE_PARAMETERS.md)**: Complete API reference for locale parameters and i18n endpoints - **[User Guide](docs/USER_GUIDE.md)**: End-user guide for language switching and multilingual features - **[Deployment Guide](docs/DEPLOYMENT_I18N.md)**: Production deployment with i18n configuration, caching, and monitoring - **[Technical Documentation](docs/TECHNICAL_I18N.md)**: Architecture details, template helpers, and code examples - **[I18n API Reference](docs/i18n/API_REFERENCE.md)**: Template rendering system and i18n integration details ### Legacy Documentation - [Template Rendering System Documentation](docs/FINAL_STATUS.md)