29个版本
新版本 0.10.1 | 2024年8月19日 |
---|---|
0.9.4 | 2024年4月22日 |
0.9.1 | 2024年3月11日 |
0.8.0 | 2022年8月8日 |
0.5.13 | 2020年7月24日 |
#7 in 模板引擎
32,040 每月下载量
用于 26 个crate (12 直接使用)
67KB
952 行
Fluent Templates:一个高级Fluent API。
fluent-templates
允许您轻松地将 Fluent 本地化集成到您的Rust应用程序或库中。它通过提供一个高级“加载器”API来实现,该API根据简单的语言协商加载fluent字符串,以及一个 FluentLoader
结构体,它是一个对 Loader
无感知的容器类型,它提供了对流行的模板引擎(如handlebars或tera)的可选特质实现,允许您在模板中使用本地化而无需样板代码。
加载器
目前这个crate提供了两种不同类型的加载器,覆盖了两个主要用例。
-
static_loader!
— 一个过程宏,它将在 编译时 将您的fluent资源加载到您的二进制文件中,并创建一个新的StaticLoader
静态变量,允许您访问本地化。static_loader!
在您想要本地化应用程序并希望将fluent资源与二进制文件一起发布时非常有用。 -
ArcLoader
— 一个结构体,它使用Arc
作为其后端存储在 运行时 加载您的fluent资源。ArcLoader
在您希望在运行时更改和/或更新本地化,或者如果您正在编写一个希望在自己的应用程序中提供fluent本地化的开发工具(如静态网站生成器)时非常有用。
static_loader!
使用 fluent-templates
最简单的方法是使用 static_loader!
程序宏,它将创建一个新的 StaticLoader
静态变量。
基本示例
fluent_templates::static_loader! {
// Declare our `StaticLoader` named `LOCALES`.
static LOCALES = {
// The directory of localisations and fluent resources.
locales: "./tests/locales",
// The language to falback on if something is not present.
fallback_language: "en-US",
// Optional: A fluent resource that is shared with every locale.
core_locales: "./tests/locales/core.ftl",
};
}
自定义示例
您还可以在初始化时修改每个 FluentBundle
,以便能够更改配置或从 Rust 中添加资源。
use fluent_bundle::FluentResource;
use fluent_templates::static_loader;
use once_cell::sync::Lazy;
static_loader! {
// Declare our `StaticLoader` named `LOCALES`.
static LOCALES = {
// The directory of localisations and fluent resources.
locales: "./tests/locales",
// The language to falback on if something is not present.
fallback_language: "en-US",
// Optional: A fluent resource that is shared with every locale.
core_locales: "./tests/locales/core.ftl",
// Optional: A function that is run over each fluent bundle.
customise: |bundle| {
// Since this will be called for each locale bundle and
// `FluentResource`s need to be either `&'static` or behind an
// `Arc` it's recommended you use lazily initialised
// static variables.
static CRATE_VERSION_FTL: Lazy<FluentResource> = Lazy::new(|| {
let ftl_string = String::from(
concat!("-crate-version = {}", env!("CARGO_PKG_VERSION"))
);
FluentResource::try_new(ftl_string).unwrap()
});
bundle.add_resource(&CRATE_VERSION_FTL);
}
};
}
区域设置目录
fluent-templates
将收集所有匹配有效 Unicode 语言标识符 的子目录,并将这些目录中找到的所有 fluent 文件捆绑在一起,并将这些资源映射到相应的标识符。 fluent-templates
将按需递归遍历每个语言目录,并尊重任何存在的 .gitignore
或 .ignore
文件。
示例布局
locales
├── core.ftl
├── en-US
│ └── main.ftl
├── fr
│ └── main.ftl
├── zh-CN
│ └── main.ftl
└── zh-TW
└── main.ftl
查找 fluent 资源
您可以使用 Loader
特性来 lookup
给定的 fluent 资源,并使用 lookup_with_args
提供所需任何额外的参数。
示例
# In `locales/en-US/main.ftl`
hello-world = Hello World!
greeting = Hello { $name }!
# In `locales/fr/main.ftl`
hello-world = Bonjour le monde!
greeting = Bonjour { $name }!
# In `locales/de/main.ftl`
hello-world = Hallo Welt!
greeting = Hallo { $name }!
use std::collections::HashMap;
use unic_langid::{LanguageIdentifier, langid};
use fluent_templates::{Loader, static_loader};
const US_ENGLISH: LanguageIdentifier = langid!("en-US");
const FRENCH: LanguageIdentifier = langid!("fr");
const GERMAN: LanguageIdentifier = langid!("de");
static_loader! {
static LOCALES = {
locales: "./tests/locales",
fallback_language: "en-US",
// Removes unicode isolating marks around arguments, you typically
// should only set to false when testing.
customise: |bundle| bundle.set_use_isolating(false),
};
}
fn main() {
assert_eq!("Hello World!", LOCALES.lookup(&US_ENGLISH, "hello-world"));
assert_eq!("Bonjour le monde!", LOCALES.lookup(&FRENCH, "hello-world"));
assert_eq!("Hallo Welt!", LOCALES.lookup(&GERMAN, "hello-world"));
let args = {
let mut map = HashMap::new();
map.insert(String::from("name"), "Alice".into());
map
};
assert_eq!("Hello Alice!", LOCALES.lookup_with_args(&US_ENGLISH, "greeting", &args));
assert_eq!("Bonjour Alice!", LOCALES.lookup_with_args(&FRENCH, "greeting", &args));
assert_eq!("Hallo Alice!", LOCALES.lookup_with_args(&GERMAN, "greeting", &args));
}
Tera
使用 tera
功能,您可以像 Tera 函数一样使用 FluentLoader
。它接受一个指向 fluent 资源的 key
参数和一个表示要获取该键的语言的 lang
。您可以选择将额外参数作为资源参数传递给函数。fluent-templates
将自动将 Tera 的 snake_case
参数键转换为 fluent 优先的 kebab-case
参数。
fluent-templates = { version = "*", features = ["tera"] }
use fluent_templates::{FluentLoader, static_loader};
static_loader! {
static LOCALES = {
locales: "./tests/locales",
fallback_language: "en-US",
// Removes unicode isolating marks around arguments, you typically
// should only set to false when testing.
customise: |bundle| bundle.set_use_isolating(false),
};
}
fn main() {
let mut tera = tera::Tera::default();
let ctx = tera::Context::default();
tera.register_function("fluent", FluentLoader::new(&*LOCALES));
assert_eq!(
"Hello World!",
tera.render_str(r#"{{ fluent(key="hello-world", lang="en-US") }}"#, &ctx).unwrap()
);
assert_eq!(
"Hello Alice!",
tera.render_str(r#"{{ fluent(key="greeting", lang="en-US", name="Alice") }}"#, &ctx).unwrap()
);
}
Handlebars
在 handlebars 中,fluent-templates
将在渲染时读取您的 handlebars::Context
中的 lang
字段。
fluent-templates = { version = "*", features = ["handlebars"] }
use fluent_templates::{FluentLoader, static_loader};
static_loader! {
static LOCALES = {
locales: "./tests/locales",
fallback_language: "en-US",
// Removes unicode isolating marks around arguments, you typically
// should only set to false when testing.
customise: |bundle| bundle.set_use_isolating(false),
};
}
fn main() {
let mut handlebars = handlebars::Handlebars::new();
handlebars.register_helper("fluent", Box::new(FluentLoader::new(&*LOCALES)));
let data = serde_json::json!({"lang": "zh-CN"});
assert_eq!("Hello World!", handlebars.render_template(r#"{{fluent "hello-world"}}"#, &data).unwrap());
assert_eq!("Hello Alice!", handlebars.render_template(r#"{{fluent "greeting" name="Alice"}}"#, &data).unwrap());
}
Handlebars 辅助器语法。
提供的主要辅助器是 {{fluent}}
辅助器。如果您有以下 Fluent 文件
foo-bar = "foo bar"
placeholder = this has a placeholder { $variable }
placeholder2 = this has { $variable1 } { $variable2 }
您可以使用以下方式在模板中包含字符串
<!-- will render "foo bar" -->
{{fluent "foo-bar"}}
<!-- will render "this has a placeholder baz" -->
{{fluent "placeholder" variable="baz"}}
您还可以使用 {{fluentparam}}
辅助器来指定 变量,特别是当您需要它们为多行时。
{{#fluent "placeholder2"}}
{{#fluentparam "variable1"}}
first line
second line
{{/fluentparam}}
{{#fluentparam "variable2"}}
first line
second line
{{/fluentparam}}
{{/fluent}}
常见问题解答
为什么参数的值周围有额外的字符?
这些被称为“Unicode Isolating Marks”,用于允许文本双向。您可以通过将 FluentBundle::set_isolating_marks
设置为 false
来禁用此功能。
static_loader! {
static LOCALES = {
locales: "./tests/locales",
fallback_language: "en-US",
// Removes unicode isolating marks around arguments.
customise: |bundle| bundle.set_use_isolating(false),
};
}
依赖关系
~5–15MB
~181K SLoC