deeplx 2.2.6

A Rust package for unlimited DeepL translation
Documentation
use std::{future::Future, pin::Pin, sync::Arc};

use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use deeplx::DeepLXTranslationResult;
use serde::Serialize;

use crate::server::pkgs::{Error, Json};

pub trait TranslateRepo: Send + Sync {
    fn translate<'a>(
        &'a self,
        text: &'a str,
        source_lang: &'a str,
        target_lang: &'a str,
        dl_session: Option<&'a str>,
    ) -> Pin<Box<dyn Future<Output = Result<DeepLXTranslationResult, Error>> + Send + 'a>>;
}

pub struct TranslateUsecase {
    repo: Arc<dyn TranslateRepo>,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct TranslateResult {
    pub code: u16,
    pub id: i64,
    pub data: String,
    pub alternatives: Vec<String>,
    pub source_lang: String,
    pub target_lang: String,
    pub method: String,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct TranslateResultUnknown {
    pub code: u16,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct Translation {
    pub detected_source_language: String,
    pub text: String,
}

#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub struct TranslateResultOfficial {
    pub translations: Vec<Translation>,
}

impl TranslateUsecase {
    pub fn new(repo: Arc<dyn TranslateRepo>) -> Self {
        Self { repo }
    }

    pub async fn translate(
        &self,
        text: &str,
        source_lang: &str,
        target_lang: &str,
        dl_session: Option<&str>,
    ) -> Result<Response, Error> {
        let res = self
            .repo
            .translate(text, source_lang, target_lang, dl_session)
            .await?;

        match res.code {
            200 => Ok(Json(TranslateResult {
                code: res.code as u16,
                id: res.id,
                data: res.data,
                alternatives: res.alternatives,
                source_lang: res.source_lang,
                target_lang: res.target_lang,
                method: res.method,
            })
            .with_status_code(StatusCode::OK)
            .into_response()),
            _ => Ok(Json(TranslateResultUnknown {
                code: res.code as u16,
                message: res.message,
            })
            .with_status_code(
                StatusCode::from_u16(res.code as u16).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
            )
            .into_response()),
        }
    }

    pub async fn translate_official(
        &self,
        text: &str,
        target_lang: &str,
    ) -> Result<Response, Error> {
        let res = self.repo.translate(text, "auto", target_lang, None).await?;

        match res.code {
            200 => Ok(Json(TranslateResultOfficial {
                translations: vec![Translation {
                    detected_source_language: res.source_lang,
                    text: res.data,
                }],
            })
            .with_status_code(StatusCode::OK)
            .into_response()),
            _ => Ok(Json(TranslateResultUnknown {
                code: res.code as u16,
                message: res.message,
            })
            .with_status_code(
                StatusCode::from_u16(res.code as u16).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
            )
            .into_response()),
        }
    }
}