#fluent #localization

构建 fluent-typed

对 Fluent 本地化消息的类型安全访问

1 个不稳定版本

新功能 0.1.0 2024年8月27日

131构建工具

Download history · Rust 包仓库 93/week @ 2024-08-21 · Rust 包仓库

95 每月下载次数

自定义许可证

74KB
2K SLoC

Fluent-Typed

在使用翻译键时,通常没有简单的方法知道它们是否被正确使用,以及它们是否被使用。该项目使用 fluent ast 生成翻译键在 fluent 文件中的函数定义。

为了保证安全性,只有找到所有地区的消息才会生成函数。对于只找到某些地区的消息或如果消息的签名不同,将打印警告。

用户负责加载翻译资源,这使他有选择如何检索它们的自由(嵌入到二进制文件中、从文件加载、下载等)。

没有必要处理任何回退语言,因为可以保证所有消息都已翻译成所有语言

用法

# in Cargo.toml
[dependencies]
fluent-typed = 0.1

[build-dependencies]
fluent-typed = { version = "0.1", features = ["build"] }
// in build.rs
fn main() -> std::process::ExitCode {
    // generate the src/l10n.rs file from the fluent translations found in the locales folder,
    // prefix the generated functions with "msg_" and indent the code with 4 spaces.
    // This function returns an ExitCode.
    fluent_typed::build_from_locales_folder("locales", "src/l10n.rs", "msg_", "    ")

    // Note: there are also fluent_typed::try_build_from_locales_folder which returns a Result
}
// in lib.rs or main.rs
mod l10n;
use l10n::{L10nResource, L10n};


fn main() {
    // The L10nResource struct is generated by the build script and contains
    // one field per fluent resource used when generating the functions.
    let resources = L10nResource {
      // contains:
      //   # $name (String) - The user's name.
      //   hello = Hello { $name }
      //   greeting = Welcome!
      base: include_str!("locales/en/base.ftl"),
      // contains:
      //   # $count (Number) - How many unread meassages.
      //   unread_messages = You have { $count } unread messages
      settings: include_str!("locales/en/settings.ftl"),
    };

    // The L10n struct is generated by the build script and has
    // one function per message in the fluent resources.
    let strs = L10n::load("en", resources).unwrap();

    // A message without arguments.
    assert_eq!("Welcome!", strs.msg_greeting());
    // A message with a string argument (AsRef<str>).
    assert_eq!("Hello world", strs.msg_hello("world"));
    // A message with a number argument (Into<FluentNumber>).
    assert_eq!("You have 2 unread messages", strs.msg_unread_messages(2));
}

类型推导

由于 fluent 语法没有明确指定翻译变量的类型,该项目使用以下规则推断翻译变量的类型

  • 字符串
    • 如果一个变量的注释包含 (String),例如 # $name (String) - 名称.
  • 数字
    • 如果一个变量的注释包含 (Number),例如 # $count (Number) - 多少.
    • 如果使用了 NUMBER 函数,例如 dpi-ratio = 您的 DPI 比率是 { NUMBER($ratio) }
    • 如果一个选择器只包含数字和CLDR复数类别:zeroonetwofewmanyother。示例
      your-rank = { NUMBER($pos, type: "ordinal") ->
         [1] You finished first!
         [one] You finished {$pos}st
         [two] You finished {$pos}nd
         [few] You finished {$pos}rd
        *[other] You finished {$pos}th
      }
      

依赖关系

~1.5–2MB
~41K SLoC