use std::cmp::Ordering;
use std::fmt;
use crate::entry::{
maybe_msgid_msgctxt_eot_split, mo_entry_to_string,
EntryCmpByOptions, MsgidEotMsgctxt, POEntry, Translated,
};
use crate::traits::Merge;
#[derive(Default, Clone, Debug, PartialEq)]
pub struct MOEntry {
pub msgid: String,
pub msgstr: Option<String>,
pub msgid_plural: Option<String>,
pub msgstr_plural: Vec<String>,
pub msgctxt: Option<String>,
}
impl MOEntry {
pub fn new(
msgid: String,
msgstr: Option<String>,
msgid_plural: Option<String>,
msgstr_plural: Vec<String>,
msgctxt: Option<String>,
) -> MOEntry {
MOEntry {
msgid,
msgstr,
msgid_plural,
msgstr_plural,
msgctxt,
}
}
pub fn to_string_with_wrapwidth(
&self,
wrapwidth: usize,
) -> String {
mo_entry_to_string(self, wrapwidth, "")
}
pub fn cmp_by(
&self,
other: &Self,
options: &EntryCmpByOptions,
) -> Ordering {
let placeholder = &"\0".to_string();
if options.by_msgctxt {
let msgctxt = self
.msgctxt
.as_ref()
.unwrap_or(placeholder)
.to_string();
let other_msgctxt = other
.msgctxt
.as_ref()
.unwrap_or(placeholder)
.to_string();
if msgctxt > other_msgctxt {
return Ordering::Greater;
} else if msgctxt < other_msgctxt {
return Ordering::Less;
}
}
if options.by_msgid_plural {
let msgid_plural = self
.msgid_plural
.as_ref()
.unwrap_or(placeholder)
.to_string();
let other_msgid_plural = other
.msgid_plural
.as_ref()
.unwrap_or(placeholder)
.to_string();
if msgid_plural > other_msgid_plural {
return Ordering::Greater;
} else if msgid_plural < other_msgid_plural {
return Ordering::Less;
}
}
if options.by_msgstr_plural {
let mut msgstr_plural = self.msgstr_plural.clone();
msgstr_plural.sort();
let mut other_msgstr_plural = other.msgstr_plural.clone();
other_msgstr_plural.sort();
if msgstr_plural > other_msgstr_plural {
return Ordering::Greater;
} else if msgstr_plural < other_msgstr_plural {
return Ordering::Less;
}
}
if options.by_msgid {
if self.msgid > other.msgid {
return Ordering::Greater;
} else if self.msgid < other.msgid {
return Ordering::Less;
}
}
if options.by_msgstr {
let msgstr = self
.msgstr
.as_ref()
.unwrap_or(placeholder)
.to_string();
let other_msgstr = other
.msgstr
.as_ref()
.unwrap_or(placeholder)
.to_string();
if msgstr > other_msgstr {
return Ordering::Greater;
} else if msgstr < other_msgstr {
return Ordering::Less;
}
}
Ordering::Equal
}
}
impl MsgidEotMsgctxt for MOEntry {
fn msgid_eot_msgctxt(&self) -> String {
maybe_msgid_msgctxt_eot_split(&self.msgid, &self.msgctxt)
.to_string()
}
}
impl Translated for MOEntry {
fn translated(&self) -> bool {
if let Some(msgstr) = &self.msgstr {
return !msgstr.is_empty();
}
if self.msgstr_plural.is_empty() {
return false;
} else {
for msgstr_plural in &self.msgstr_plural {
if !msgstr_plural.is_empty() {
return true;
}
}
}
false
}
}
impl Merge for MOEntry {
fn merge(&mut self, other: Self) {
self.msgid = other.msgid;
self.msgstr = other.msgstr;
self.msgid_plural = other.msgid_plural;
self.msgstr_plural = other.msgstr_plural;
self.msgctxt = other.msgctxt;
}
}
impl fmt::Display for MOEntry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_string_with_wrapwidth(78))
}
}
impl From<&str> for MOEntry {
fn from(s: &str) -> Self {
MOEntry::new(s.to_string(), None, None, vec![], None)
}
}
impl From<&POEntry> for MOEntry {
fn from(entry: &POEntry) -> Self {
MOEntry {
msgid: entry.msgid.clone(),
msgstr: entry.msgstr.clone(),
msgid_plural: entry.msgid_plural.clone(),
msgstr_plural: entry.msgstr_plural.clone(),
msgctxt: entry.msgctxt.clone(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn constructor() {
let moentry = MOEntry::new(
"msgid".to_string(),
Some("msgstr".to_string()),
None,
vec![],
None,
);
assert_eq!(moentry.msgid, "msgid");
assert_eq!(moentry.msgstr, Some("msgstr".to_string()));
assert_eq!(moentry.msgid_plural, None);
assert_eq!(moentry.msgstr_plural, vec![] as Vec<String>);
assert_eq!(moentry.msgctxt, None);
}
#[test]
fn moentry_translated() {
let moentry = MOEntry::new(
"msgid".to_string(),
Some("".to_string()),
None,
vec![],
None,
);
assert_eq!(moentry.translated(), false);
let moentry = MOEntry::new(
"msgid".to_string(),
Some("msgstr".to_string()),
None,
vec![],
None,
);
assert_eq!(moentry.translated(), true);
let moentry = MOEntry::new(
"msgid".to_string(),
None,
None,
vec![],
None,
);
assert_eq!(moentry.translated(), false);
let moentry = MOEntry::new(
"msgid".to_string(),
None,
None,
vec!["".to_string()],
None,
);
assert_eq!(moentry.translated(), false);
}
#[test]
fn moentry_merge() {
let mut moentry = MOEntry::new(
"msgid".to_string(),
Some("msgstr".to_string()),
Some("msgid_plural".to_string()),
vec!["msgstr_plural".to_string()],
Some("msgctxt".to_string()),
);
let other = MOEntry::new(
"other_msgid".to_string(),
Some("other_msgstr".to_string()),
Some("other_msgid_plural".to_string()),
vec!["other_msgstr_plural".to_string()],
Some("other_msgctxt".to_string()),
);
moentry.merge(other);
assert_eq!(moentry.msgid, "other_msgid");
assert_eq!(moentry.msgstr, Some("other_msgstr".to_string()));
assert_eq!(
moentry.msgid_plural,
Some("other_msgid_plural".to_string())
);
assert_eq!(
moentry.msgstr_plural,
vec!["other_msgstr_plural".to_string()],
);
assert_eq!(
moentry.msgctxt,
Some("other_msgctxt".to_string())
);
}
#[test]
fn moentry_to_string() {
let moentry = MOEntry::new(
"msgid".to_string(),
Some("msgstr".to_string()),
Some("msgid_plural".to_string()),
vec!["msgstr_plural".to_string()],
Some("msgctxt".to_string()),
);
let expected = r#"msgctxt "msgctxt"
msgid "msgid"
msgid_plural "msgid_plural"
msgstr[0] "msgstr_plural"
"#
.to_string();
assert_eq!(moentry.to_string(), expected);
let moentry = MOEntry::new(
"msgid".to_string(),
Some("msgstr".to_string()),
None,
vec![],
Some("msgctxt".to_string()),
);
let expected = r#"msgctxt "msgctxt"
msgid "msgid"
msgstr "msgstr"
"#
.to_string();
assert_eq!(moentry.to_string(), expected);
}
#[test]
fn moentry_from_poentry() {
let msgstr_plural = vec!["msgstr_plural".to_string()];
let mut poentry = POEntry::new(0);
poentry.msgid = "msgid".to_string();
poentry.msgstr = Some("msgstr".to_string());
poentry.msgid_plural = Some("msgid_plural".to_string());
poentry.msgstr_plural = msgstr_plural.clone();
poentry.msgctxt = Some("msgctxt".to_string());
let moentry = MOEntry::from(&poentry);
assert_eq!(moentry.msgid, "msgid");
assert_eq!(moentry.msgstr, Some("msgstr".to_string()));
assert_eq!(
moentry.msgid_plural,
Some("msgid_plural".to_string())
);
assert_eq!(moentry.msgstr_plural, msgstr_plural);
assert_eq!(moentry.msgctxt, Some("msgctxt".to_string()));
}
}