langcodec_cli/
formats.rs

1use std::str::FromStr;
2
3/// Custom format types that are not supported by the lib crate.
4/// These are one-way conversions only (to Resource format).
5#[derive(Debug, Clone, PartialEq, clap::ValueEnum)]
6pub enum CustomFormat {
7    /// A JSON file which contains a map of language codes to translations.
8    ///
9    /// The key is the localization code, and the value is the translation:
10    ///
11    /// ```json
12    /// {
13    ///     "key": "hello_world",
14    ///     "en": "Hello, World!",
15    ///     "fr": "Bonjour, le monde!"
16    /// }
17    /// ```
18    JSONLanguageMap,
19
20    /// A YAML file which contains a map of language codes to translations.
21    ///
22    /// The key is the localization code, and the value is the translation:
23    ///
24    /// ```yaml
25    /// key: hello_world
26    /// en: Hello, World!
27    /// fr: Bonjour, le monde!
28    /// ```
29    YAMLLanguageMap,
30
31    /// A JSON file which contains an array of language map objects.
32    ///
33    /// Each object contains a key and translations for different languages:
34    ///
35    /// ```json
36    /// [
37    ///     {
38    ///         "key": "hello_world",
39    ///         "en": "Hello, World!",
40    ///         "fr": "Bonjour, le monde!"
41    ///     },
42    ///     {
43    ///         "key": "welcome_message",
44    ///         "en": "Welcome to our app!",
45    ///         "fr": "Bienvenue dans notre application!"
46    ///     }
47    /// ]
48    /// ```
49    JSONArrayLanguageMap,
50}
51
52impl FromStr for CustomFormat {
53    type Err = String;
54
55    fn from_str(s: &str) -> Result<Self, Self::Err> {
56        let normalized = s.trim().to_ascii_lowercase().replace(['-', '_'], "");
57        //: cspell:disable
58        match normalized.as_str() {
59            "jsonlanguagemap" => Ok(CustomFormat::JSONLanguageMap),
60            "jsonarraylanguagemap" => Ok(CustomFormat::JSONArrayLanguageMap),
61            "yamllanguagemap" => Ok(CustomFormat::YAMLLanguageMap),
62            // "csvlanguages" => Ok(CustomFormat::CSVLanguages),
63            _ => Err(format!(
64                "Unknown custom format: '{}'. Supported formats: json-language-map, json-array-language-map, yaml-language-map",
65                s
66            )),
67        }
68        //: cspell:enable
69    }
70}
71
72/// Parse a custom format from a string, with helpful error messages.
73pub fn parse_custom_format(s: &str) -> Result<CustomFormat, String> {
74    CustomFormat::from_str(s)
75}
76
77/// Detect if a file is a custom format based on its content and extension.
78/// Returns the detected custom format if found, None otherwise.
79pub fn detect_custom_format(file_path: &str, file_content: &str) -> Option<CustomFormat> {
80    let extension = std::path::Path::new(file_path)
81        .extension()
82        .and_then(|ext| ext.to_str())
83        .unwrap_or("")
84        .to_lowercase();
85
86    match extension.as_str() {
87        "json" => {
88            // Try to parse as JSON object first (JSONLanguageMap)
89            if let Ok(_) = serde_json::from_str::<serde_json::Value>(file_content) {
90                // Check if it's an object (not an array)
91                if let Ok(obj) = serde_json::from_str::<
92                    std::collections::HashMap<String, serde_json::Value>,
93                >(file_content)
94                {
95                    if !obj.is_empty() {
96                        return Some(CustomFormat::JSONLanguageMap);
97                    }
98                }
99                // Check if it's an array (JSONArrayLanguageMap)
100                if let Ok(_) = serde_json::from_str::<Vec<serde_json::Value>>(file_content) {
101                    return Some(CustomFormat::JSONArrayLanguageMap);
102                }
103            }
104        }
105        "yaml" | "yml" => {
106            // Try to parse as YAML
107            if let Ok(_) = serde_yaml::from_str::<serde_yaml::Value>(file_content) {
108                return Some(CustomFormat::YAMLLanguageMap);
109            }
110        }
111        _ => {}
112    }
113
114    None
115}
116
117/// Get a list of all supported custom formats for help messages.
118pub fn get_supported_custom_formats() -> &'static str {
119    "json-language-map, json-array-language-map, yaml-language-map"
120}