use std::sync::OnceLock;
pub mod cache;
pub mod formalization;
pub mod formatting;
pub mod http;
mod language_markers;
pub mod meaning;
pub mod pipeline;
pub mod prompt;
pub mod selection;
pub mod wikidata;
pub mod wiktionary;
pub use cache::CachedHttpClient;
pub use formalization::{
formalize_prompt, formalize_prompt_candidates, FormalizationAnchor, FormalizationAnchorKind,
FormalizationCandidate, FormalizationRole, FormalizationSlot,
};
pub use formatting::match_source_formatting;
pub use http::{CurlClient, HttpError};
pub(crate) use language_markers::{detect_source_language, detect_target_language};
pub use pipeline::{Translation, TranslationPipeline};
pub use prompt::extract_unquoted_translation_surface;
pub use selection::{
formalization_probability_target, select_formalization_candidate,
select_formalization_candidate_with_probability_store, softmax_formalization_scores,
FormalizationDecision, FormalizationSelection, FormalizationSelectionConfig,
FormalizationSelectionReason,
};
fn default_cached_client() -> &'static CachedHttpClient<CurlClient> {
static CLIENT: OnceLock<CachedHttpClient<CurlClient>> = OnceLock::new();
CLIENT.get_or_init(|| CachedHttpClient::new(cache::DEFAULT_CACHE_DIR, CurlClient::default()))
}
pub fn translate_via_default_pipeline(
surface: &str,
source: &str,
target: &str,
) -> Result<Translation, HttpError> {
let pipeline = TranslationPipeline::new(default_cached_client());
pipeline.translate(surface, source, target)
}
#[cfg(test)]
mod parity {
use super::{
detect_source_language, detect_target_language, extract_unquoted_translation_surface,
};
const BATTERY: &[(&str, &str, &str, &str)] = &[
("translate apple from english", "en", "-", "-"),
("переведи apple с английского", "en", "-", "-"),
("apple अंग्रेजी से", "en", "-", "-"),
("apple अंग्रेज़ी से", "en", "-", "-"),
("从英语翻译 apple", "en", "-", "-"),
("从英文翻译 apple", "en", "-", "-"),
("translate apple from russian", "ru", "-", "-"),
("apple с русского", "ru", "-", "-"),
("apple रूसी से", "ru", "-", "-"),
("从俄语翻译 apple", "ru", "-", "-"),
("translate apple from hindi", "hi", "-", "-"),
("apple हिंदी से", "hi", "-", "-"),
("apple हिन्दी से", "hi", "-", "-"),
("从印地语翻译 apple", "hi", "-", "-"),
("从印地文翻译 apple", "hi", "-", "-"),
("translate apple from chinese", "zh", "-", "-"),
("apple चीनी से", "zh", "-", "-"),
("从中文翻译 apple", "zh", "-", "-"),
("从汉语翻译 apple", "zh", "-", "-"),
("从漢語翻译 apple", "zh", "-", "-"),
("translate apple to english", "-", "en", "apple"),
("переведи apple на английский", "-", "en", "apple"),
("apple на английском", "-", "en", "-"),
("apple अंग्रेजी में", "-", "en", "-"),
("apple अंग्रेज़ी में", "-", "en", "-"),
("apple 成英文", "-", "en", "-"),
("apple 成英语", "-", "en", "-"),
("apple 为英文", "-", "en", "-"),
("apple 为英语", "-", "en", "-"),
("apple 為英文", "-", "en", "-"),
("apple 為英语", "-", "en", "-"),
("apple 到英文", "-", "en", "-"),
("apple 到英语", "-", "en", "-"),
("translate apple to russian", "-", "ru", "apple"),
("apple на русский", "-", "ru", "-"),
("apple 成俄语", "-", "ru", "-"),
("apple 成俄語", "-", "ru", "-"),
("apple 为俄语", "-", "ru", "-"),
("apple 为俄語", "-", "ru", "-"),
("apple 為俄语", "-", "ru", "-"),
("apple 為俄語", "-", "ru", "-"),
("apple 到俄语", "-", "ru", "-"),
("apple 到俄語", "-", "ru", "-"),
("translate apple to hindi", "-", "hi", "apple"),
("apple на хинди", "-", "hi", "-"),
("apple हिंदी में", "-", "hi", "-"),
("apple हिन्दी में", "-", "hi", "-"),
("apple 成印地语", "-", "hi", "-"),
("apple 成印地文", "-", "hi", "-"),
("apple 为印地语", "-", "hi", "-"),
("apple 为印地文", "-", "hi", "-"),
("apple 為印地语", "-", "hi", "-"),
("apple 為印地文", "-", "hi", "-"),
("apple 到印地语", "-", "hi", "-"),
("apple 到印地文", "-", "hi", "-"),
("translate apple to chinese", "-", "zh", "apple"),
("apple на китайский", "-", "zh", "-"),
("apple चीनी में", "-", "zh", "-"),
("apple 成中文", "-", "zh", "-"),
("apple 成汉语", "-", "zh", "-"),
("apple 成漢語", "-", "zh", "-"),
("apple 为中文", "-", "zh", "-"),
("apple 为汉语", "-", "zh", "-"),
("apple 为漢語", "-", "zh", "-"),
("apple 為中文", "-", "zh", "-"),
("apple 為汉语", "-", "zh", "-"),
("apple 為漢語", "-", "zh", "-"),
("apple 到中文", "-", "zh", "-"),
("apple 到汉语", "-", "zh", "-"),
("apple 到漢語", "-", "zh", "-"),
(
"translate apple from english to russian",
"en",
"ru",
"apple from english",
),
(
"переведи яблоко с английского на русский",
"en",
"ru",
"яблоко с английского",
),
("把 apple 从中文 翻译成英文", "zh", "en", "apple 从中文"),
("translate apple to russian", "-", "ru", "apple"),
("Translate Apple to Russian", "-", "ru", "Apple"),
("translate apple to russian.", "-", "ru", "apple"),
("translate \"apple\" to russian", "-", "ru", "-"),
("translate apple", "-", "-", "-"),
("what is apple", "-", "-", "-"),
(
"translate the red apple to russian",
"-",
"ru",
"the red apple",
),
("переведи яблоко на английский", "-", "en", "яблоко"),
(
"переведи красное яблоко на английский",
"-",
"en",
"красное яблоко",
),
("apple का हिंदी में अनुवाद करो", "-", "hi", "apple"),
("सेब को अंग्रेजी में अनुवाद करो", "-", "en", "सेब"),
("apple का हिंदी मे अनुवाद करो", "-", "-", "apple"),
("把 apple 翻译成中文", "-", "zh", "apple"),
("将苹果翻译成英文", "-", "en", "苹果"),
("翻译 apple 成中文", "-", "zh", "apple"),
("把 apple 翻译为英文", "-", "en", "apple"),
("把 apple 翻译到英文", "-", "en", "apple"),
("apple с хинди", "hi", "-", "-"),
("apple с китайского", "zh", "-", "-"),
("apple रूसी में", "-", "ru", "-"),
];
fn opt(sentinel: &str) -> Option<&str> {
(sentinel != "-").then_some(sentinel)
}
#[test]
fn translation_cluster_matches_frozen_behaviour() {
for &(prompt, source, target, surface) in BATTERY {
let normalized = prompt.to_lowercase();
assert_eq!(
detect_source_language(&normalized),
opt(source),
"source language mismatch for {prompt:?}"
);
assert_eq!(
detect_target_language(&normalized),
opt(target),
"target language mismatch for {prompt:?}"
);
assert_eq!(
extract_unquoted_translation_surface(prompt).as_deref(),
opt(surface),
"extracted surface mismatch for {prompt:?}"
);
}
}
}