#localization #macro #compile-time

l10n

基于 fluent-bundle 构建的具有观点的本地化库

3 个不稳定版本

0.1.1 2023年2月19日
0.1.0 2023年2月19日
0.1.0-beta.12022年10月19日
0.0.0 2022年8月8日

国际化(i18n)中排名第89

MIT/Apache

115KB
2.5K SLoC

l10n

CI badge Crate badge Rustc badge

l10n 是一个基于出色的 fluent-bundle 库,Fluent 项目thiserror 库构建的高层次、有观点的本地化包。

该包的目的是简化项目本地化并提供编译时检查(消息存在、必选参数已设置、函数已定义)。

您可以在以下位置查看一些示例: https://github.com/MathieuTricoire/l10n-examples

代码仓库: https://github.com/MathieuTricoire/l10n

⚠️ 关于 0.1 版本的注意事项 ⚠️

0.1 版本依赖于 fluent-bundle@0.15,它不包含以下问题的修复

  • 字符串参数:#251
  • Cow 的生命周期问题:#264
  • 合并参数:#271,l10n 依赖于这些修复

因此,字符串参数无法直接使用,您需要编写 "argument" = value.as_str() 而不是 "argument" = value,并且这个版本理论上性能较低,因为所有返回的 Cow<String> 实际上是所有者,并且由于参数合并方式。

如果您想使用包含这些问题修复的最新版本的 fluent-bundle,请使用 GitHub 上的版本

[dependencies]
l10n = { git = "https://github.com/MathieuTricoire/l10n.git" }

安装

[dependencies]
l10n = "0.1

MSRV:rustc 1.61+

快速开始

使用l10n无需配置,只需在Cargo.toml旁边创建一个l10n目录,创建多个包含fluent资源的区域目录(必须是有效的区域)。

示例

本地化目录树结构

l10n
├── _brand.ftl          (global unnamed resource)
├── en
│   ├── _common.ftl     (unnamed resource)
│   ├── app.ftl         (named resource)
│   └── settings.ftl    (named resource)
├── en-CA
├── en-GB
│   └── app.ftl         (named resource)
├── fr
│   ├── _common.ftl     (unnamed resource)
│   ├── app.ftl         (named resource)
│   └── settings.ftl    (named resource)
└── fr-CA
    ├── _terms.ftl      (unnamed resource)
    └── settings.ftl    (named resource)
Cargo.toml

l10n/fr/app.ftl文件

greeting = Bonjour { $first-name } !

l10n/fr/settings.ftl文件

status =
    .online = En ligne
    .offline = Hors ligne
    .busy = { $gender ->
        [male] Occupé
        [female] Occupée
       *[other] Non disponible
    } ({ $reason })

然后在应用程序或库的根目录中初始化l10n(这创建了一个其他宏使用的静态引用L10N),并使用message!宏或通过继承L10nMessage来创建l10n消息。

use l10n::unic_langid::langid;
use l10n::{message, message_args, L10nMessage};
use l10n::fluent_bundle::{FluentValue, FluentArgs}; // for functions, not necessary for this example

