147 lines
4.4 KiB
Rust
147 lines
4.4 KiB
Rust
use std::{
|
|
fs::File,
|
|
io::{BufReader, Read, Write},
|
|
path::Path,
|
|
};
|
|
|
|
use icu_locid::{langid, LanguageIdentifier};
|
|
use xml::{attribute::OwnedAttribute, reader, writer, EmitterConfig, EventReader, EventWriter};
|
|
|
|
use crate::{Bundle, Message, ReadError, WriteError};
|
|
|
|
pub fn export_file(
|
|
bundle: &Bundle,
|
|
locale: LanguageIdentifier,
|
|
path: &Path,
|
|
) -> Result<(), WriteError> {
|
|
let mut file = File::create(path).unwrap();
|
|
export_fh(bundle, locale, &mut file)
|
|
}
|
|
|
|
pub fn export_fh<W>(bundle: &Bundle, locale: LanguageIdentifier, fh: W) -> Result<(), WriteError>
|
|
where
|
|
W: Write,
|
|
{
|
|
let mut writer = EmitterConfig::new().perform_indent(true).create_writer(fh);
|
|
|
|
writer
|
|
.write(
|
|
writer::XmlEvent::start_element("xliff")
|
|
.attr("xmlns", "urn:oasis:names:tc:xliff:document:2.0")
|
|
.attr("version", "2.0")
|
|
.attr("srcLang", &format!("{}", locale)),
|
|
)
|
|
.unwrap();
|
|
writer
|
|
.write(writer::XmlEvent::start_element("file").attr("id", "main"))
|
|
.unwrap();
|
|
|
|
for (key, message) in bundle.message_iter() {
|
|
write_message(&mut writer, key, message, &locale);
|
|
}
|
|
|
|
writer.write(writer::XmlEvent::end_element()).unwrap();
|
|
writer.write(writer::XmlEvent::end_element()).unwrap();
|
|
Ok(())
|
|
}
|
|
|
|
pub fn import_file(bundle: &mut Bundle, path: &Path) -> Result<(), ReadError> {
|
|
let file = File::open(path).unwrap();
|
|
let file = BufReader::new(file);
|
|
|
|
import_reader(bundle, file)
|
|
}
|
|
|
|
pub fn import_reader<R>(bundle: &mut Bundle, fh: R) -> Result<(), ReadError>
|
|
where
|
|
R: Read,
|
|
{
|
|
let parser = EventReader::new(fh);
|
|
|
|
let mut locale: LanguageIdentifier = langid!("en");
|
|
let mut current_key = None;
|
|
let mut current_text: Option<String> = None;
|
|
let mut in_target = false;
|
|
|
|
for event in parser {
|
|
match event {
|
|
Ok(reader::XmlEvent::StartElement {
|
|
name, attributes, ..
|
|
}) => match name.local_name.as_ref() {
|
|
"xliff" => {
|
|
locale = find_attribute(&attributes, "trgLang")
|
|
.unwrap()
|
|
.parse::<LanguageIdentifier>()
|
|
.unwrap();
|
|
}
|
|
"unit" => current_key = find_attribute(&attributes, "id"),
|
|
"target" => in_target = true,
|
|
_ => println!("name: {}", name),
|
|
},
|
|
Ok(reader::XmlEvent::EndElement { name }) => match name.local_name.as_ref() {
|
|
"unit" => {
|
|
if let Some(key) = current_key {
|
|
let message = bundle.message(key);
|
|
let variant = message.variant_mut(locale.clone());
|
|
if let Some(ref text) = current_text {
|
|
variant.set_content(text.clone());
|
|
}
|
|
}
|
|
current_key = None;
|
|
}
|
|
"target" => in_target = false,
|
|
_ => {}
|
|
},
|
|
Ok(reader::XmlEvent::Characters(data)) => {
|
|
if in_target {
|
|
current_text = Some(data)
|
|
}
|
|
}
|
|
Err(e) => {
|
|
eprintln!("error: {e}");
|
|
break;
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn write_message<T>(
|
|
writer: &mut EventWriter<T>,
|
|
key: &str,
|
|
message: &Message,
|
|
locale: &LanguageIdentifier,
|
|
) where
|
|
T: std::io::Write,
|
|
{
|
|
[
|
|
writer::XmlEvent::start_element("unit")
|
|
.attr("id", key)
|
|
.into(),
|
|
writer::XmlEvent::start_element("notes").into(),
|
|
writer::XmlEvent::start_element("note").into(),
|
|
writer::XmlEvent::characters(message.description()),
|
|
writer::XmlEvent::end_element().into(),
|
|
writer::XmlEvent::end_element().into(),
|
|
writer::XmlEvent::start_element("segment").into(),
|
|
writer::XmlEvent::start_element("source").into(),
|
|
writer::XmlEvent::characters(message.variant(locale).unwrap().content()),
|
|
writer::XmlEvent::end_element().into(),
|
|
writer::XmlEvent::end_element().into(),
|
|
writer::XmlEvent::end_element().into(),
|
|
]
|
|
.into_iter()
|
|
.for_each(|elem: writer::XmlEvent| writer.write(elem).unwrap());
|
|
}
|
|
|
|
fn find_attribute(attrs: &Vec<OwnedAttribute>, name: &str) -> Option<String> {
|
|
for f in attrs {
|
|
if name == f.name.local_name {
|
|
return Some(f.value.clone());
|
|
}
|
|
}
|
|
None
|
|
}
|