2个版本
使用旧的Rust 2015
0.0.2 | 2017年9月2日 |
---|---|
0.0.1 | 2017年8月26日 |
#17 in #dict
用于 mauzi
48KB
925 lines
Mauzi
一个用于国际化的实验性库,使用proc_macro
宏。 这仅仅是我的一个实验;这个库不再开发了。
这个库背后的想法如下:i18n通常是通过编写特殊格式的文本文件来完成的。翻译者还可以使用一些特殊功能来简化复数等操作。与其使用具有奇怪语法的外部文件,我认为Rust将受益于拥有更类型安全的工具。你可以在模板库领域中看到类似的东西:有一些库以字符串作为输入(handlebars、tera等)。然后是maud
:在这里,模板是以proc_macro
内的语法编写的。这提供了更高的类型安全性,并带来了一些其他好处。
这个库希望成为i18n的“maud”。要了解这个库的样子:请看这个示例
mod dict {
use mauzi::mauzi;
mauzi! {
// The first thing in the macro invocation is the Locale definition.
// Here you define which languages and regions your dictionary
// supports.
enum Locale {
// You can have languages without distinguishing between regions...
De,
// ... but you can have regions for a given language, too.
En { Gb, Us },
}
// A simple translation unit: it returns a string depending on the
// locale.
unit fav_color {
De => "Was ist deine Lieblingsfarbe?",
En(Gb) => "What is your favourite colour?",
En(Us) => "What is your favorite color?",
}
// Translation units can take parameters. Those are declared in a pair
// of parenthesis, just like parameters for a Rust function.
//
// You can then use the parameter in the string with the `{param}`
// syntax.
unit greet(name: &str) {
En(Gb) => "Hi {name}! Are you all right, mate?",
En(Us) => "Hi {name}! How are you, buddy?",
De => "Hallo {name}, wie geht's dir?",
}
// Instead of simple strings, you can specify your own Rust code which
// will generate a string instead. Note that you can't use the fancy
// `{param}` syntax as above.
unit new_emails(count: u32) {
// Note that the region is omitted here. You can do that if the
// region doesn't matter. This is equivalent to `En(_)`.
En => {
match count {
1 => "You have one new email".to_string(),
_ => format!("You have {} new emails", count),
}
}
De => {
match count {
1 => "Sie haben eine neue E-Mail".to_string(),
_ => format!("Sie haben {} neue E-Mails", count),
}
}
}
// You can also specify custom return types. However, this requires you
// to specify raw bodies. Custom return types are mostly useful for
// preformatted HTML, like the `maud::Markup` type.
unit number_of_umlauts -> u32 {
De => { 3 },
En => { 0 },
}
}
}
fn main() {
use dict::{Locale, EnRegion};
let locales = [
Locale::De,
Locale::En(EnRegion::Gb),
Locale::En(EnRegion::Us),
];
for &locale in &locales {
println!("--- for {:?} ---", locale);
let dict = dict::new(locale);
// All translation keys are simple functions. You can access it like
// calling a function.
println!("greet => {}", dict.greet("Ferris"));
println!("fav_color => {}", dict.fav_color());
println!("new_emails => {}", dict.new_emails(3));
println!("umlauts => {}", dict.number_of_umlauts());
}
}
状态
这个库只是一个实验。我使用这个库的项目已经不存在了,所以我没有直接的动力去开发这个库。也许我会在将来再次访问这个库。
防患未然,双倍努力(一串脏技巧)
目前这个库和Rust 1.0之前的元素周期表中的 flerovium制成的纸牌屋一样不稳定。部分原因是我对某些事物缺乏理解,部分原因在于proc_macro
特性的不完整和不稳定。在这里,我想列出我现在使用的所有邪恶技巧。
模拟模块系统
我无法将 mauzi-modules 映射到 Rust 模块。问题在于,从子模块中,我需要使用在根模块中定义的 Dict
。理论上看起来很简单,但由于宏的清洁性(我想?),实际上很复杂。几乎没有任何 use
语句按预期工作。也许 这个 被采纳后能解决这个问题,也许不能。我在这里 也对类似的问题发表过评论。也许这已经可行,但我找不到解决方案。
当前的解决方案是在子模块中为类型构建长名称。所以,而不是
dict::bar::baz::Dict
... 类型是
dict::bar___this_is_a_bad_solution___baz___this_is_a_bad_solution___Dict
加载子模块文件
过程宏无法确定它是在哪个文件中被调用的。这意味着我们不知道在哪里查找子模块文件!这已经在这里讨论过。
当前的解决方案使用 CARGO_MANIFEST_PATH
并添加 src/
。这意味着
- 您必须在直接位于
src/
文件夹中的文件中调用mauzi!
宏。 - 任何不在
src/
中的项目都无法正常工作(例如,在examples/
中的示例)
许可证
根据您的选择,受以下任一许可证的许可:
- Apache License,版本 2.0,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证(LICENSE-MIT 或 http://opensource.org/licenses/MIT)
。
贡献
除非您明确表示,否则根据 Apache-2.0 许可证定义,您提交的任何有意包含在作品中的贡献,将如上所述双重许可,没有额外的条款或条件。
lib.rs
:
此crate定义了过程宏 mauzi!
。
您不应该直接使用此crate,而应使用 mauzi
。宏在那里重新导出。
依赖项
~31KB