Rust本地化处理库with_locals的使用:高效管理多语言和本地化资源的插件库
Rust本地化处理库with_locals的使用:高效管理多语言和本地化资源的插件库
基本示例:返回/生成引用本地变量的format_args
use ::core::fmt::Display;
use ::with_locals::with;
#[with('local)]
fn hex(n: u32) -> &'local dyn Display
{
&format_args!("{:#x}", n)
}
上面的代码会被转换为:
use ::core::fmt::Display;
fn with_hex<R, F>(n: u32, f: F) -> R
where F : FnOnce(&'_ dyn Display) -> R,
// for<'local> F : FnOnce(&'local dyn Display) -> R,
{
f(&format_args!("{:#x}", n))
}
这里的f: F
被称为"continuation"(延续):
不是让函数返回/生成某个元素/对象,而是接收调用者想要对该元素执行的逻辑,
这样实际处理对象的是被调用者而不是调用者。
使用示例
with_hex(66, |s| {
println!("{}", s);
})
嵌套使用示例
with_hex(1, |one| {
with_hex(2, |two| {
with_hex(3, |three| {
// 嵌套层级过深...
})
})
})
使用#[with]
宏可以简化:
#[with] let one = hex(1);
#[with] let two = hex(2);
#[with] let three = hex(3);
完整示例代码
use ::core::fmt::Display;
use ::with_locals::with;
#[with('local)]
fn hex(n: u32) -> &'local dyn Display {
&format_args!("{:#x}", n)
}
#[with]
fn hex_example() {
let s: String = {
println!("Hello, World!");
#[with]
let s_hex = hex(66);
println!("s_hex = {}", s_hex); // 输出`s_hex = 0x42`
let s = s_hex.to_string();
assert_eq!(s, "0x42");
s
};
assert_eq!(s, "0x42");
}
#[with]
fn main() {
for n in 0.. {
#[with]
let s = hex(n);
println!("{}", s);
if n >= 5 {
break;
}
};
}
特性方法示例
use ::with_locals::with;
trait ToStr {
#[with('local)]
fn to_str(self: &'_ Self) -> &'local str;
}
impl ToStr for u32 {
#[with('local)]
fn to_str(self: &'_ u32) -> &'local str {
let mut x = *self;
if x == 0 {
return "0";
}
let mut buf = [b' '; 1 + 3 + 3 + 3]; // u32::MAX ~ 4_000_000_000
let mut cursor = buf.len();
while x > 0 {
cursor -= 1;
buf[cursor] = b'0' + (x % 10) as u8;
x /= 10;
}
::core::str::from_utf8(&buf[cursor..])
.unwrap()
}
}
#[with('special)]
fn main() {
let s: &'special str = 42.to_str();
assert_eq!(s, "42");
}
高级用法示例
use ::core::fmt::Display;
use ::with_locals::with;
#[with('local, continuation_name = return_)]
fn display_addr(addr: usize) -> &'local dyn Display {
if addr == 0 {
return_!(&"NULL");
}
with_hex(addr, |hex| {
return_(&format_args!("0x{}", hex))
})
}
#[with('local)]
fn hex(n: usize) -> &'local dyn Display {
&format_args!("{:x}", n)
}
调试宏展开
在Cargo.toml中启用expand-macros
特性:
[dependencies]
with_locals = { version = "...", features = ["expand-macros"] }
然后可以使用环境变量过滤特定展开:
WITH_LOCALS_DEBUG_FILTER=pattern cargo check
完整示例demo
以下是一个结合了上述特性的完整示例:
use ::core::fmt::Display;
use ::with_locals::with;
// 定义16进制格式化函数
#[with('local)]
fn hex(n: u32) -> &'local dyn Display {
&format_args!("{:#x}", n)
}
// 定义数字转字符串特性
trait ToStr {
#[with('local)]
fn to_str(self: &'_ Self) -> &'local str;
}
impl ToStr for u32 {
#[with('local)]
fn to_str(self: &'_ u32) -> &'local str {
let mut x = *self;
if x == 0 {
return "0";
}
let mut buf = [b' '; 10]; // 足够存储u32最大值
let mut cursor = buf.len();
while x > 0 {
cursor -= 1;
buf[cursor] = b'0' + (x % 10) as u8;
x /= 10;
}
::core::str::from_utf8(&buf[cursor..]).unwrap()
}
}
#[with]
fn main() {
// 使用hex函数
#[with]
let hex_value = hex(255);
println!("Hex value: {}", hex_value); // 输出 Hex value: 0xff
// 使用ToStr特性
#[with]
let str_value = 12345.to_str();
println!("String value: {}", str_value); // 输出 String value: 12345
// 组合使用
#[with]
let combined = hex(42);
println!("Combined: {}", combined); // 输出 Combined: 0x2a
// 嵌套使用
#[with]
let nested = {
#[with]
let a = hex(10);
#[with]
let b = hex(20);
format!("{} + {} = {}", a, b, 10 + 20)
};
println!("Nested: {}", nested); // 输出 Nested: 0xa + 0x14 = 30
}
1 回复
Rust本地化处理库with_locals的使用指南
概述
with_locals
是一个高效的Rust本地化处理库,专门设计用于管理多语言和本地化资源。它提供了简洁的API和强大的功能,帮助开发者轻松实现应用程序的国际化(i18n)和本地化(l10n)。
主要特性
- 轻量级且高效的内存使用
- 支持多种语言资源加载
- 线程安全的本地化资源管理
- 简单的键值对查找机制
- 支持格式化字符串和动态参数
安装
在Cargo.toml中添加依赖:
[dependencies]
with_locals = "0.3"
基本使用方法
1. 初始化本地化资源
use with_locals::Localizations;
let mut locals = Localizations::new();
locals.add("en", "greeting", "Hello, {}!");
locals.add("es", "greeting", "¡Hola, {}!");
locals.add("fr", "greeting", "Bonjour, {}!");
2. 获取本地化字符串
// 获取英语问候语
let greeting = locals.get("en", "greeting").unwrap();
println!("{}", greeting.format(&["John"])); // 输出: Hello, John!
// 获取西班牙语问候语
let greeting = locals.get("es", "greeting").unwrap();
println!("{}", greeting.format(&["Juan"])); // 输出: ¡Hola, Juan!
3. 使用默认语言
locals.set_default_language("en");
// 当请求的语言不存在时回退到默认语言
let greeting = locals.get("de", "greeting").unwrap();
println!("{}", greeting.format(&["Hans"])); // 输出: Hello, Hans!
高级用法
从文件加载本地化资源
use with_locals::Localizations;
use std::path::Path;
let mut locals = Localizations::new();
locals.load_from_file(Path::new("locales/en.json")).unwrap();
locals.load_from_file(Path::new("locales/es.json")).unwrap();
假设en.json
内容如下:
{
"greeting": "Hello, {}!",
"farewell": "Goodbye, {}!"
}
使用宏简化代码
use with_locals::{localizations, loc};
// 使用宏初始化
let locals = localizations! {
"en" => {
"greeting" => "Hello, {}!",
"farewell" => "Goodbye, {}!"
},
"es" => {
"greeting" => "¡Hola, {}!",
"farewell" => "¡Adiós, {}!"
}
};
// 使用宏获取本地化字符串
println!("{}", loc!(locals, "en", "greeting", "Alice"));
线程安全使用
use with_locals::Localizations;
use std::sync::Arc;
use std::thread;
let locals = Arc::new(localizations! {
"en" => { "thread" => "Thread {} says hello!" },
"fr" => { "thread" => "Le fil {} dit bonjour!" }
});
let handles: Vec<_> = (0..5).map(|i| {
let locals = Arc::clone(&locals);
thread::spawn(move || {
let msg = locals.get("fr", "thread").unwrap();
println!("{}", msg.format(&[&i.to_string()]));
})
}).collect();
for handle in handles {
handle.join().unwrap();
}
最佳实践
- 组织本地化文件:按语言代码组织JSON/YAML文件,如
en.json
,es.json
等 - 使用命名空间:为大型项目使用键前缀作为命名空间,如
homepage.title
- 缓存常用查询:对于频繁访问的字符串,考虑在应用层缓存
- 错误处理:总是处理
get
可能返回的None
情况
性能考虑
with_locals
在设计上注重性能:
- 使用高效的哈希映射存储本地化资源
- 最小化字符串复制
- 零成本抽象用于静态字符串
对于性能敏感的应用,建议在应用启动时预加载所有需要的本地化资源。
完整示例代码
use with_locals::{Localizations, localizations, loc};
use std::sync::Arc;
use std::thread;
fn main() {
// 基本使用示例
let mut locals = Localizations::new();
locals.add("en", "welcome", "Welcome, {}!");
locals.add("zh", "welcome", "欢迎, {}!");
let welcome_msg = locals.get("zh", "welcome").unwrap();
println!("{}", welcome_msg.format(&["张三"])); // 输出: 欢迎, 张三!
// 使用宏示例
let locals = localizations! {
"en" => {
"login" => "Login",
"logout" => "Logout"
},
"zh" => {
"login" => "登录",
"logout" => "退出"
}
};
println!("{}", loc!(locals, "zh", "login")); // 输出: 登录
// 线程安全示例
let shared_locals = Arc::new(localizations! {
"en" => { "count" => "Count: {}" },
"zh" => { "count" => "计数: {}" }
});
let mut handles = vec![];
for i in 1..=3 {
let locals = Arc::clone(&shared_locals);
handles.push(thread::spawn(move || {
let msg = locals.get("zh", "count").unwrap();
println!("{}", msg.format(&[&i.to_string()]));
}));
}
for handle in handles {
handle.join().unwrap();
}
}
总结
with_locals
库为Rust应用程序提供了简单而强大的本地化支持。通过其直观的API,开发者可以轻松实现多语言支持,同时保持代码的整洁和高效。无论是小型项目还是大型企业应用,with_locals
都能满足您的国际化需求。