use crate::{cmark_xml, deepl};
pub async fn translate_cmark_file<P: AsRef<std::path::Path>>(
deepl: &deepl::Deepl,
from_lang: deepl::Language,
to_lang: deepl::Language,
formality: deepl::Formality,
src_path: P,
dst_path: P,
) -> std::io::Result<()> {
use std::io::Write;
let mut f = std::fs::File::open(src_path)?;
let (cmark_text, frontmatter) = cmark_xml::read_cmark_with_frontmatter(&mut f)?;
drop(f);
log::trace!(
"Read file:\n+++\n{}\n+++\n{}",
frontmatter.as_deref().unwrap_or_default(),
cmark_text
);
let translated_frontmatter = if let Some(frontmatter) = frontmatter {
Some(translate_toml(&deepl, from_lang, to_lang, formality, &frontmatter).await?)
} else {
None
};
let translated_cmark =
translate_cmark(&deepl, from_lang, to_lang, formality, &cmark_text).await?;
let mut f = std::fs::File::create(dst_path)?;
if let Some(translated_frontmatter) = translated_frontmatter {
f.write_all("+++\n".as_bytes())?;
f.write_all(translated_frontmatter.as_bytes())?;
f.write_all("+++\n".as_bytes())?;
}
f.write_all(translated_cmark.as_bytes())?;
Ok(())
}
pub async fn translate_toml(
deepl: &deepl::Deepl,
from_lang: deepl::Language,
to_lang: deepl::Language,
formality: deepl::Formality,
toml_frontmatter: &str,
) -> Result<String, std::io::Error> {
if let toml::Value::Table(mut root) = toml_frontmatter.parse::<toml::Value>()? {
let mut should_be_translate: Vec<&mut String> = vec![];
for (key, val) in &mut root {
match key.as_str() {
"title" | "description" => {
if let toml::Value::String(val) = val {
should_be_translate.push(val);
}
}
"extra" => {
if let toml::Value::Table(extra) = val {
for (extra_key, extra_val) in extra {
match extra_key.as_str() {
"time" => {
if let toml::Value::String(extra_val) = extra_val {
should_be_translate.push(extra_val);
}
}
_ => (),
}
}
}
}
_ => {}
}
}
let src_vec = should_be_translate
.iter()
.map(|s| s.as_str())
.collect::<Vec<&str>>();
let translated_vec = deepl
.translate_strings(from_lang, to_lang, formality, &src_vec)
.await
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
should_be_translate
.into_iter()
.zip(translated_vec.iter())
.for_each(|(toml_val, translated_str)| {
toml_val.clear();
*toml_val += translated_str.as_str();
});
let translated_frontmatter = toml::to_string_pretty(&toml::Value::Table(root)).unwrap();
log::trace!("Translated TOML :\n{}\n", translated_frontmatter);
Ok(translated_frontmatter)
} else {
Err(std::io::Error::from(std::io::ErrorKind::InvalidData))
}
}
pub async fn translate_cmark(
deepl: &deepl::Deepl,
from_lang: deepl::Language,
to_lang: deepl::Language,
formality: deepl::Formality,
cmark_text: &str,
) -> Result<String, std::io::Error> {
let xml = cmark_xml::xml_from_cmark(&cmark_text, true);
log::trace!("XML: {}\n", xml);
let xml_translated = deepl
.translate_xml(from_lang, to_lang, formality, &xml)
.await
.unwrap();
log::trace!("Translated XML: {}\n", xml);
let cmark_translated = cmark_xml::cmark_from_xml(&xml_translated, true).unwrap();
Ok(cmark_translated)
}