prvng_core/nulib/lib_provisioning/fluent_daemon.nu

414 lines
11 KiB
Plaintext
Raw Normal View History

#! Fluent i18n translation daemon functions
#!
#! Provides high-performance message translation via HTTP API using Mozilla's Fluent.
#! The CLI daemon's Fluent engine offers 50-100x better performance than using
#! the nu_plugin_fluent plugin due to aggressive caching and no process spawning.
#!
#! Performance:
#! - Single translation: ~1-5ms uncached, ~0.1-0.5ms cached (vs ~50ms with plugin)
#! - Batch 10 translations: ~10-20ms with cache
#! - Cache hit ratio: 75-80% on typical workloads
use ../env.nu [get-cli-daemon-url]
# Translate a message ID to the target locale
#
# Uses the CLI daemon's Fluent engine for fast i18n translation.
# Supports variable interpolation and fallback locales.
#
# # Arguments
# * `message_id` - Message identifier (e.g., "welcome-message")
# * `--locale (-l)` - Target locale (default: "en-US")
# * `--args (-a)` - Arguments for variable interpolation (record)
# * `--fallback (-f)` - Fallback locale if message not found
#
# # Returns
# Translated message string or error if translation failed
#
# # Example
# ```nushell
# # Simple translation
# fluent-translate "welcome-message" --locale en-US
#
# # With arguments
# fluent-translate "greeting" --locale es --args {name: "María"}
#
# # With fallback
# fluent-translate "new-feature" --locale fr --fallback en-US
# ```
export def fluent-translate [
message_id: string
--locale (-l): string = "en-US"
--args (-a): record = {}
--fallback (-f): string
] -> string {
let daemon_url = (get-cli-daemon-url)
# Build request
let request = {
message_id: $message_id
locale: $locale
args: ($args | to json | from json)
fallback_locale: $fallback
}
# Send to daemon's Fluent endpoint
let response = (
http post $"($daemon_url)/fluent/translate" $request
--raw
)
# Parse response
let parsed = ($response | from json)
# Check for error
if ($parsed.error? != null) {
error make {msg: $"Fluent translation error: ($parsed.error)"}
}
# Return translated message
$parsed.translated
}
# Translate multiple messages in batch mode
#
# Translates a list of message IDs to the same locale. More efficient
# than calling fluent-translate multiple times due to connection reuse.
#
# # Arguments
# * `message_ids` - List of message IDs to translate
# * `--locale (-l)` - Target locale (default: "en-US")
# * `--fallback (-f)` - Fallback locale if messages not found
#
# # Returns
# List of translated messages
#
# # Example
# ```nushell
# let messages = ["welcome", "goodbye", "thank-you"]
# fluent-translate-batch $messages --locale fr --fallback en
# ```
export def fluent-translate-batch [
message_ids: list<string>
--locale (-l): string = "en-US"
--fallback (-f): string
] -> list<string> {
$message_ids | each { |msg_id|
fluent-translate $msg_id --locale $locale --fallback $fallback
}
}
# Load a Fluent bundle from a specific FTL file
#
# Loads messages from an FTL file into the daemon's bundle cache.
# This is useful for loading custom translations at runtime.
#
# # Arguments
# * `locale` - Locale identifier (e.g., "es", "fr-FR")
# * `path` - Path to FTL file
#
# # Returns
# Record with load status and message count
#
# # Example
# ```nushell
# fluent-load-bundle "es" "/path/to/es.ftl"
# ```
export def fluent-load-bundle [
locale: string
path: string
] -> record {
let daemon_url = (get-cli-daemon-url)
let request = {
locale: $locale
path: $path
}
let response = (
http post $"($daemon_url)/fluent/bundles/load" $request
)
$response | from json
}
# Reload all Fluent bundles from the FTL directory
#
# Clears all cached bundles and reloads them from the configured
# FTL directory. Useful after updating translation files.
#
# # Returns
# Record with reload status and list of loaded locales
#
# # Example
# ```nushell
# fluent-reload-bundles
# ```
export def fluent-reload-bundles [] -> record {
let daemon_url = (get-cli-daemon-url)
let response = (
http post $"($daemon_url)/fluent/bundles/reload" ""
)
$response | from json
}
# List all available locales
#
# Returns a list of all currently loaded locale identifiers.
#
# # Returns
# List of locale strings
#
# # Example
# ```nushell
# fluent-list-locales
# # Output: [en-US, es, fr-FR, de]
# ```
export def fluent-list-locales [] -> list<string> {
let daemon_url = (get-cli-daemon-url)
let response = (http get $"($daemon_url)/fluent/bundles/locales")
($response | from json).locales
}
# Get translation statistics from daemon
#
# Returns statistics about translations since daemon startup or last reset.
#
# # Returns
# Record with:
# - `total_translations`: Total number of translations
# - `successful_translations`: Number of successful translations
# - `failed_translations`: Number of failed translations
# - `cache_hits`: Number of cache hits
# - `cache_misses`: Number of cache misses
# - `cache_hit_ratio`: Cache hit ratio (0.0 - 1.0)
# - `bundles_loaded`: Number of bundles loaded
# - `total_time_ms`: Total time spent translating (milliseconds)
# - `average_time_ms`: Average time per translation
#
# # Example
# ```nushell
# fluent-stats
# ```
export def fluent-stats [] -> record {
let daemon_url = (get-cli-daemon-url)
let response = (http get $"($daemon_url)/fluent/stats")
$response | from json
}
# Reset translation statistics on daemon
#
# Clears all counters and timing statistics.
#
# # Example
# ```nushell
# fluent-reset-stats
# ```
export def fluent-reset-stats [] -> void {
let daemon_url = (get-cli-daemon-url)
http post $"($daemon_url)/fluent/stats/reset" ""
}
# Clear all Fluent caches
#
# Clears both the translation cache and bundle cache.
# All subsequent translations will reload bundles and re-translate messages.
#
# # Example
# ```nushell
# fluent-clear-caches
# ```
export def fluent-clear-caches [] -> void {
let daemon_url = (get-cli-daemon-url)
http delete $"($daemon_url)/fluent/cache/clear"
}
# Check if CLI daemon is running with Fluent support
#
# # Returns
# `true` if daemon is running with Fluent support, `false` otherwise
#
# # Example
# ```nushell
# if (is-fluent-daemon-available) {
# fluent-translate "welcome"
# } else {
# print "Fallback: Welcome!"
# }
# ```
export def is-fluent-daemon-available [] -> bool {
try {
let daemon_url = (get-cli-daemon-url)
let response = (http get $"($daemon_url)/fluent/health" --timeout 500ms)
($response | from json | .status == "healthy")
} catch {
false
}
}
# Ensure Fluent daemon is available
#
# Checks if the daemon is running and prints a status message.
# Useful for diagnostics and setup scripts.
#
# # Example
# ```nushell
# ensure-fluent-daemon
# ```
export def ensure-fluent-daemon [] -> void {
if (is-fluent-daemon-available) {
print "✅ Fluent i18n daemon is available and running"
} else {
print "⚠️ Fluent i18n daemon is not available"
print " CLI daemon may not be running at http://localhost:9091"
print " Translations will not work until daemon is started"
}
}
# Profile translation performance
#
# Translates a message multiple times and reports timing statistics.
# Useful for benchmarking and performance optimization.
#
# # Arguments
# * `message_id` - Message ID to translate
# * `--locale (-l)` - Target locale (default: "en-US")
# * `--iterations (-i)` - Number of times to translate (default: 100)
# * `--args (-a)` - Arguments for variable interpolation (record)
#
# # Returns
# Record with performance metrics
#
# # Example
# ```nushell
# fluent-profile "greeting" --locale es --iterations 1000 --args {name: "Usuario"}
# ```
export def fluent-profile [
message_id: string
--locale (-l): string = "en-US"
--iterations (-i): int = 100
--args (-a): record = {}
] -> record {
let start = (date now)
# Reset stats before profiling
fluent-reset-stats
# Run translations
for i in 0..<$iterations {
fluent-translate $message_id --locale $locale --args $args
}
let elapsed_ms = ((date now) - $start) | into duration | .0 / 1_000_000
let stats = (fluent-stats)
{
message_id: $message_id
locale: $locale
iterations: $iterations
total_time_ms: $elapsed_ms
avg_time_ms: ($elapsed_ms / $iterations)
daemon_total_translations: $stats.total_translations
daemon_cache_hits: $stats.cache_hits
daemon_cache_hit_ratio: $stats.cache_hit_ratio
daemon_avg_time_ms: $stats.average_time_ms
daemon_successful: $stats.successful_translations
daemon_failed: $stats.failed_translations
}
}
# Show cache efficiency report
#
# Displays a formatted report of cache performance.
#
# # Example
# ```nushell
# fluent-cache-report
# ```
export def fluent-cache-report [] -> void {
let stats = (fluent-stats)
print $"=== Fluent i18n Cache Report ==="
print $""
print $"Total translations: ($stats.total_translations)"
print $"Cache hits: ($stats.cache_hits)"
print $"Cache misses: ($stats.cache_misses)"
print $"Hit ratio: (($stats.cache_hit_ratio * 100) | math round --precision 1)%"
print $""
print $"Average latency: ($stats.average_time_ms | math round --precision 2)ms"
print $"Total time: ($stats.total_time_ms)ms"
print $""
print $"Bundles loaded: ($stats.bundles_loaded)"
print $"Success rate: (($stats.successful_translations / $stats.total_translations * 100) | math round --precision 1)%"
}
# Translate and fallback to default if not found
#
# Attempts to translate a message, falling back to a default value if not found.
#
# # Arguments
# * `message_id` - Message ID to translate
# * `default` - Default value if translation fails
# * `--locale (-l)` - Target locale (default: "en-US")
# * `--args (-a)` - Arguments for variable interpolation (record)
#
# # Returns
# Translated message or default value
#
# # Example
# ```nushell
# fluent-translate-or "new-feature" "New Feature" --locale fr
# ```
export def fluent-translate-or [
message_id: string
default: string
--locale (-l): string = "en-US"
--args (-a): record = {}
] -> string {
try {
fluent-translate $message_id --locale $locale --args $args
} catch {
$default
}
}
# Create a localized string table from message IDs
#
# Translates a list of message IDs and returns a record mapping IDs to translations.
#
# # Arguments
# * `message_ids` - List of message IDs
# * `--locale (-l)` - Target locale (default: "en-US")
#
# # Returns
# Record mapping message IDs to translated strings
#
# # Example
# ```nushell
# let ids = ["welcome", "goodbye", "help"]
# let strings = (fluent-string-table $ids --locale es)
# $strings.welcome # Accesses translated "welcome" message
# ```
export def fluent-string-table [
message_ids: list<string>
--locale (-l): string = "en-US"
] -> record {
let table = {}
for msg_id in $message_ids {
let translation = (fluent-translate $msg_id --locale $locale)
$table | insert $msg_id $translation
}
$table
}