From 1957ba706f62a82a9f60df1f28e23de5fa8bb319 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Wed, 17 Jun 2026 01:05:24 +0800 Subject: Implement fallback chain resolution for translation keys --- shakehand/src/analyzer.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) (limited to 'shakehand/src/analyzer.rs') diff --git a/shakehand/src/analyzer.rs b/shakehand/src/analyzer.rs index 3007f58..f53461d 100644 --- a/shakehand/src/analyzer.rs +++ b/shakehand/src/analyzer.rs @@ -179,6 +179,55 @@ pub fn scan_toml_files(dir: &Path) -> Vec<(Vec, PathBuf)> { files } +/// Fallback chain configuration read from the crate's `Cargo.toml` `[package.metadata.shakehand]` +#[derive(Clone, Debug)] +pub struct FallbackConfig { + /// Per-language fallback: `source_language -> fallback_language` + pub fallback_map: BTreeMap, + /// Default fallback for any language not in `fallback_map` (`fallback.other`) + pub default_fallback: String, +} + +/// Read fallback configuration from the crate's `Cargo.toml` +/// under `[package.metadata.shakehand]`. +/// +/// Expects entries like: +/// ```toml +/// [package.metadata.shakehand] +/// fallback.other = "en" +/// fallback.zh_HK = "zh_CN" +/// fallback.zh_TW = "zh_CN" +/// ``` +pub fn read_fallback_from_manifest(manifest_dir: &str) -> Option { + let cargo_toml_path = Path::new(manifest_dir).join("Cargo.toml"); + let content = fs::read_to_string(&cargo_toml_path).ok()?; + let value: toml::Value = content.parse().ok()?; + + let shakehand = value.get("package")?.get("metadata")?.get("shakehand")?; + + let mut fallback_map = BTreeMap::new(); + let mut default_fallback = String::from("en"); + + // In TOML, `fallback.other = "en"` under `[package.metadata.shakehand]` + // creates a nested table `{ fallback: { other: "en", ... } }`. + if let Some(fallback_table) = shakehand.get("fallback").and_then(|v| v.as_table()) { + for (key, val) in fallback_table { + if let Some(fb_lang) = val.as_str() { + if key == "other" { + default_fallback = fb_lang.to_string(); + } else { + fallback_map.insert(key.to_string(), fb_lang.to_string()); + } + } + } + } + + Some(FallbackConfig { + fallback_map, + default_fallback, + }) +} + /// Parse a toml file pub fn parse_toml_file(path: &Path) -> Option { let content = fs::read_to_string(path).ok()?; -- cgit