Skip to main content

gettext_mcp/model/
file.rs

1//! In-memory representation of a parsed PO file.
2
3use indexmap::IndexMap;
4
5use super::entry::MessageEntry;
6
7/// A parsed PO file: ordered translation entries plus header metadata
8/// plus any preserved obsolete (`#~`) lines.
9#[derive(Debug, Clone)]
10pub struct GettextFile {
11    /// All translation entries, including the header at key `("", None)`.
12    pub entries: IndexMap<(String, Option<String>), MessageEntry>,
13    /// Header metadata parsed out of the `msgid ""` entry's `msgstr`.
14    pub metadata: IndexMap<String, String>,
15    /// Raw obsolete entry lines (`#~ ...`) preserved verbatim for
16    /// round-trip fidelity.
17    pub obsolete_lines: Vec<String>,
18}
19
20impl GettextFile {
21    /// Construct an empty PO file with no entries and no metadata.
22    pub fn new() -> Self {
23        Self {
24            entries: IndexMap::new(),
25            metadata: IndexMap::new(),
26            obsolete_lines: Vec::new(),
27        }
28    }
29
30    /// `Plural-Forms` header, if set.
31    pub fn plural_forms(&self) -> Option<String> {
32        self.metadata.get("Plural-Forms").cloned()
33    }
34
35    /// `Language` header, if set.
36    pub fn language(&self) -> Option<String> {
37        self.metadata.get("Language").cloned()
38    }
39
40    /// Rebuild the header entry's `msgstr` from the current metadata map.
41    ///
42    /// Called by store mutators that change a header value: the on-disk
43    /// representation is the joined `Key: Value\n` block, so the entry
44    /// has to be regenerated whenever a header changes.
45    pub fn rebuild_header_entry(&mut self) {
46        let mut header_str = String::new();
47        for (k, v) in self.metadata.iter() {
48            header_str.push_str(&format!("{}: {}\n", k, v));
49        }
50        let header_key = (String::new(), None);
51        if let Some(entry) = self.entries.get_mut(&header_key) {
52            entry.msgstr = header_str;
53        } else {
54            self.entries.insert(
55                header_key,
56                MessageEntry {
57                    msgstr: header_str,
58                    ..Default::default()
59                },
60            );
61        }
62    }
63}
64
65impl Default for GettextFile {
66    fn default() -> Self {
67        Self::new()
68    }
69}