use serde_json::Value;
use super::DpTran;
use super::connection;
use super::DeeplAPIError;
use super::ApiKeyType;
#[derive(Debug, PartialEq, Clone, serde::Serialize, serde::Deserialize)]
pub struct Language {
pub language: String,
pub name: String,
pub supports_formality: Option<bool>,
}
pub type LangCodeName = (String, String);
#[derive(Debug, PartialEq)]
pub enum LangType {
Source,
Target,
}
pub const DEEPL_API_LANGUAGES: &str = "https://api-free.deepl.com/v2/languages";
pub const DEEPL_API_LANGUAGES_PRO: &str = "https://api.deepl.com/v2/languages";
pub static EXTENDED_LANG_CODES: [(&str, &str, LangType); 2] = [
("EN", "English", LangType::Target),
("PT", "Portuguese", LangType::Target),
];
fn get_languages_list(json: &String) -> Result<Vec<Language>, DeeplAPIError> {
let langs: Vec<Language> = serde_json::from_str(&json).map_err(|e| DeeplAPIError::JsonError(e.to_string(), json.clone()))?;
Ok(langs)
}
fn json_to_vec(json: &String, type_name: &String) -> Result<Vec<LangCodeName>, DeeplAPIError> {
let v: Value = serde_json::from_str(&json).map_err(|e| DeeplAPIError::JsonError(e.to_string(), json.clone()))?;
let lang_type = if type_name == "source" {
LangType::Source
} else if type_name == "target" {
LangType::Target
} else {
return Err(DeeplAPIError::InvalidLangTypeError(type_name.clone()));
};
let mut lang_codes: Vec<LangCodeName> = Vec::new();
let v_array = v.as_array();
if let None = v_array {
if v.to_string().contains("Wrong endpoint") {
return Err(DeeplAPIError::WrongEndPointError(v.to_string()));
}
return Err(DeeplAPIError::JsonError(v.to_string(), json.clone()));
}
let langs = get_languages_list(&json)?;
for lang in langs.iter() {
match lang_type {
LangType::Source => {
lang_codes.push((lang.language.clone(), lang.name.clone()));
},
LangType::Target => {
lang_codes.push((lang.language.clone(), lang.name.clone()));
},
}
}
for i in 0..EXTENDED_LANG_CODES.len() {
if EXTENDED_LANG_CODES[i].2 == lang_type {
if lang_codes.iter().any(|x| x.0 == EXTENDED_LANG_CODES[i].0 && x.1 == EXTENDED_LANG_CODES[i].1) {
continue;
}
lang_codes.push((EXTENDED_LANG_CODES[i].0.to_string(), EXTENDED_LANG_CODES[i].1.to_string()));
}
}
Ok(lang_codes)
}
pub fn get_language_codes(api: &DpTran, type_name: String) -> Result<Vec<LangCodeName>, DeeplAPIError> {
let url = if api.api_key_type == ApiKeyType::Free {
api.api_urls.languages_for_free.clone()
} else {
api.api_urls.languages_for_pro.clone()
};
let url = format!("{}?type={}", url, type_name);
let header_auth_key = format!("Authorization: DeepL-Auth-Key {}", api.api_key);
let headers = vec![header_auth_key];
let res = connection::get_with_headers(url, &headers).map_err(|e| DeeplAPIError::ConnectionError(e))?;
let mut lang_codes = json_to_vec(&res, &type_name)?;
lang_codes.sort_by(|a, b| a.0.cmp(&b.0));
if lang_codes.len() == 0 {
Err(DeeplAPIError::GetLanguageCodesError)
} else {
Ok(lang_codes)
}
}
pub fn get_languages_as_struct(api: &DpTran, type_name: String) -> Result<Vec<Language>, DeeplAPIError> {
let url = if api.api_key_type == ApiKeyType::Free {
api.api_urls.languages_for_free.clone()
} else {
api.api_urls.languages_for_pro.clone()
};
let url = format!("{}?type={}", url, type_name);
let header_auth_key = format!("Authorization: DeepL-Auth-Key {}", api.api_key);
let headers = vec![header_auth_key];
let res = connection::get_with_headers(url, &headers).map_err(|e| DeeplAPIError::ConnectionError(e))?;
let result = get_languages_list(&res)?;
Ok(result)
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
fn impl_json_to_vec() {
let json = r#"[{"language":"EN","name":"English","supports_formality":false},{"language":"DE","name":"German","supports_formality":true}]"#.to_string();
let res = json_to_vec(&json, &"source".to_string());
match res {
Ok(res) => {
assert_eq!(res[0], ("EN".to_string(), "English".to_string()));
assert_eq!(res[1], ("DE".to_string(), "German".to_string()));
},
Err(e) => {
panic!("Error: {}", e);
}
}
}
#[test]
fn api_sorted_languages_test() {
let (api_key, api_key_type) = super::super::super::tests::get_api_key();
let api = DpTran::with_endpoint(&api_key, &api_key_type, super::super::super::tests::get_endpoint());
let res = get_language_codes(&api, "source".to_string());
match res {
Ok(res) => {
if res.len() == 0 {
panic!("Error: language codes is empty");
}
for i in 0..res.len()-1 {
if res[i].0 > res[i+1].0 {
panic!("Error: language codes are not sorted");
}
}
},
Err(e) => {
panic!("Error: {}", e);
}
}
let res = get_language_codes(&api, "source".to_string());
match res {
Ok(res) => {
let mut found = false;
for i in 0..EXTENDED_LANG_CODES.len() {
if res.iter().any(|x| x.0 == EXTENDED_LANG_CODES[i].0 && x.1 == EXTENDED_LANG_CODES[i].1) {
found = true;
break;
}
}
if !found {
panic!("Error: extended language codes not found");
}
},
Err(e) => {
panic!("Error: {}", e);
}
}
let res = get_language_codes(&api, "source".to_string());
match res {
Ok(res) => {
for i in 0..res.len()-1 {
if res[i].0 > res[i+1].0 {
panic!("Error: language codes are not sorted");
}
}
},
Err(e) => {
panic!("Error: {}", e);
}
}
let res = get_language_codes(&api, "target".to_string());
match res {
Ok(res) => {
if res.len() == 0 {
panic!("Error: language codes is empty");
}
for i in 0..res.len()-1 {
if res[i].0 > res[i+1].0 {
panic!("Error: language codes are not sorted");
}
}
},
Err(e) => {
panic!("Error: {}", e);
}
}
let res = get_language_codes(&api, "target".to_string());
match res {
Ok(res) => {
let mut found = false;
for i in 0..EXTENDED_LANG_CODES.len() {
if res.iter().any(|x| x.0 == EXTENDED_LANG_CODES[i].0 && x.1 == EXTENDED_LANG_CODES[i].1) {
found = true;
break;
}
}
if !found {
panic!("Error: extended language codes not found");
}
},
Err(e) => {
panic!("Error: {}", e);
}
}
let res = get_language_codes(&api, "target".to_string());
match res {
Ok(res) => {
for i in 0..res.len()-1 {
if res[i].0 > res[i+1].0 {
panic!("Error: language codes are not sorted");
}
}
},
Err(e) => {
panic!("Error: {}", e);
}
}
}
#[test]
fn api_get_languages_as_struct_test() {
let (api_key, api_key_type) = super::super::super::tests::get_api_key();
let api = DpTran::with_endpoint(&api_key, &api_key_type, super::super::super::tests::get_endpoint());
let res = get_languages_as_struct(&api, "source".to_string());
match res {
Ok(res) => {
if res.len() == 0 {
panic!("Error: languages is empty");
}
},
Err(e) => {
panic!("Error: {}", e);
}
}
}
}