Jesús Pérez d9ef2f0d5b
Some checks failed
Build and Test / Validate Setup (push) Has been cancelled
Build and Test / Build (darwin-amd64) (push) Has been cancelled
Build and Test / Build (darwin-arm64) (push) Has been cancelled
Build and Test / Build (linux-amd64) (push) Has been cancelled
Build and Test / Build (windows-amd64) (push) Has been cancelled
Build and Test / Build (linux-arm64) (push) Has been cancelled
Build and Test / Security Audit (push) Has been cancelled
Build and Test / Package Results (push) Has been cancelled
Build and Test / Quality Gate (push) Has been cancelled
Nightly Build / Check for Changes (push) Has been cancelled
Nightly Build / Validate Setup (push) Has been cancelled
Nightly Build / Nightly Build (darwin-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (darwin-arm64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (windows-amd64) (push) Has been cancelled
Nightly Build / Nightly Build (linux-arm64) (push) Has been cancelled
Nightly Build / Create Nightly Pre-release (push) Has been cancelled
Nightly Build / Notify Build Status (push) Has been cancelled
Nightly Build / Nightly Maintenance (push) Has been cancelled
chore: update all plugins to Nushell 0.111.0
- Bump all 18 plugins from 0.110.0 to 0.111.0
  - Update rust-toolchain.toml channel to 1.93.1 (nu 0.111.0 requires ≥1.91.1)

  Fixes:
  - interprocess pin =2.2.x → ^2.3.1 in nu_plugin_mcp, nu_plugin_nats, nu_plugin_typedialog
    (required by nu-plugin-core 0.111.0)
  - nu_plugin_typedialog: BackendType::Web initializer — add open_browser: false field
  - nu_plugin_auth: implement missing user_info_to_value helper referenced in tests

  Scripts:
  - update_all_plugins.nu: fix [package].version update on minor bumps; add [dev-dependencies]
    pass; add nu-plugin-test-support to managed crates
  - download_nushell.nu: rustup override unset before rm -rf on nushell dir replace;
    fix unclosed ) in string interpolation
2026-03-11 03:22:42 +00:00

1 line
10 KiB
Markdown

# nu_plugin_fluent\n\nA [Nushell](https://nushell.sh/) plugin for [Fluent](https://projectfluent.org/) internationalization (i18n) and localization (l10n) workflows.\n\n## Overview\n\nThis plugin provides powerful tools for managing multilingual applications using Mozilla's Fluent localization system. It enables you to parse, validate, localize, and manage Fluent Translation List (`.ftl`) files directly from Nushell.\n\n## Installing\n\nClone this repository\n\n> [!WARNING]\n> **nu_plugin_fluent** has dependencies to nushell source via local path in Cargo.toml\n> Nushell and plugins require to be **sync** with same **version**\n\nClone [Nushell](https://nushell.sh/) alongside this plugin or change dependencies in [Cargo.toml](Cargo.toml)\n\nThis plugin is also included as submodule in [nushell-plugins](https://repo.jesusperez.pro/jesus/nushell-plugins)\nas part of plugins collection for [Provisioning project](https://rlung.librecloud.online/jesus/provisioning)\n\nBuild from source\n\n```nushell\n> cd nu_plugin_fluent\n> cargo install --path .\n```\n\n### Nushell\n\nIn a [Nushell](https://nushell.sh/)\n\n```nushell\n> plugin add ~/.cargo/bin/nu_plugin_fluent\n```\n\n## Commands\n\n### `fluent-parse`\n\nParse a Fluent Translation List (`.ftl`) file and extract its message structure.\n\n```nushell\n> fluent-parse <file>\n```\n\n**Parameters:**\n\n- **file** `<path>`: FTL file to parse\n\n**Example:**\n\n```nushell\n> fluent-parse locales/en-US/main.ftl\n╭───────────────┬─────────────────────────────╮\n│ file │ locales/en-US/main.ftl │\n│ message_count │ 3 │\n│ messages │ [list of parsed messages] │\n╰───────────────┴─────────────────────────────╯\n```\n\n### `fluent-localize`\n\nLocalize a message using the Fluent translation system with hierarchical fallback support.\n\n```nushell\n> fluent-localize <message_id> <locale> [--files] [--bundle] [--args] [--fallback]\n```\n\n**Parameters:**\n\n- **message_id** `<string>`: Message ID to localize\n- **locale** `<string>`: Locale code (e.g., en-US, es-ES)\n\n**Flags:**\n\n- **--files** `-f` `<list>`: FTL files to load\n- **--bundle** `-b` `<record>`: Pre-loaded message bundle\n- **--args** `-a` `<record>`: Arguments for message interpolation\n- **--fallback** `-F`: Return message ID if translation not found\n\n**Examples:**\n\nBasic localization:\n\n```nushell\n> fluent-localize welcome-message en-US --files [locales/en-US/main.ftl]\n"Welcome to our application!"\n```\n\nWith arguments:\n\n```nushell\n> fluent-localize user-greeting en-US --files [locales/en-US/main.ftl] --args {name: "Alice"}\n"Hello, Alice! Welcome back."\n```\n\nWith fallback:\n\n```nushell\n> fluent-localize missing-message es-ES --files [locales/es-ES/main.ftl] --fallback\n"[[missing-message]]"\n```\n\n### `fluent-validate`\n\nValidate the syntax of a Fluent Translation List (`.ftl`) file.\n\n```nushell\n> fluent-validate <file>\n```\n\n**Parameters:**\n\n- **file** `<path>`: FTL file to validate\n\n**Example:**\n\n```nushell\n> fluent-validate locales/en-US/main.ftl\n╭────────┬─────────────────────────╮\n│ valid │ true │\n│ file │ locales/en-US/main.ftl │\n│ errors │ [] │\n╰────────┴─────────────────────────╯\n```\n\n### `fluent-extract`\n\nExtract message IDs from a Fluent Translation List (`.ftl`) file.\n\n```nushell\n> fluent-extract <file>\n```\n\n**Parameters:**\n\n- **file** `<path>`: FTL file to extract messages from\n\n**Example:**\n\n```nushell\n> fluent-extract locales/en-US/main.ftl\n╭───┬─────────────────╮\n│ 0 │ welcome-message │\n│ 1 │ user-greeting │\n│ 2 │ goodbye-message │\n╰───┴─────────────────╯\n```\n\n### `fluent-list-locales`\n\nList available locales from a directory structure.\n\n```nushell\n> fluent-list-locales <directory>\n```\n\n**Parameters:**\n\n- **directory** `<path>`: Directory containing locale folders\n\n**Example:**\n\n```nushell\n> fluent-list-locales ./locales\n╭───┬───────╮\n│ 0 │ en-US │\n│ 1 │ es-ES │\n│ 2 │ fr-FR │\n│ 3 │ de-DE │\n╰───┴───────╯\n```\n\n### `fluent-create-bundle`\n\nCreate a merged Fluent bundle from global and page-specific locale files.\n\n```nushell\n> fluent-create-bundle <locale> [--global] [--page] [--fallback] [--override]\n```\n\n**Parameters:**\n\n- **locale** `<string>`: Locale code (e.g., en-US)\n\n**Flags:**\n\n- **--global** `-g` `<list>`: Global FTL files to include\n- **--page** `-p` `<list>`: Page-specific FTL files to include\n- **--fallback** `-f` `<list>`: Fallback locales in order\n- **--override** `-o`: Allow page files to override global messages\n\n**Examples:**\n\nCreate bundle with global and page-specific files:\n\n```nushell\n> fluent-create-bundle en-US --global [global/en-US/common.ftl] --page [pages/blog/en-US/blog.ftl]\n```\n\nCreate bundle with fallback support:\n\n```nushell\n> fluent-create-bundle es-ES --fallback [en-US] --global [global/es-ES/common.ftl]\n```\n\n## Workflow Examples\n\n### Complete Localization Workflow\n\n1. **Set up your locale directory structure:**\n\n```plaintext\nlocales/\n├── en-US/\n│ ├── common.ftl\n│ └── pages.ftl\n├── es-ES/\n│ ├── common.ftl\n│ └── pages.ftl\n└── fr-FR/\n ├── common.ftl\n └── pages.ftl\n```\n\n1. **List available locales:**\n\n```nushell\n> fluent-list-locales ./locales\n```\n\n1. **Validate all locale files:**\n\n```nushell\n> ls locales/**/*.ftl | each { |file| fluent-validate $file.name }\n```\n\n1. **Extract all message IDs for translation coverage:**\n\n```nushell\n> ls locales/en-US/*.ftl | each { |file|\n fluent-extract $file.name | wrap messages | insert file $file.name\n} | flatten\n```\n\n1. **Create a localization function:**\n\n```nushell\ndef localize [message_id: string, locale: string = "en-US"] {\n let files = (ls $"locales/($locale)/*.ftl" | get name)\n fluent-localize $message_id $locale --files $files --fallback\n}\n```\n\n1. **Use the localization function:**\n\n```nushell\n> localize "welcome-message" "es-ES"\n"¡Bienvenido a nuestra aplicación!"\n```\n\n### Quality Assurance Workflow\n\nCheck for missing translations across locales:\n\n```nushell\ndef check-translation-coverage [] {\n let base_locale = "en-US"\n let base_messages = (ls $"locales/($base_locale)/*.ftl"\n | each { |file| fluent-extract $file.name }\n | flatten | uniq)\n\n ls locales/*/\n | get name\n | path basename\n | where $it != $base_locale\n | each { |locale|\n let locale_messages = (ls $"locales/($locale)/*.ftl"\n | each { |file| fluent-extract $file.name }\n | flatten | uniq)\n\n let missing = ($base_messages | where $it not-in $locale_messages)\n {locale: $locale, missing_count: ($missing | length), missing: $missing}\n }\n}\n\n> check-translation-coverage\n```\n\n## Fluent File Format\n\nExample `.ftl` file structure:\n\n**locales/en-US/common.ftl**\n\n```fluent\n# Simple message\nwelcome-message = Welcome to our application!\n\n# Message with variables\nuser-greeting = Hello, { $name }! Welcome back.\n\n# Message with attributes\nlogin-button =\n .label = Sign In\n .aria-label = Sign in to your account\n .tooltip = Click here to access your account\n\n# Message with variants\nunread-emails = You have { $count ->\n [one] one unread email\n *[other] { $count } unread emails\n}.\n\n# Message with functions\nlast-login = Last login: { DATETIME($date, month: "long", day: "numeric") }\n```\n\n## Features\n\n- ✅ **Parse FTL files** - Extract and analyze message structure\n- ✅ **Validate syntax** - Ensure FTL files are syntactically correct\n- ✅ **Localize messages** - Translate messages with variable interpolation\n- ✅ **Fallback support** - Hierarchical locale fallback system\n- ✅ **Bundle management** - Merge global and page-specific translations\n- ✅ **Message extraction** - List all message IDs for coverage analysis\n- ✅ **Locale discovery** - Auto-detect available locales\n- ✅ **Quality assurance** - Tools for translation completeness checking\n\n## Use Cases\n\n- **Web Applications**: Manage frontend translations with dynamic content\n- **CLI Tools**: Internationalize command-line applications\n- **Documentation**: Maintain multilingual documentation systems\n- **Content Management**: Handle localized content workflows\n- **Quality Assurance**: Automate translation coverage and validation\n- **Build Systems**: Integrate i18n validation into CI/CD pipelines\n\n## Integration with Nushell\n\nThis plugin leverages Nushell's powerful data processing capabilities:\n\n```nushell\n# Batch validate all locale files\nls locales/**/*.ftl\n| par-each { |file| fluent-validate $file.name }\n| where valid == false\n\n# Generate translation progress report\ndef translation-report [] {\n fluent-list-locales ./locales\n | each { |locale|\n let files = (ls $"locales/($locale)/*.ftl" | get name)\n let message_count = ($files | each { |f| fluent-extract $f } | flatten | length)\n {locale: $locale, messages: $message_count}\n }\n}\n\n# Find untranslated messages\ndef find-missing-translations [base_locale: string, target_locale: string] {\n let base_msgs = (ls $"locales/($base_locale)/*.ftl" | each { |f| fluent-extract $f.name } | flatten)\n let target_msgs = (ls $"locales/($target_locale)/*.ftl" | each { |f| fluent-extract $f.name } | flatten)\n $base_msgs | where $it not-in $target_msgs\n}\n```\n\n## Contributing\n\nContributions are welcome! Please feel free to submit issues, feature requests, or pull requests.\n\n## License\n\nThis project is licensed under the MIT License.\n\n## Related Projects\n\n- [Fluent](https://projectfluent.org/) - Mozilla's localization system\n- [Nushell](https://nushell.sh/) - A new type of shell\n- [nu_plugin_tera](../nu_plugin_tera/) - Tera templating plugin for Nushell