l10n::init!({
    // not necessary for this example
    functions: { "TIME": |_: &[FluentValue<'_>], _: &FluentArgs| FluentValue::None }
});

fn main() {
    let lang = langid!("fr");

    let username = "Alice";
    let greeting = message!("app", "greeting", "first-name" = username);
    assert_eq!(greeting.translate(&lang), "Bonjour \u{2068}Alice\u{2069} !");

    let status = Status::Busy {
        reason: "Meeting".to_string(),
    };
    assert_eq!(status.translate(&lang), "\u{2068}Non disponible\u{2069} (\u{2068}Meeting\u{2069})");
    assert_eq!(
        status.translate_with_args(&lang, Some(&message_args!("gender" => "female"))),
        "\u{2068}Occupée\u{2069} (\u{2068}Meeting\u{2069})"
    );
}

#[derive(L10nMessage)]
#[l10n_message("settings", "status")]
enum Status {
    #[l10n_message(".online")]
    Online,
    #[l10n_message(".offline")]
    Offline,
    #[l10n_message(".busy", "reason" = reason.as_str(), "gender" = "other")]
    Busy { reason: String },
}

高级用法

配置文件

Cargo.toml旁边创建一个l10n.tomlconfig.toml文件,以定义区域或设置包含区域目录和fluent文件的“本地化”目录的不同路径。

l10n.toml文件示例

[l10n]
locales = [
    "en",
    { main = "en-GB", fallback = "en" },
    { main = "en-CA", fallback = "en-GB" },
    "fr",
    { main = "fr-CA", fallback = "fr" },
]
path = "localization_files"

要在编译时使用另一个配置文件,设置环境变量L10N_CONFIG_FILE如下:L10N_CONFIG_FILE=/path/to/specific-config.toml

本地化目录的路径

为了根据需要有不同的“本地化”目录路径,使用path(或paths)的映射值,其中键是环境的名称,值是“本地化”目录的路径。需要一个default环境。

然后使用环境变量L10N_PATH_ENV编译使用此环境的工件。

l10n.toml文件示例

[l10n]
paths = { default = "l10n", prod = "/path/to/l10n" }

构建命令

L10N_PATH_ENV=prod cargo build --release

您还可以使用特殊变量前缀您的路径,例如$ROOT,库将用配置文件的路径替换此变量。

/path/to/l10n.toml文件示例

[l10n]
path = "$ROOT/localization_files"

生成的路径:/path/to/localization_files

区域

发现的区域

如果没有提供区域配置,l10n将在“本地化”目录中发现区域。如果区域包含“区域”代码,它将回退到没有“区域”代码的相同区域(如果存在)。

本地化目录树结构(只显示区域目录)

l10n
├── en
├── en-CA
├── en-GB
├── en-GB-variant
├── en-Latn
├── en-Latn-variant
├── en-Latn-GB
└── en-Latn-GB-variant

在上面的示例中,回退将是

  • en:无回退
  • en-CA:回退到en
  • en-GB:回退到en
  • en-GB-variant:无回退
  • en-Latn:无回退
  • en-Latn-variant:无回退
  • en-Latn-GB:回退到en-Latn
  • en-Latn-GB-variant:回退到en-Latn-variant

配置中设置的区域

如果区域被设置为“主要”区域,则可以将其使用,这意味着如果区域仅设置为回退,则无法在此区域中翻译消息。

l10n.toml文件示例

[l10n]
locales = [
  { main = "en-US", fallback = "en" },
  { main = "en-GB", fallback = "en" },
  { main = "en-CA", fallback = "en-GB" },
  { main = "fr" }, # same as writing `"fr",`
  { main = "fr-CA", fallback = "fr" },
]

在这个例子中,消息只能使用以下区域设置进行翻译:en-USen-GBen-CAfrfr-CA,但不能使用en,因为它仅设置为回退“区域设置”。

详细信息

资源

存在3种资源类型

  • 全局未命名资源:在l10n目录下以_开头,这些资源在所有区域设置的所有命名资源中共享。
  • 未命名资源:在区域设置目录下以_开头,这些资源在当前区域设置的所有命名资源中共享。
  • 命名资源:在区域设置目录下,这些是包含您可以在代码中使用的消息的资源。

“全局未命名资源”和“未命名资源”可以自由创建,并将根据其附加的区域设置加载。

“命名资源”必须存在于所有“强制区域设置”中。 “强制区域设置”是解析路径末尾的所有区域设置,在下一个示例中,“强制区域设置”是:“en”和“fr”。

[l10n]
locales = [
  { main = "en-GB", fallback = "en" },
  { main = "en-CA", fallback = "en-GB" },
  "fr",
  { main = "fr-CA", fallback = "fr" },
]

许可证

根据您的要求

贡献

除非您明确说明,否则您提交给作品以供包含的任何贡献,根据Apache-2.0许可证定义,应双许可如上所述,无任何额外条款或条件。

依赖项

~1.8–2.4MB
~51K SLoC