sysd_manager_translating/
lib.rs1use std::{fs, io, process::Command};
2
3use log::info;
4
5use crate::error::TransError;
6pub mod error;
7
8pub const MAIN_PROG: &str = "sysd-manager";
9pub const PO_DIR: &str = "./po";
10pub const DESKTOP_DIR: &str = "./data/applications";
11
12pub fn xgettext(potfiles_file_path: &str, output_pot_file: &str) {
15 let mut command = Command::new("xgettext");
16
17 for preset in glib_preset() {
18 command.arg(preset);
19 }
20
21 let output = command
22 .arg(format!("--files-from={potfiles_file_path}"))
23 .arg(format!("--output={output_pot_file}"))
24 .arg("--verbose")
25 .output()
26 .unwrap();
27
28 display_output("XGETTEXT", output);
29}
30
31fn display_output(id: &str, output: std::process::Output) {
32 println!("{id}: {:?}", output.status);
33 println!("{id}: {}", String::from_utf8_lossy(&output.stdout));
34 if !output.status.success() {
35 eprintln!("{id}: {}", String::from_utf8_lossy(&output.stderr));
36 }
37}
38
39pub fn msginit(input_pot_file: &str, output_file: &str, lang: &str) {
42 let mut command = Command::new("msginit");
43
44 let output = command
45 .arg(format!("--input={input_pot_file}"))
46 .arg(format!("--output-file={output_file}"))
47 .arg(format!("--locale={lang}"))
48 .output()
49 .expect("command msginit ok");
50
51 display_output("MSGINIT", output);
52}
53
54pub fn msgmerge(input_pot_file: &str, output_file: &str) {
60 let mut command = Command::new("msgmerge");
61
62 let output = command
63 .arg("-o")
64 .arg(output_file)
65 .arg(output_file)
66 .arg(input_pot_file)
67 .arg("--verbose")
68 .output()
69 .unwrap();
70
71 display_output("MSGMERGE", output);
72}
73
74pub fn generate_mo() -> Result<(), TransError> {
75 for path in fs::read_dir(PO_DIR)?
76 .filter_map(|r| r.ok())
77 .filter_map(|dir_entry| {
78 let p = dir_entry.path();
79 if p.extension().is_some_and(|this_ext| this_ext == "po") {
80 Some(p)
81 } else {
82 None
83 }
84 })
85 {
86 info!("PO file {:?} lang {:?}", path, path.file_stem());
87
88 if let Some(po_file) = path.to_str() {
89 if let Some(lang) = path.file_stem().and_then(|s| s.to_str()) {
90 msgfmt(po_file, lang, MAIN_PROG)?;
91 }
92 }
93 }
94
95 Ok(())
96}
97
98use std::env;
99
100pub fn set_lingas_env() -> Result<(), TransError> {
101 let mut vec: Vec<_> = fs::read_dir(PO_DIR)?
102 .filter_map(|r| r.ok())
103 .filter_map(|dir_entry| {
104 let p = dir_entry.path();
105 if p.extension().is_some_and(|this_ext| this_ext == "po") {
106 Some(p)
107 } else {
108 None
109 }
110 })
111 .filter_map(|path| {
112 path.file_stem()
113 .and_then(|s| s.to_str())
114 .map(|s| s.to_string())
115 })
121 .collect();
122
123 vec.sort();
124 let langs = vec.join(" ");
125
126 let key = "LINGUAS";
127 unsafe {
128 env::set_var(key, langs);
129 }
130
131 Ok(())
132}
133
134pub fn generate_desktop() -> Result<(), TransError> {
135 let desktop_file_name = "io.github.plrigaux.sysd-manager.desktop";
136
137 let out_dir = "target/locale";
138 fs::create_dir_all(out_dir)?;
139 let out_file = format!("{}/{}", out_dir, desktop_file_name);
140
141 let mut command = Command::new("msgfmt");
142 let output = command
143 .arg("--check")
144 .arg("--statistics")
145 .arg("--verbose")
146 .arg("--desktop")
147 .arg(format!("--template={DESKTOP_DIR}/{desktop_file_name}"))
148 .arg("-d")
149 .arg(PO_DIR)
150 .arg("-o")
151 .arg(out_file)
152 .output()?;
153
154 display_output("MSGFMT", output);
155
156 Ok(())
157}
158
159pub fn msgfmt(po_file: &str, lang: &str, domain_name: &str) -> io::Result<()> {
163 let mut command = Command::new("msgfmt");
164
165 let out_dir = format!("target/locale/{lang}/LC_MESSAGES");
166
167 fs::create_dir_all(&out_dir)?;
168
169 let output = command
170 .arg("--check")
171 .arg("--statistics")
172 .arg("--verbose")
173 .arg("-o")
174 .arg(format!("{out_dir}/{domain_name}.mo"))
175 .arg(po_file)
176 .output()
177 .unwrap();
178
179 display_output("MSGFMT", output);
180
181 Ok(())
182}
183
184fn glib_preset() -> Vec<&'static str> {
185 let v = vec![
186 "--from-code=UTF-8",
187 "--add-comments",
188 "--keyword=_",
190 "--keyword=N_",
191 "--keyword=C_:1c,2",
192 "--keyword=NC_:1c,2",
193 "--keyword=g_dcgettext:2",
194 "--keyword=g_dngettext:2,3",
195 "--keyword=g_dpgettext2:2c,3",
196 "--flag=N_:1:pass-c-format",
197 "--flag=C_:2:pass-c-format",
198 "--flag=NC_:2:pass-c-format",
199 "--flag=g_dngettext:2:pass-c-format",
200 "--flag=g_strdup_printf:1:c-format",
201 "--flag=g_string_printf:2:c-format",
202 "--flag=g_string_append_printf:2:c-format",
203 "--flag=g_error_new:3:c-format",
204 "--flag=g_set_error:4:c-format",
205 "--flag=g_markup_printf_escaped:1:c-format",
206 "--flag=g_log:3:c-format",
207 "--flag=g_print:1:c-format",
208 "--flag=g_printerr:1:c-format",
209 "--flag=g_printf:1:c-format",
210 "--flag=g_fprintf:2:c-format",
211 "--flag=g_sprintf:2:c-format",
212 "--flag=g_snprintf:3:c-format",
213 ];
214 v
215}