deepl_rustls/endpoint/
languages.rs

1use super::{Error, Result};
2use crate::DeepLApi;
3use serde::Deserialize;
4
5/// Information about a supported language
6#[derive(Deserialize)]
7pub struct LangInfo {
8    /// Language code
9    pub language: String,
10    /// Language name
11    pub name: String,
12    /// Denotes a target language supports formality
13    pub supports_formality: Option<bool>,
14}
15
16/// Language type used to request supported languages
17#[derive(Debug)]
18pub enum LangType {
19    /// Source language
20    Source,
21    /// Target language
22    Target,
23}
24
25impl AsRef<str> for LangType {
26    fn as_ref(&self) -> &str {
27        match self {
28            Self::Source => "source",
29            Self::Target => "target",
30        }
31    }
32}
33
34impl DeepLApi {
35    ///
36    /// Retrieve supported languages for a given [`LangType`]
37    ///
38    /// # Example
39    ///
40    /// ```rust
41    /// let target_langs = deepl.languages(LangType::Target).await.unwrap();
42    /// assert!(!target_langs.is_empty());
43    ///
44    /// let lang = target_langs.first().unwrap();
45    /// println!("{}", lang.language); // BG
46    /// println!("{}", lang.name); // Bulgarian
47    /// ```
48    pub async fn languages(&self, lang_type: LangType) -> Result<Vec<LangInfo>> {
49        let q = vec![("type", lang_type.as_ref())];
50
51        let resp = self
52            .get(self.get_endpoint("languages"))
53            .query(&q)
54            .send()
55            .await
56            .map_err(|err| Error::RequestFail(err.to_string()))?;
57
58        if !resp.status().is_success() {
59            return super::extract_deepl_error(resp).await;
60        }
61
62        resp.json().await.map_err(|err| {
63            Error::InvalidResponse(format!("convert json bytes to Rust type: {err}"))
64        })
65    }
66}
67
68#[tokio::test]
69async fn test_get_languages() {
70    let deepl = DeepLApi::with(&std::env::var("DEEPL_API_KEY").unwrap()).new();
71
72    let langs = deepl.languages(LangType::Target).await.unwrap();
73    assert!(!langs.is_empty());
74}
75
76#[tokio::test]
77async fn test_generate_langs() {
78    use crate::Lang;
79    let deepl = DeepLApi::with(&std::env::var("DEEPL_API_KEY").unwrap()).new();
80
81    // fetch source langs
82    let source_langs = deepl.languages(LangType::Source).await.unwrap();
83    let codes: Vec<&str> = source_langs.iter().map(|l| l.language.as_str()).collect();
84
85    // fetch target langs, filtering same lang code
86    let mut target_langs = deepl.languages(LangType::Target).await.unwrap();
87    target_langs.retain(|l| !codes.contains(&l.language.as_str()));
88
89    // iterate `LangInfo`s and try to create a `Lang`.
90    // prints the missing lang to stdout in case of error
91    let _: Vec<Lang> = source_langs
92        .into_iter()
93        .chain(target_langs)
94        .map(|l| {
95            let code = &l.language;
96            let name = &l.name;
97            Lang::try_from(code)
98                .map_err(|_| println!("Failed to convert lang: {code} {name}"))
99                .unwrap()
100        })
101        .collect();
102}