Got universal strings to notify for missing translations.
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
Some checks failed
Gitea Actions Demo / Explore-Gitea-Actions (push) Failing after 1s
This commit is contained in:
@@ -10,6 +10,6 @@ use record::{InternalRecord, InternalRecords, Oid};
|
|||||||
pub use clock::Clock;
|
pub use clock::Clock;
|
||||||
pub use create::{CreateDoc, IndexType};
|
pub use create::{CreateDoc, IndexType};
|
||||||
pub use definition::{DocDef, DocFuncType};
|
pub use definition::{DocDef, DocFuncType};
|
||||||
pub use field::{Field, FieldType};
|
pub use field::{Field, FieldType, MissingTranslation};
|
||||||
pub use record::{Record, Records};
|
pub use record::{Record, Records};
|
||||||
pub use session::Session;
|
pub use session::Session;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::{ErrorID, MTTError};
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use isolang::Language;
|
use isolang::Language;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -577,10 +578,96 @@ mod paragraphs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
|
||||||
|
struct ParagraphID {
|
||||||
|
data: Uuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ParagraphID {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
data: Uuid::new_v4(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nil() -> Self {
|
||||||
|
Self { data: Uuid::nil() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod paragraphids {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn are_paragraph_ids_unique() {
|
||||||
|
let id1 = ParagraphID::new();
|
||||||
|
let id2 = ParagraphID::new();
|
||||||
|
assert_ne!(id1, id2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_create_nil() {
|
||||||
|
let id = ParagraphID::nil();
|
||||||
|
assert_eq!(id.data, Uuid::nil());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct MissingTranslation {
|
||||||
|
needs: Language,
|
||||||
|
has: Language,
|
||||||
|
text: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MissingTranslation {
|
||||||
|
fn new(needs: Language, has: Language, text: String) -> Self {
|
||||||
|
Self {
|
||||||
|
needs: needs,
|
||||||
|
has: has,
|
||||||
|
text: text,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn needs(&self) -> Language {
|
||||||
|
self.needs.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has(&self) -> Language {
|
||||||
|
self.has.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn text(&self) -> String {
|
||||||
|
self.text.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod missing_translations {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_get_mising_translation_information() {
|
||||||
|
let langs = [
|
||||||
|
Language::from_639_1("en").unwrap(),
|
||||||
|
Language::from_639_1("ja").unwrap(),
|
||||||
|
];
|
||||||
|
let text = Uuid::new_v4().to_string();
|
||||||
|
let missing = MissingTranslation::new(langs[0].clone(), langs[1].clone(), text.clone());
|
||||||
|
assert_eq!(missing.needs(), langs[0]);
|
||||||
|
assert_eq!(missing.has(), langs[1]);
|
||||||
|
assert_eq!(missing.text(), text);
|
||||||
|
let missing2 = MissingTranslation::new(langs[1].clone(), langs[0].clone(), text.clone());
|
||||||
|
assert_eq!(missing2.needs(), langs[1]);
|
||||||
|
assert_eq!(missing2.has(), langs[0]);
|
||||||
|
assert_eq!(missing2.text(), text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
struct UniversalString {
|
struct UniversalString {
|
||||||
paragraphs: HashMap<Uuid, Paragraph>,
|
paragraphs: HashMap<ParagraphID, Paragraph>,
|
||||||
revisions: Vec<Vec<Uuid>>,
|
revisions: Vec<Vec<ParagraphID>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UniversalString {
|
impl UniversalString {
|
||||||
@@ -593,20 +680,36 @@ impl UniversalString {
|
|||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, lang: &Language) -> Option<String> {
|
fn get(&self, lang: &Language) -> Result<String, MTTError> {
|
||||||
let latest = self.revisions.len() - 1;
|
let latest = self.revisions.len() - 1;
|
||||||
self.get_revision(latest, lang)
|
self.get_revision(latest, lang)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_revision(&self, rev_num: usize, lang: &Language) -> Option<String> {
|
fn get_revision(&self, rev_num: usize, lang: &Language) -> Result<String, MTTError> {
|
||||||
let mut output = "".to_string();
|
let mut output = "".to_string();
|
||||||
|
let mut missing: Vec<MissingTranslation> = Vec::new();
|
||||||
for id in self.revisions[rev_num].iter() {
|
for id in self.revisions[rev_num].iter() {
|
||||||
let paragraph = self.paragraphs.get(id).unwrap();
|
let paragraph = self.paragraphs.get(id).unwrap();
|
||||||
let text = paragraph.get(lang).unwrap();
|
let text = match paragraph.get(lang) {
|
||||||
|
Some(data) => data,
|
||||||
|
None => {
|
||||||
|
let (ori_lang, text) = paragraph.get_initial();
|
||||||
|
missing.push(MissingTranslation::new(
|
||||||
|
lang.clone(),
|
||||||
|
ori_lang.clone(),
|
||||||
|
text.clone(),
|
||||||
|
));
|
||||||
|
""
|
||||||
|
}
|
||||||
|
};
|
||||||
output += text;
|
output += text;
|
||||||
output += "\u{2029}";
|
output += "\u{2029}";
|
||||||
}
|
}
|
||||||
Some(output)
|
if missing.is_empty() {
|
||||||
|
Ok(output)
|
||||||
|
} else {
|
||||||
|
Err(MTTError::new(ErrorID::MissingTranslation(missing)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn revision_count(&self) -> usize {
|
fn revision_count(&self) -> usize {
|
||||||
@@ -617,17 +720,17 @@ impl UniversalString {
|
|||||||
let mut version = Vec::new();
|
let mut version = Vec::new();
|
||||||
for paragraph in text.as_str().split("\u{2029}") {
|
for paragraph in text.as_str().split("\u{2029}") {
|
||||||
if paragraph != "" {
|
if paragraph != "" {
|
||||||
let mut id = Uuid::nil();
|
let mut id = ParagraphID::nil();
|
||||||
for (key, value) in self.paragraphs.iter() {
|
for (key, value) in self.paragraphs.iter() {
|
||||||
if ¶graph == value.get(&lang).unwrap() {
|
if ¶graph == value.get(&lang).unwrap() {
|
||||||
id = key.clone();
|
id = key.clone();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if id == Uuid::nil() {
|
if id == ParagraphID::nil() {
|
||||||
id = Uuid::new_v4();
|
id = ParagraphID::new();
|
||||||
while self.paragraphs.contains_key(&id) {
|
while self.paragraphs.contains_key(&id) {
|
||||||
id = Uuid::new_v4();
|
id = ParagraphID::new();
|
||||||
}
|
}
|
||||||
self.paragraphs.insert(
|
self.paragraphs.insert(
|
||||||
id.clone(),
|
id.clone(),
|
||||||
@@ -645,6 +748,7 @@ impl UniversalString {
|
|||||||
mod universal_strings {
|
mod universal_strings {
|
||||||
use super::*;
|
use super::*;
|
||||||
use rand::random_range;
|
use rand::random_range;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
const ENGLISH_DATA: [&str; 5] = ["one", "two", "three", "four", "five"];
|
const ENGLISH_DATA: [&str; 5] = ["one", "two", "three", "four", "five"];
|
||||||
const JAPANESE_DATA: [&str; 5] = ["一", "二", "三", "四", "五"];
|
const JAPANESE_DATA: [&str; 5] = ["一", "二", "三", "四", "五"];
|
||||||
@@ -764,4 +868,32 @@ mod universal_strings {
|
|||||||
assert_eq!(ustr.paragraphs.len(), expected_paragraphs, "{:?}", ustr);
|
assert_eq!(ustr.paragraphs.len(), expected_paragraphs, "{:?}", ustr);
|
||||||
assert_eq!(ustr.get_revision(0, &lang).unwrap(), initial);
|
assert_eq!(ustr.get_revision(0, &lang).unwrap(), initial);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_translation_be_added() {
|
||||||
|
let (elang, edata) = TestData::english();
|
||||||
|
let (jlang, jdata) = TestData::japanese();
|
||||||
|
let initial = TestData::to_input(jdata.clone());
|
||||||
|
let mut ustr = UniversalString::new(jlang.clone(), initial.clone());
|
||||||
|
assert_eq!(ustr.get(&jlang).unwrap(), initial);
|
||||||
|
let err = ustr.get(&elang).unwrap_err();
|
||||||
|
match err.get_error_ids().iter().last().unwrap() {
|
||||||
|
ErrorID::MissingTranslation(missing) => {
|
||||||
|
assert_eq!(
|
||||||
|
missing.len(),
|
||||||
|
jdata.len(),
|
||||||
|
"should return list of translations needed"
|
||||||
|
);
|
||||||
|
let mut holder: HashSet<String> = jdata.iter().cloned().collect();
|
||||||
|
for data in missing.iter() {
|
||||||
|
assert_eq!(data.needs(), elang, "needed language is incorrect");
|
||||||
|
assert_eq!(data.has(), jlang, "original language is incorrect");
|
||||||
|
assert!(holder.contains(&data.text()));
|
||||||
|
holder.remove(&data.text());
|
||||||
|
}
|
||||||
|
assert!(holder.is_empty(), "still had {:?}", holder);
|
||||||
|
}
|
||||||
|
_ => unreachable!("got {:?}, should have been needs translation", err),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ mod mtterror;
|
|||||||
pub mod name;
|
pub mod name;
|
||||||
mod queue;
|
mod queue;
|
||||||
|
|
||||||
pub use action::*;
|
|
||||||
use document::{Clock, CreateDoc, Session};
|
use document::{Clock, CreateDoc, Session};
|
||||||
use message::{wrapper::Message, MessageAction};
|
use message::{wrapper::Message, MessageAction};
|
||||||
use queue::{
|
use queue::{
|
||||||
@@ -18,6 +17,8 @@ use std::{
|
|||||||
};
|
};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
pub use action::*;
|
||||||
|
pub use document::MissingTranslation;
|
||||||
pub use mtterror::{ErrorID, MTTError};
|
pub use mtterror::{ErrorID, MTTError};
|
||||||
pub use name::{Name, NameType};
|
pub use name::{Name, NameType};
|
||||||
pub use queue::data_director::{Include, Path};
|
pub use queue::data_director::{Include, Path};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
action::{Field, FieldType},
|
action::{Field, FieldType},
|
||||||
message::MessageAction,
|
message::MessageAction,
|
||||||
name::{Name, NameType},
|
name::{Name, NameType},
|
||||||
|
MissingTranslation,
|
||||||
};
|
};
|
||||||
use isolang::Language;
|
use isolang::Language;
|
||||||
use std::{collections::VecDeque, error::Error, fmt};
|
use std::{collections::VecDeque, error::Error, fmt};
|
||||||
@@ -21,6 +22,7 @@ pub enum ErrorID {
|
|||||||
FieldTypeExpected(FieldType),
|
FieldTypeExpected(FieldType),
|
||||||
IndexEntryAlreadyExists(Field),
|
IndexEntryAlreadyExists(Field),
|
||||||
InvalidFieldName(Name),
|
InvalidFieldName(Name),
|
||||||
|
MissingTranslation(Vec<MissingTranslation>),
|
||||||
NameAlreadyExists,
|
NameAlreadyExists,
|
||||||
NameLanguageNotUnique,
|
NameLanguageNotUnique,
|
||||||
NameNotFound(NameType),
|
NameNotFound(NameType),
|
||||||
|
|||||||
Reference in New Issue
Block a user