502 lines
16 KiB
Markdown
502 lines
16 KiB
Markdown
|
|
considering we want to stick to nushell, how can we introduce i18n and fluent files into this framework project for pages ?
|
|||
|
|
do we need to crate a nushell plugin for i18n and FTL files ?
|
|||
|
|
Let us ultrathink on this for easy to use, admin and generate via AI or builders
|
|||
|
|
|
|||
|
|
✻ Thinking…
|
|||
|
|
|
|||
|
|
The user is asking about introducing internationalization (i18n) and Fluent (.ftl) files into the AuroraFrame project. They want to stick with Nushell and are
|
|||
|
|
wondering if they need to create a Nushell plugin for i18n and FTL files. They want me to think deeply about making it easy to use, administer, and generate via
|
|||
|
|
AI or builders.
|
|||
|
|
|
|||
|
|
Let me think about this:
|
|||
|
|
|
|||
|
|
1. Fluent is Mozilla's localization system that uses .ftl files for translations. It's more powerful than traditional i18n systems because it handles
|
|||
|
|
pluralization, gender, and complex formatting rules.
|
|||
|
|
2. Current Architecture: AuroraFrame is built with:
|
|||
|
|
- Nushell for scripting
|
|||
|
|
- KCL for configuration
|
|||
|
|
- Tera for templating
|
|||
|
|
- AI integration via MCP
|
|||
|
|
3. Options for i18n integration:
|
|||
|
|
- Native Nushell plugin for Fluent
|
|||
|
|
- Use existing Rust fluent-rs library via a wrapper
|
|||
|
|
- Integrate at the Tera template level
|
|||
|
|
- Build a custom solution using Nushell's data processing
|
|||
|
|
4. Considerations:
|
|||
|
|
- Easy to use for developers
|
|||
|
|
- AI-friendly for content generation
|
|||
|
|
- Works with the multi-output strategy (web/email/mobile)
|
|||
|
|
- Type-safe with KCL schemas
|
|||
|
|
|
|||
|
|
Let me think about the best approach:
|
|||
|
|
|
|||
|
|
Since we're in plan mode, I should research what's available and present a comprehensive plan for implementing i18n with Fluent in the AuroraFrame.
|
|||
|
|
|
|||
|
|
I should look at:
|
|||
|
|
|
|||
|
|
- How Fluent works
|
|||
|
|
- How to integrate it with Nushell
|
|||
|
|
- How to make it work with the existing KCL schemas
|
|||
|
|
- How to make it AI-friendly
|
|||
|
|
- How to support multiple output formats
|
|||
|
|
|
|||
|
|
⏺ Let me deeply analyze the i18n and Fluent integration options for AuroraFrame within the Nushell ecosystem.
|
|||
|
|
|
|||
|
|
Now let me think about how to design a comprehensive i18n solution for AuroraFrame that:
|
|||
|
|
|
|||
|
|
1. Stays within the Nushell ecosystem
|
|||
|
|
2. Uses Fluent/FTL files
|
|||
|
|
3. Is easy to use for developers
|
|||
|
|
4. Can be generated/managed via AI
|
|||
|
|
5. Works with the existing KCL schema system
|
|||
|
|
6. Integrates with Tera templates
|
|||
|
|
7. Supports multiple output formats (web/email/mobile)
|
|||
|
|
|
|||
|
|
🌐 Deep Analysis: i18n & Fluent Integration for AuroraFrame
|
|||
|
|
|
|||
|
|
After analyzing the requirements and ecosystem, here's my comprehensive approach for integrating i18n with Fluent into AuroraFrame:
|
|||
|
|
|
|||
|
|
Architecture Overview
|
|||
|
|
|
|||
|
|
┌─────────────────────────────────────────────────────┐
|
|||
|
|
│ AuroraFrame i18n │
|
|||
|
|
├─────────────────────────────────────────────────────┤
|
|||
|
|
│ KCL Schemas → AI Generator → FTL Files │
|
|||
|
|
│ ↓ ↓ ↓ │
|
|||
|
|
│ Type Safety MCP Server Fluent Bundle │
|
|||
|
|
│ ↓ ↓ ↓ │
|
|||
|
|
│ Validation Translations Template Engine │
|
|||
|
|
│ ↓ ↓ ↓ │
|
|||
|
|
│ [Web Output] [Email Output] [Mobile Output] │
|
|||
|
|
└─────────────────────────────────────────────────────┘
|
|||
|
|
|
|||
|
|
Proposed Solution: Hybrid Approach
|
|||
|
|
|
|||
|
|
1. nu_plugin_fluent (Rust Plugin)
|
|||
|
|
|
|||
|
|
Create a performant Nushell plugin that wraps fluent-rs:
|
|||
|
|
|
|||
|
|
// Core functionality
|
|||
|
|
|
|||
|
|
- parse_ftl: Parse FTL files into message bundles
|
|||
|
|
- localize: Get localized messages with arguments
|
|||
|
|
- validate_ftl: Check FTL syntax and references
|
|||
|
|
- list_messages: Extract all message IDs for type checking
|
|||
|
|
|
|||
|
|
1. Native Nushell i18n Framework
|
|||
|
|
|
|||
|
|
Pure Nushell orchestration layer for developer experience:
|
|||
|
|
|
|||
|
|
# High-level commands
|
|||
|
|
|
|||
|
|
aurora i18n init # Initialize i18n for project
|
|||
|
|
aurora i18n add <locale> # Add new locale
|
|||
|
|
aurora i18n generate # AI-generate translations
|
|||
|
|
aurora i18n validate # Check all translations
|
|||
|
|
aurora i18n extract # Extract strings from templates
|
|||
|
|
|
|||
|
|
1. KCL Schema Integration
|
|||
|
|
|
|||
|
|
Type-safe message definitions:
|
|||
|
|
|
|||
|
|
schema I18nMessage:
|
|||
|
|
id: str # Message ID
|
|||
|
|
description: str # Context for translators
|
|||
|
|
parameters: [Parameter] # Type-safe parameters
|
|||
|
|
variants: [Variant] # Plurals, gender, etc.
|
|||
|
|
|
|||
|
|
schema LocaleConfig:
|
|||
|
|
code: str # en-US, es-ES, etc.
|
|||
|
|
name: str # English, Spanish
|
|||
|
|
fallback: str? # Fallback locale
|
|||
|
|
direction: "ltr" | "rtl" # Text direction
|
|||
|
|
|
|||
|
|
Implementation Plan
|
|||
|
|
|
|||
|
|
Phase 1: Core Plugin Development
|
|||
|
|
|
|||
|
|
nu_plugin_fluent (Rust):
|
|||
|
|
use nu_plugin::{Plugin, PluginCommand};
|
|||
|
|
use fluent::{FluentBundle, FluentResource};
|
|||
|
|
|
|||
|
|
struct FluentPlugin;
|
|||
|
|
|
|||
|
|
impl Plugin for FluentPlugin {
|
|||
|
|
fn commands(&self) -> Vec<Box<dyn PluginCommand>> {
|
|||
|
|
vec![
|
|||
|
|
Box::new(ParseFtl),
|
|||
|
|
Box::new(Localize),
|
|||
|
|
Box::new(ValidateFtl),
|
|||
|
|
Box::new(ExtractMessages),
|
|||
|
|
]
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Command: localize
|
|||
|
|
// Usage: fluent localize "welcome-message" --locale "en-US" --args {name: "User"}
|
|||
|
|
|
|||
|
|
Phase 2: Nushell Framework Layer
|
|||
|
|
|
|||
|
|
framework/i18n.nu:
|
|||
|
|
|
|||
|
|
# Smart locale detection
|
|||
|
|
|
|||
|
|
export def detect_locale [] {
|
|||
|
|
# Check: URL param > Cookie > Header > System > Default
|
|||
|
|
let url_locale = ($env.QUERY_PARAMS?.locale?)
|
|||
|
|
let cookie_locale = ($env.COOKIES?.locale?)
|
|||
|
|
let header_locale = parse_accept_language $env.ACCEPT_LANGUAGE?
|
|||
|
|
let system_locale = ($env.LANG? | str substring 0..5)
|
|||
|
|
let default_locale = "en-US"
|
|||
|
|
|
|||
|
|
$url_locale | default $cookie_locale | default $header_locale | default $system_locale | default $default_locale
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Fluent message loader with caching
|
|||
|
|
|
|||
|
|
export def load_messages [locale: string, namespace: string = "main"] {
|
|||
|
|
let cache_key = $"($locale):($namespace)"
|
|||
|
|
|
|||
|
|
if $cache_key in $i18n_cache {
|
|||
|
|
return ($i18n_cache | get $cache_key)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
let ftl_path = $"locales/($locale)/($namespace).ftl"
|
|||
|
|
let messages = (fluent parse_ftl $ftl_path)
|
|||
|
|
|
|||
|
|
$i18n_cache = ($i18n_cache | insert $cache_key $messages)
|
|||
|
|
$messages
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Phase 3: AI-Powered Generation
|
|||
|
|
|
|||
|
|
MCP Integration for Translation:
|
|||
|
|
|
|||
|
|
# AI-powered FTL generation
|
|||
|
|
|
|||
|
|
export def "ai i18n generate" [
|
|||
|
|
source_locale: string = "en-US"
|
|||
|
|
target_locale: string
|
|||
|
|
--context: string # Additional context for AI
|
|||
|
|
] {
|
|||
|
|
# Extract messages from source
|
|||
|
|
let source_messages = (fluent extract_messages $"locales/($source_locale)")
|
|||
|
|
|
|||
|
|
# Generate via MCP
|
|||
|
|
let translations = (aurora ai translate $source_messages
|
|||
|
|
--from $source_locale
|
|||
|
|
--to $target_locale
|
|||
|
|
--format ftl
|
|||
|
|
--context $context)
|
|||
|
|
|
|||
|
|
# Validate and save
|
|||
|
|
let validated = (fluent validate_ftl $translations)
|
|||
|
|
$translations | save $"locales/($target_locale)/messages.ftl"
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Phase 4: Template Integration
|
|||
|
|
|
|||
|
|
Tera Filter for i18n:
|
|||
|
|
|
|||
|
|
# Register Tera filter
|
|||
|
|
|
|||
|
|
export def register_i18n_filters [tera_env: any] {
|
|||
|
|
# Add 'fluent' filter to Tera
|
|||
|
|
# Usage in template: {{ "welcome-message" | fluent(name="User") }}
|
|||
|
|
|
|||
|
|
let fluent_filter = {|msg_id, args|
|
|||
|
|
let locale = (detect_locale)
|
|||
|
|
let messages = (load_messages $locale)
|
|||
|
|
fluent localize $msg_id --bundle $messages --args $args
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
$tera_env | add_filter "fluent" $fluent_filter
|
|||
|
|
$tera_env | add_filter "t" $fluent_filter # Alias
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
FTL File Structure
|
|||
|
|
|
|||
|
|
locales/
|
|||
|
|
├── en-US/
|
|||
|
|
│ ├── main.ftl # Main messages
|
|||
|
|
│ ├── errors.ftl # Error messages
|
|||
|
|
│ └── emails.ftl # Email-specific
|
|||
|
|
├── es-ES/
|
|||
|
|
│ ├── main.ftl
|
|||
|
|
│ ├── errors.ftl
|
|||
|
|
│ └── emails.ftl
|
|||
|
|
└── locale.kcl # Locale configuration
|
|||
|
|
|
|||
|
|
Example FTL (main.ftl):
|
|||
|
|
|
|||
|
|
# Brand terms
|
|||
|
|
|
|||
|
|
-brand-name = AuroraFrame
|
|||
|
|
|
|||
|
|
# Welcome section
|
|||
|
|
|
|||
|
|
welcome-title = Welcome to { -brand-name }
|
|||
|
|
welcome-message =
|
|||
|
|
{ $user_type ->
|
|||
|
|
[new] Start your journey with { -brand-name }
|
|||
|
|
[returning] Welcome back to { -brand-name }
|
|||
|
|
*[other] Welcome to { -brand-name }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# Pluralization
|
|||
|
|
|
|||
|
|
page-count =
|
|||
|
|
{ $count ->
|
|||
|
|
[0] No pages
|
|||
|
|
[one] 1 page
|
|||
|
|
*[other] { $count } pages
|
|||
|
|
} built in { $time }ms
|
|||
|
|
|
|||
|
|
Easy Admin Interface
|
|||
|
|
|
|||
|
|
CLI Commands:
|
|||
|
|
|
|||
|
|
# Initialize i18n
|
|||
|
|
|
|||
|
|
aurora i18n init --locales en-US,es-ES,fr-FR
|
|||
|
|
|
|||
|
|
# Add translations interactively
|
|||
|
|
|
|||
|
|
aurora i18n add-message
|
|||
|
|
> Message ID: welcome-title
|
|||
|
|
> Default text: Welcome to {-brand-name}
|
|||
|
|
> Description: Main welcome heading
|
|||
|
|
|
|||
|
|
# Generate missing translations
|
|||
|
|
|
|||
|
|
aurora i18n sync --ai
|
|||
|
|
|
|||
|
|
# Validate all locales
|
|||
|
|
|
|||
|
|
aurora i18n validate --fix
|
|||
|
|
|
|||
|
|
# Extract from templates
|
|||
|
|
|
|||
|
|
aurora i18n extract src/**/*.html
|
|||
|
|
|
|||
|
|
AI Builder Integration
|
|||
|
|
|
|||
|
|
# AI-powered message builder
|
|||
|
|
|
|||
|
|
export def "ai i18n builder" [] {
|
|||
|
|
print "🤖 AuroraFrame i18n AI Builder"
|
|||
|
|
|
|||
|
|
# Analyze project structure
|
|||
|
|
let pages = (find_pages)
|
|||
|
|
let components = (find_components)
|
|||
|
|
|
|||
|
|
# Generate message suggestions
|
|||
|
|
let suggestions = (aurora ai analyze
|
|||
|
|
--prompt "Generate i18n message structure for these pages and components"
|
|||
|
|
--context {pages: $pages, components: $components})
|
|||
|
|
|
|||
|
|
# Interactive review
|
|||
|
|
for msg in $suggestions {
|
|||
|
|
print $"Suggested: ($msg.id)"
|
|||
|
|
print $" Text: ($msg.default_text)"
|
|||
|
|
let approve = (input "Add this message? (y/n/edit): ")
|
|||
|
|
|
|||
|
|
if $approve == "y" {
|
|||
|
|
add_message $msg
|
|||
|
|
} else if $approve == "edit" {
|
|||
|
|
let edited = (edit_message $msg)
|
|||
|
|
add_message $edited
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Multi-Output Support
|
|||
|
|
|
|||
|
|
# Different formatting per output type
|
|||
|
|
|
|||
|
|
export def format_for_output [text: string, output_type: string] {
|
|||
|
|
match $output_type {
|
|||
|
|
"web" => $text # HTML-safe output
|
|||
|
|
"email" => ($text | strip_markdown | wrap_email_template)
|
|||
|
|
"mobile" => ({
|
|||
|
|
text: $text,
|
|||
|
|
rtl: (is_rtl_locale (detect_locale)),
|
|||
|
|
formatted: (parse_fluent_markup $text)
|
|||
|
|
} | to json)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Type Safety with KCL
|
|||
|
|
|
|||
|
|
# locale-config.k
|
|||
|
|
|
|||
|
|
import "messages.k"
|
|||
|
|
|
|||
|
|
locales: [LocaleConfig] = [
|
|||
|
|
{
|
|||
|
|
code = "en-US"
|
|||
|
|
name = "English (US)"
|
|||
|
|
messages = messages_en_US
|
|||
|
|
fallback = None
|
|||
|
|
}
|
|||
|
|
{
|
|||
|
|
code = "es-ES"
|
|||
|
|
name = "Español"
|
|||
|
|
messages = messages_es_ES
|
|||
|
|
fallback = "en-US"
|
|||
|
|
}
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
# Compile-time validation
|
|||
|
|
|
|||
|
|
check:
|
|||
|
|
all locale in locales {
|
|||
|
|
locale.messages.keys() == required_message_ids
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Benefits of This Approach
|
|||
|
|
|
|||
|
|
1. Performance: Rust plugin for fast FTL parsing
|
|||
|
|
2. Developer Experience: Pure Nushell commands
|
|||
|
|
3. Type Safety: KCL validates message IDs
|
|||
|
|
4. AI-Ready: Built for content generation
|
|||
|
|
5. Multi-Output: Format per platform
|
|||
|
|
6. Hot Reload: Watch FTL files for changes
|
|||
|
|
7. Extensible: Easy to add new locales
|
|||
|
|
8. Testable: Validate all translations
|
|||
|
|
|
|||
|
|
Why Not Pure Nushell?
|
|||
|
|
|
|||
|
|
While we could parse FTL in pure Nushell, using fluent-rs via plugin provides:
|
|||
|
|
|
|||
|
|
- Battle-tested FTL parser
|
|||
|
|
- Complex plural/gender rules
|
|||
|
|
- Performance for large message catalogs
|
|||
|
|
- Compatibility with Fluent ecosystem
|
|||
|
|
|
|||
|
|
Next Steps
|
|||
|
|
|
|||
|
|
1. Create nu_plugin_fluent Rust crate
|
|||
|
|
2. Implement core i18n.nu framework
|
|||
|
|
3. Add MCP tools for translation
|
|||
|
|
4. Create example multilingual site
|
|||
|
|
5. Document best practices
|
|||
|
|
|
|||
|
|
This architecture provides the best of all worlds: Rust performance, Nushell ergonomics, AI assistance, and type safety - perfectly aligned with
|
|||
|
|
AuroraFrame's philosophy.
|
|||
|
|
|
|||
|
|
i18n & Fluent Integration Plan for AuroraFrame
|
|||
|
|
|
|||
|
|
Implementation Steps:
|
|||
|
|
|
|||
|
|
1. Create nu_plugin_fluent (Rust Plugin)
|
|||
|
|
- Wrap fluent-rs for FTL parsing and localization
|
|||
|
|
- Commands: parse_ftl, localize, validate_ftl, extract_messages
|
|||
|
|
- Handle plurals, gender, and complex language rules
|
|||
|
|
2. Build Nushell i18n Framework (framework/i18n.nu)
|
|||
|
|
- High-level commands: aurora i18n init/add/generate/validate
|
|||
|
|
- Smart locale detection (URL > Cookie > Header > System)
|
|||
|
|
- Message caching and hot reload
|
|||
|
|
- Multi-output formatting (web/email/mobile)
|
|||
|
|
3. Integrate with KCL Schemas
|
|||
|
|
- Define I18nMessage and LocaleConfig schemas
|
|||
|
|
- Type-safe message IDs and parameters
|
|||
|
|
- Compile-time validation of translations
|
|||
|
|
4. Add AI-Powered Translation via MCP
|
|||
|
|
- Generate FTL files from schemas
|
|||
|
|
- Auto-translate between locales
|
|||
|
|
- Interactive message builder
|
|||
|
|
- Context-aware suggestions
|
|||
|
|
5. Create Tera Template Integration
|
|||
|
|
- Add 'fluent' and 't' filters for templates
|
|||
|
|
- Format output per platform (web/email/mobile)
|
|||
|
|
- Handle RTL languages properly
|
|||
|
|
|
|||
|
|
File Structure:
|
|||
|
|
|
|||
|
|
auroraframe-fluent-plugin/ # Rust plugin
|
|||
|
|
locales/ # FTL files per locale
|
|||
|
|
framework/i18n.nu # Nushell i18n framework
|
|||
|
|
framework/i18n-schemas.k # KCL type definitions
|
|||
|
|
|
|||
|
|
Benefits:
|
|||
|
|
|
|||
|
|
- Type-safe i18n with compile-time checking
|
|||
|
|
- AI-assisted translation generation
|
|||
|
|
- Native Nushell developer experience
|
|||
|
|
- Fast Rust-powered FTL processing
|
|||
|
|
- Multi-platform output support
|
|||
|
|
|
|||
|
|
This hybrid approach leverages Rust for performance, Nushell for ergonomics, and AI for content generation - perfectly aligned with
|
|||
|
|
AuroraFrame's architecture.
|
|||
|
|
|
|||
|
|
but locales can be global or/and extended per page !!!
|
|||
|
|
probably we shoud require to have some kind of site and page settings for build tasks !!!
|
|||
|
|
|
|||
|
|
✻ Thinking…
|
|||
|
|
|
|||
|
|
Excellent point! The user is pointing out that locales should be flexible and hierarchical:
|
|||
|
|
|
|||
|
|
1. Global locales - site-wide translations (navigation, footer, common UI elements)
|
|||
|
|
2. Page-specific locales - content that's specific to individual pages
|
|||
|
|
3. Extended/overridden locales - where pages can override or extend global translations
|
|||
|
|
|
|||
|
|
This means we need:
|
|||
|
|
|
|||
|
|
- A hierarchical locale system
|
|||
|
|
- Site-level settings for default/available locales
|
|||
|
|
- Page-level settings for locale overrides/extensions
|
|||
|
|
- A build system that merges these appropriately
|
|||
|
|
- KCL schemas to define this structure
|
|||
|
|
|
|||
|
|
This is much more sophisticated than a simple flat locale structure. We need:
|
|||
|
|
|
|||
|
|
1. Site Configuration (site.k or similar):
|
|||
|
|
- Available locales
|
|||
|
|
- Default locale
|
|||
|
|
- Fallback chains
|
|||
|
|
- Global message namespaces
|
|||
|
|
2. Page Configuration (per page):
|
|||
|
|
- Page-specific locale overrides
|
|||
|
|
- Additional locale files
|
|||
|
|
- Locale inheritance rules
|
|||
|
|
3. Build Process:
|
|||
|
|
- Merge global + page-specific locales
|
|||
|
|
- Handle conflicts/overrides
|
|||
|
|
- Generate per-page locale bundles
|
|||
|
|
- Optimize for performance
|
|||
|
|
4. Directory Structure:
|
|||
|
|
locales/
|
|||
|
|
├── global/ # Site-wide translations
|
|||
|
|
│ ├── en-US/
|
|||
|
|
│ ├── es-ES/
|
|||
|
|
│ └── fr-FR/
|
|||
|
|
├── pages/ # Page-specific translations
|
|||
|
|
│ ├── blog/
|
|||
|
|
│ │ ├── en-US/
|
|||
|
|
│ │ └── es-ES/
|
|||
|
|
│ └── products/
|
|||
|
|
│ ├── en-US/
|
|||
|
|
│ └── es-ES/
|
|||
|
|
└── locale.k # Locale configuration
|
|||
|
|
|
|||
|
|
This requires rethinking the architecture to be more sophisticated and build-aware.
|
|||
|
|
|
|||
|
|
⏺ You're absolutely right! That's a crucial architectural insight. We need a hierarchical locale system with global + page-specific
|
|||
|
|
locales, integrated with build settings. Let me redesign this properly:
|
|||
|
|
|
|||
|
|
✻ Thinking…
|
|||
|
|
|
|||
|
|
The user is absolutely right. Let me redesign the i18n system with this hierarchical approach. I need to:
|
|||
|
|
|
|||
|
|
1. Create KCL schemas for site and page configuration that includes locale settings
|
|||
|
|
2. Design directory structure that supports global and page-specific locales
|
|||
|
|
3. Build system integration that merges locales during build
|
|||
|
|
4. Locale resolution that follows a priority chain: page-specific > global > fallback
|
|||
|
|
|
|||
|
|
Let me start with the configuration schemas and directory structure.
|
|||
|
|
|
|||
|
|
⏺ 🌐 Enhanced Hierarchical Locale Architecture
|
|||
|
|
|
|||
|
|
You're absolutely correct! Let me redesign this with proper global + page-specific locale architecture integrated with build settings:
|