Rust
Rust 国际化
没有 Better I18N 的 crate。Rust 服务读取的是与所有 SDK 相同的 CDN JSON——reqwest 和 serde_json 就够了,新文案无需重新构建。
Setup
在 Rust 中使用 Better I18N
添加 HTTP 和 JSON crate
只需 reqwest 和 serde_json——没有需要安装的 Better I18N crate。
Cargo.toml
[dependencies]
reqwest = { version = "0.12", features = ["json"] }
serde_json = "1"
tokio = { version = "1", features = ["full"] }获取一个命名空间
CDN 为每个命名空间和语言提供一个 JSON 文件,并且总是返回 200。
src/i18n.rs
use std::collections::HashMap;
/// The CDN serves one JSON file per namespace, per locale:
/// https://cdn.better-i18n.com/{org}/{project}/{locale}/{namespace}.json
/// It always answers 200 — an unknown locale returns `{}` rather than an error.
pub async fn fetch_messages(
locale: &str,
namespace: &str,
) -> reqwest::Result<HashMap<String, serde_json::Value>> {
let url = format!(
"https://cdn.better-i18n.com/your-org/your-project/{locale}/{namespace}.json"
);
reqwest::get(&url).await?.json().await
}在后台刷新
在进程内缓存该映射,并每 60 秒重新读取一次,与 CDN 的 max-age 一致。
src/main.rs
use std::time::Duration;
// Cache in process and re-read on an interval: the CDN sets
// `Cache-Control: max-age=60`, so a 60s refresh matches it exactly.
tokio::spawn(async move {
let mut ticker = tokio::time::interval(Duration::from_secs(60));
loop {
ticker.tick().await;
if let Ok(next) = fetch_messages("en", "common").await {
*messages.write().await = next;
}
}
});Capabilities
Rust 服务能得到什么
无需 SDK——也不存在 Rust crate,因此无需等待
通过 HTTPS 传输的普通 JSON,用 serde_json 解析
适用于 axum、actix-web、Rocket 或普通二进制程序
新文案约 60 秒内到达,无需重新构建
REST API 覆盖 CDN 不提供的一切
如果你已用 rust-i18n 管理本地目录,两者可以共存
Example
一个读取 CDN 消息的 axum 处理函数
消息保存在 RwLock 后面,并由定时器刷新。
use axum::{extract::State, routing::get, Json, Router};
use std::{collections::HashMap, sync::Arc};
use tokio::sync::RwLock;
type Messages = Arc<RwLock<HashMap<String, serde_json::Value>>>;
async fn greeting(State(messages): State<Messages>) -> Json<serde_json::Value> {
let messages = messages.read().await;
let hello = messages
.get("greeting.hello")
.and_then(|v| v.as_str())
.unwrap_or("Hello");
Json(serde_json::json!({ "message": hello }))
}
#[tokio::main]
async fn main() {
let messages: Messages = Arc::new(RwLock::new(
fetch_messages("en", "common").await.unwrap_or_default(),
));
let app = Router::new()
.route("/greeting", get(greeting))
.with_state(messages);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}其他框架
Get started
为你的 Rust 服务做本地化
创建项目、发布第一个语言,然后在 Rust 中通过 HTTPS 读取。