{"record":{"id":"de8a3a35ffcbb074","repo":"cjpais/Handy","slug":"english-translations-must-exist","errorCode":null,"errorMessage":"English translations must exist","messagePattern":"English translations must exist","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/src/tray_i18n.rs","lineNumber":53,"sourceCode":"        .iter()\n        .any(|region| subtags.contains(region));\n\n    let exact_match = TRANSLATIONS\n        .iter()\n        .find_map(|(code, strings)| code.eq_ignore_ascii_case(&normalized).then_some(strings));\n    let fallback = match language {\n        \"zh\" if is_hant || (!is_hans && is_traditional_region) => \"zh-TW\",\n        // Cantonese uses Traditional Chinese unless explicitly tagged as Hans.\n        \"yue\" if is_hans => \"zh\",\n        \"yue\" => \"zh-TW\",\n        _ => language,\n    };\n\n    exact_match\n        .or_else(|| TRANSLATIONS.get(fallback))\n        .or_else(|| TRANSLATIONS.get(\"en\"))\n        .cloned()\n        .expect(\"English translations must exist\")\n}\n\n#[cfg(test)]\nmod tests {\n    use super::{get_tray_translations, TRANSLATIONS};\n\n    #[test]\n    fn resolves_locale_fallbacks() {\n        for (locale, expected) in [\n            (\"zh-Hant-TW\", \"zh-TW\"),\n            (\"zh-Hant-HK\", \"zh-TW\"),\n            (\"zh-HK\", \"zh-TW\"),\n            (\"zh-MO\", \"zh-TW\"),\n            (\"ZH-TW\", \"zh-TW\"),\n            (\"zh_Hant_TW\", \"zh-TW\"),\n            (\"zh-Hans-CN\", \"zh\"),\n            (\"yue-Hant-HK\", \"zh-TW\"),\n            (\"yue-Hans-CN\", \"zh\"),","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/cjpais/Handy/blob/c89b7bf38974ad317177389f5bfe28236f0d64e3/src-tauri/src/tray_i18n.rs#L35-L71","documentation":"get_tray_translations resolves a locale through TRANSLATIONS — a static HashMap code-generated at compile time by build.rs from the frontend locale files, with English as the designed single source of truth. Lookup order is exact match, then a script/region fallback (zh-Hant->zh-TW, yue->zh-TW, etc.), then the literal \"en\" entry. The .expect(\"English translations must exist\") fires only when that final invariant is broken: src/i18n/locales/en/translation.json was deleted, renamed, or failed to generate into OUT_DIR/tray_translations.rs.","triggerScenarios":"Deleting or renaming en/translation.json (or its \"tray\" section) so build.rs emits a TRANSLATIONS map without the \"en\" key; a malformed en JSON that makes build.rs skip the entry; a stale OUT_DIR after moving locale directories; then any call to get_tray_translations panics for every locale.","commonSituations":"Refactoring the i18n pipeline; changing the locales directory layout without updating build.rs globbing; CI caches serving a stale generated file; deliberately trying to make English a fallback-only build.","solutions":["Restore src/i18n/locales/en/translation.json with the complete \"tray\" key set — it is the source for the generated TrayStrings struct and the \"en\" map entry","Clean build artifacts (cargo clean) so build.rs regenerates OUT_DIR/tray_translations.rs from the current locale tree","Extend the existing tests module in tray_i18n.rs with a test asserting TRANSLATIONS.get(\"en\").is_some() so CI fails before runtime","If the locales layout changed, update the glob/discovery logic in build.rs to match"],"exampleFix":"// src-tauri/src/tray_i18n.rs — add to the existing #[cfg(test)] mod tests\n#[test]\nfn english_fallback_entry_exists() {\n    assert!(\n        TRANSLATIONS.get(\"en\").is_some(),\n        \"build.rs must generate the \\\"en\\\" entry; check src/i18n/locales/en/translation.json\"\n    );\n}\n\n// before: deleting locales/en/ makes get_tray_translations panic for ANY locale\n// after: the unit test fails at `cargo test` time instead of the app panicking at runtime","handlingStrategy":"validation","validationCode":"// src-tauri/src/tray_i18n.rs tests module\n#[test]\nfn english_fallback_entry_exists() {\n    assert!(TRANSLATIONS.get(\"en\").is_some(),\n        \"build.rs must emit the \\\"en\\\" entry; check src/i18n/locales/en/translation.json\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat en/translation.json as load-bearing build input: deleting or renaming it breaks the generated TRANSLATIONS map","Run cargo clean after changing the locales directory layout so build.rs regenerates OUT_DIR","Add CI tests for fallback invariants (en present) whenever a static map has a documented last-resort entry"],"tags":["rust","i18n","build-script","panic","invariant"],"backgroundTag":"missing-translation-fallback","analyzedSha":"c89b7bf38974ad317177389f5bfe28236f0d64e3","analyzedAt":"2026-08-17T10:29:55.597Z","contentChangedAt":"2026-08-17T10:29:55.597Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}