1pub use self::model::Lang;
2
3pub use self::model::PapagoReq;
4
5use crate::config::NaverAuth;
6
7mod model;
8
9pub const NMT_URL: &'static str = "https://openapi.naver.com/v1/papago/n2mt";
11pub const SMT_URL: &'static str = "https://openapi.naver.com/v1/language/translate";
13
14#[derive(PartialEq)]
16pub enum Error {
17 WrongPayload,
18 ReqFail,
19 RespParseFail,
20 PapagoError(String),
21}
22
23impl std::fmt::Debug for Error {
24 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
25 match self {
26 Error::WrongPayload => write!(f, "Request payload is not correct"),
27 Error::ReqFail => write!(
28 f,
29 "Request has failed. Maybe check your internet connection."
30 ),
31 Error::RespParseFail => write!(
32 f,
33 "Response was not something expected. Please report if it's a bug"
34 ),
35 Error::PapagoError(msg) => write!(f, "{}", msg),
36 }
37 }
38}
39
40pub fn send_request(
63 url: &'static str,
64 auth: &NaverAuth,
65 payload: model::PapagoReq,
66) -> Result<String, Error> {
67 let body = serde_urlencoded::to_string(&payload).or_else(|_| Err(Error::WrongPayload))?;
68
69 let client = reqwest::Client::new();
70 let mut resp = client
71 .post(url)
72 .header("X-Naver-Client-Id", auth.client_id.clone())
73 .header("X-Naver-Client-Secret", auth.client_secret.clone())
74 .header("Content-Type", "application/x-www-form-urlencoded")
75 .body(body)
76 .send()
77 .or(Err(Error::ReqFail))?;
78
79 let response: model::PapagoResponse = resp.json().or(Err(Error::RespParseFail))?;
80
81 match response {
82 model::PapagoResponse::Success { message } => Ok(message.result.translated_text),
83 model::PapagoResponse::Fail {
84 error_message,
85 error_code: _error_code,
86 } => Err(Error::PapagoError(error_message)),
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use crate::config;
94
95 #[test]
96 #[allow(non_snake_case)]
97 fn test_send_NMT_request() {
98 let auth = config::get_auth_from_env().unwrap();
99 let payload = model::PapagoReq {
100 source: model::Lang::En,
101 target: model::Lang::Ko,
102 text: "HELLO WORLD".to_owned(),
103 };
104 let result = send_request(NMT_URL, &auth, payload);
105 assert_eq!(result.unwrap(), "안녕 세계".to_owned());
106 }
107
108 #[test]
109 #[allow(non_snake_case)]
110 fn test_wrong_NMT_request__same_source_target() {
111 let auth = config::get_auth_from_env().unwrap();
112 let payload = model::PapagoReq {
113 source: model::Lang::En,
114 target: model::Lang::En,
115 text: "HELLO WORLD".to_owned(),
116 };
117 let result = send_request(NMT_URL, &auth, payload);
118 assert_eq!(
119 result.unwrap_err(),
120 Error::PapagoError(
121 "source and target must be different (source와 target이 동일합니다.)"
122 .to_owned()
123 )
124 );
125 }
126
127 #[test]
128 #[allow(non_snake_case)]
129 fn test_wrong_NMT_request__wrong_lang_combo() {
130 let auth = config::get_auth_from_env().unwrap();
131 let payload = model::PapagoReq {
132 source: model::Lang::Vi,
133 target: model::Lang::Es,
134 text: "HELLO WORLD".to_owned(),
135 };
136 let result = send_request(NMT_URL, &auth, payload);
137 assert_eq!(
138 result.unwrap_err(),
139 Error::PapagoError(
140"There is no source-to-target translator (source->target 번역기가 없습니다.)"
141 .to_owned()
142 )
143 );
144 }
145
146 #[test]
147 #[allow(non_snake_case)]
148 fn test_send_SMT_request() {
149 let auth = config::get_auth_from_env().unwrap();
150 let payload = model::PapagoReq {
151 source: model::Lang::En,
152 target: model::Lang::Ko,
153 text: "HELLO WORLD".to_owned(),
154 };
155 let result = send_request(SMT_URL, &auth, payload);
156 assert_eq!(result.unwrap(), "안녕 세계".to_owned());
157 }
158}