jlcodes99/cockpit-tools · critical

解析语言文件失败 {}: {}

Error message

解析语言文件失败 {}: {}

What it means

A startup panic in the Rust i18n module: one of the bundled locale JSON files failed `serde_json::from_str::<Value>` parsing, so the loader calls `panic!("解析语言文件失败 {locale}: {err}")`. Since this runs while building the embedded translations map, the whole process aborts at startup with the locale name and the serde error appended to the message (the `{}` in the template are the actual values).

Source

Thrown at src-tauri/src/modules/i18n.rs:33

            ("fr", include_str!("../../../src/locales/fr.json")),
            ("id", include_str!("../../../src/locales/id.json")),
            ("it", include_str!("../../../src/locales/it.json")),
            ("ja", include_str!("../../../src/locales/ja.json")),
            ("ko", include_str!("../../../src/locales/ko.json")),
            ("pl", include_str!("../../../src/locales/pl.json")),
            ("pt-br", include_str!("../../../src/locales/pt-br.json")),
            ("ru", include_str!("../../../src/locales/ru.json")),
            ("tr", include_str!("../../../src/locales/tr.json")),
            ("vi", include_str!("../../../src/locales/vi.json")),
            ("zh-cn", include_str!("../../../src/locales/zh-CN.json")),
            ("zh-tw", include_str!("../../../src/locales/zh-tw.json")),
        ];

        locale_files
            .into_iter()
            .map(|(locale, content)| {
                let parsed = serde_json::from_str::<Value>(content)
                    .unwrap_or_else(|err| panic!("解析语言文件失败 {}: {}", locale, err));
                (locale, parsed)
            })
            .collect()
    });

fn normalize_locale(locale: &str) -> String {
    locale.trim().replace('_', "-").to_lowercase()
}

fn locale_candidates(locale: &str) -> Vec<String> {
    let normalized = normalize_locale(locale);
    if normalized.is_empty() {
        return vec!["en-us".to_string(), "en".to_string()];
    }

    let mut candidates = vec![normalized.clone()];

    let mut prefix_matches: Vec<&str> = LOCALES

View on GitHub (pinned to 1ed8b77992)

Solutions

  1. Read the serde error in the panic message — it names the exact line/column in the locale file — and fix the JSON syntax there.
  2. Validate all locale files with a JSON linter (`jq . src-tauri/locales/*.json`) before rebuilding.
  3. Restore the affected locale file from version control if the edit was accidental.
  4. Replace the panic with a logged fallback so a bad locale degrades instead of crashing startup.

Example fix

// before
.unwrap_or_else(|err| panic!("解析语言文件失败 {}: {}", locale, err));
// after
.unwrap_or_else(|err| {
    log::error!("解析语言文件失败 {}: {}", locale, err);
    serde_json::json!({})
});
Defensive patterns

Strategy: validation

Validate before calling

# CI check before building
for f in src-tauri/locales/*.json; do jq -e . "$f" > /dev/null || { echo "invalid JSON: $f"; exit 1; }; done

Prevention

When it happens

Trigger: Embedding or editing a locale JSON file (e.g. zh-CN.json, en.json) with a syntax error — trailing comma, unquoted key, BOM, or non-JSON content — so `serde_json::from_str` fails when `load_locale_files` collects the map.

Common situations: A translator edited a language file by hand and broke the JSON; a build script embedded a partially written file; file encoding changed to UTF-8 with BOM; a merge conflict marker (<<<<<<<) was left inside a locale file.

Related errors


AI-assisted analysis of jlcodes99/cockpit-tools@1ed8b77992 (2026-09-05). Data as JSON: /api/errors/7068641814b1043a. Report an issue: GitHub.