1//! Defines `CatalogMetadata` struct.
2
3use std::collections::HashMap;
4
5use crate::plural::*;
6
7/// Metadata of a translation catalog.
8#[derive(Default)]
9pub struct CatalogMetadata {
10 /// `Project-Id-Version`
11 pub project_id_version: String,
12 /// `POT-Creation-Date`
13 pub pot_creation_date: String,
14 /// `PO-Revision-Date`
15 pub po_revision_date: String,
16 /// `Last-Translator`
17 pub last_translator: String,
18 /// `Language-Team`
19 pub language_team: String,
20 /// `MIME-Version`
21 pub mime_version: String,
22 /// `Content-Type`
23 pub content_type: String,
24 /// `Content-Transfer-Encoding`
25 pub content_transfer_encoding: String,
26 /// `Language`
27 pub language: String,
28 /// `Plural-Forms`
29 pub plural_rules: CatalogPluralRules,
30}
31
32/// Error in parsing metadata of a catalog
33#[derive(Debug)]
34pub struct MetadataParseError {
35 message: String,
36}
37
38impl From<PluralRulesError> for MetadataParseError {
39 fn from(e: PluralRulesError) -> Self {
40 Self {
41 message: e.to_string(),
42 }
43 }
44}
45
46impl std::fmt::Display for MetadataParseError {
47 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
48 write!(f, "invalid catalog metadata: {}", self.message)
49 }
50}
51
52impl std::error::Error for MetadataParseError {}
53
54impl CatalogMetadata {
55 /// Create a new empty catalog metadata.
56 pub fn new() -> Self {
57 CatalogMetadata::default()
58 }
59
60 /// Parse catalog metadata from string form stored in PO file.
61 pub fn parse(metadata: &str) -> Result<Self, MetadataParseError> {
62 let mut key_values = HashMap::new();
63 for line in metadata.split('\n') {
64 if let Some((key, value)) = line.split_once(':') {
65 key_values.insert(key, value.trim());
66 }
67 }
68 let res = CatalogMetadata {
69 project_id_version: key_values.get("Project-Id-Version").unwrap().to_string(),
70 pot_creation_date: key_values.get("POT-Creation-Date").unwrap().to_string(),
71 po_revision_date: key_values.get("PO-Revision-Date").unwrap().to_string(),
72 last_translator: key_values.get("Last-Translator").unwrap_or(&"").to_string(),
73 language_team: key_values.get("Language-Team").unwrap().to_string(),
74 mime_version: key_values.get("MIME-Version").unwrap().to_string(),
75 content_type: key_values.get("Content-Type").unwrap().to_string(),
76 content_transfer_encoding: key_values
77 .get("Content-Transfer-Encoding")
78 .unwrap()
79 .to_string(),
80 language: key_values.get("Language").unwrap().to_string(),
81 plural_rules: CatalogPluralRules::parse(key_values.get("Plural-Forms").unwrap())?,
82 };
83 Ok(res)
84 }
85
86 fn dump(&self, include_pot_creation_date: bool) -> String {
87 let mut buffer = String::new();
88 buffer.push_str(format!("Project-Id-Version: {}\n", self.project_id_version).as_str());
89 if include_pot_creation_date {
90 buffer.push_str(format!("POT-Creation-Date: {}\n", self.pot_creation_date).as_str());
91 }
92 buffer.push_str(format!("PO-Revision-Date: {}\n", self.po_revision_date).as_str());
93 buffer.push_str(format!("Last-Translator: {}\n", self.last_translator).as_str());
94 buffer.push_str(format!("Language-Team: {}\n", self.language_team).as_str());
95 buffer.push_str(format!("MIME-Version: {}\n", self.mime_version).as_str());
96 buffer.push_str(format!("Content-Type: {}\n", self.content_type).as_str());
97 buffer.push_str(
98 format!(
99 "Content-Transfer-Encoding: {}\n",
100 self.content_transfer_encoding
101 )
102 .as_str(),
103 );
104 buffer.push_str(format!("Language: {}\n", self.language).as_str());
105 buffer.push_str(format!("Plural-Forms: {}\n", self.plural_rules.dump()).as_str());
106 buffer
107 }
108
109 /// Export metadata for writing to a PO file.
110 pub fn export_for_po(&self) -> String {
111 self.dump(true)
112 }
113
114 /// Export metadata for writing to a MO file.
115 pub fn export_for_mo(&self) -> String {
116 self.dump(false)
117 }
118}
119