5个不稳定版本
0.3.0 | 2024年4月21日 |
---|---|
0.2.1 | 2023年9月13日 |
0.2.0 | 2023年7月20日 |
0.1.1 | 2023年7月13日 |
0.1.0 | 2023年7月12日 |
#101 在 HTTP客户端
每月56次下载
60KB
958 行
deeprl
通过一个快速可靠的接口访问DeepL翻译引擎。我们旨在提供DeepL提供的全部工具套件。请参阅DeepL API文档以获取详细资源。
注意
此crate使用阻塞HTTP客户端,因此仅适用于同步(阻塞)应用程序。如果您打算在异步应用程序中使用库函数,有一个crate适合该用途。
快速入门
创建一个新的客户端,使用有效的API令牌访问相关方法。例如,您可能希望将简单的文本字符串翻译成某种目标语言。
use deeprl::{DeepL, Language, TextOptions};
let key = std::env::var("DEEPL_API_KEY").unwrap();
let dl = DeepL::new(&key);
// Translate 'good morning' to German
let opt = TextOptions::new(Language::DE);
let text = vec![
"good morning".to_string(),
];
let result = dl.translate(opt, text).unwrap();
assert!(!result.translations.is_empty());
let translation = &result.translations[0];
assert_eq!(translation.text, "Guten Morgen");
作为一个有用的健全性检查,确保您能够返回账户使用统计信息。
use deeprl::DeepL;
let dl = DeepL::new(
&std::env::var("DEEPL_API_KEY").unwrap()
);
let usage = dl.usage().unwrap();
assert!(usage.character_limit > 0);
let count = usage.character_count;
let limit = usage.character_limit;
println!("Used: {count}/{limit}");
// Used: 42/500000
教程
内容
配置
库支持许多配置选项,其中之一是能够用新的reqwest::blocking::Client
实例替换默认客户端。
与之前一样,我们创建了一个新的DeepL
实例,但这次我们声明它为mut
。然后我们在对象上调用client
并传入我们的自定义客户端。
let mut dl = DeepL::new(
&std::env::var("DEEPL_API_KEY").unwrap()
);
let client = reqwest::blocking::Client::builder()
.timeout(std::time::Duration::from_secs(21))
.build()
.unwrap();
dl.client(client);
我们支持在请求中发送自定义用户代理。例如,如果您在其他应用程序中使用此库,例如My App v1.2.3,您可以使用set_app_info
设置应用程序名称和版本。
dl.set_app_info(
"my-app/1.2.3".to_string()
);
错误
错误封装在Error
枚举中,其变体可能为以下之一
Client
:通用的客户端错误Server
:服务器发送的错误Deserialize
:反序列化响应时发生错误InvalidRequest
:发送HTTP请求时出错InvalidResponse
:解析响应时出错InvalidLanguage
:错误匹配用户提供的字符串到Language
下面我们将要查看的库函数都是DeepL
客户端的方法,许多函数返回一个Result
类型(枚举),这个类型要么解析为我们期望的类型,要么是上述的Error
之一。因此,对于某些类型T
,返回一个结果的函数类型是Result<T, Error>
。虽然在我们提供的例子中我们使用unwrap
来展开Result
以提取值,但在生产代码中实现更健壮的错误处理是常见的。
获取语言
获取可用languages
需要指定LanguageType
为Source
或Target
,并返回一个Result
,其成功值是一个包含Vec<LanguageInfo>
的向量。
所有LanguageInfo
实例都包含language
和name
属性。目标语言包含第三个字段,supports_formality
,该字段为true
或false
。
let source_langs = dl.languages(LanguageType::Source).unwrap();
for lang in source_langs {
let code = lang.language;
let name = lang.name;
println!("{code} {name}");
// BG Bulgarian
}
文本翻译选项
翻译文本可以通过TextOptions
构建器设置多个选项,其中之一是必需的,即翻译的target_lang
。
文本翻译的选项列表如下
target_lang
:翻译的目标Language
(必需)source_lang
:源Language
split_sentences
:决定如何从输入文本中分割句子。可以是以下之一SplitSentences::None
不分割句子。SplitSentences::Default
在标点符号和新行处分割(默认)。SplitSentences::NoNewLines
仅在标点符号处分割。
preserve_formatting
:翻译器是否应保留文本的原始格式。(默认false
)formality
:在目标语言中期望的正式程度。并非所有目标语言都支持正式程度。选项包括正式程度::默认
正式程度::更正式
正式程度::不太正式
正式程度::更倾向于正式
正式程度::更倾向于不正式
glossary_id
:用于翻译的术语表IDString
标签处理
以下是与标签处理相关的翻译选项
tag_handling
:启用处理输入文本中的标签。可以是以下之一标签处理::XML
标签处理::HTML
outline_detection
:翻译器是否应自动检测大纲(默认true
)splitting_tags
:用于分割句子的逗号分隔的标签列表,例如 "head,title,body"String
non_splitting_tags
:不分割句子的逗号分隔的标签列表,String
ignore_tags
:逗号分隔的不要翻译的标签列表,String
以下是一个更复杂的翻译示例,其中我们希望指定源语言,忽略输入中的换行符,保留格式,并设置所需的正式程度。我们还将使用自定义词汇表,确保提供的词汇表与翻译的源语言和目标语言相匹配。
函数 translate
需要两个参数:一个 TextOptions
对象,以及一个包含一个或多个待翻译文本的 Vec<String>
。它返回一个 Result
,其 Ok
值是一个包含单个字段 translations
的 TranslateTextResult
,该字段包含一个 Vec<Translation>
。
// Translate 'you are nice' to French
let text = vec![
"you are nice".to_string(),
];
let opt = TextOptions::new(Language::FR) // note `new` expects the required target lang
.source_lang(Language::EN)
.formality(Formality::PreferLess)
let result = dl.translate(opt, text).unwrap();
let translation = &result.translations[0];
println!("{}", translation.text);
// tu es gentille
Translation
有两个属性:包含翻译文本字符串的 text
和包含由服务器检测到的源语言语言代码的字符串 detected_source_language
。
以下是一个示例,其中输入包含 xml,我们只想翻译 <p>
标签内的内容。
let xml = r"
<xml>
<head>
<title>My English title</title>
</head>
<body>
<p>The red crab</p>
<p>Do you speak French?</p>
</body>
</xml>"
.to_string();
let text = vec![xml];
let split = "p".to_string(); // split on <p> tags
let ignore = "title".to_string(); // ignore <title> tags
let opt = TextOptions::new(Language::FR)
.source_lang(Language::EN)
.tag_handling(TagHandling::Xml)
.outline_detection(false)
.splitting_tags(split)
.ignore_tags(ignore);
let result = dl.translate(opt, text).unwrap();
let text = &result.translations[0].text;
assert!(text.contains("My English title"));
assert!(text.contains("Le crabe rouge"));
翻译文档
翻译文档包括三个步骤:1)上传文档,2)轮询正在进行的翻译状态,3)请求下载翻译后的文档。
首先,我们创建一个 DocumentOptions
实例,这需要我们知道目标语言以及存储在本地且格式受支持的文档的文件路径。文档选项列表如下
target_lang
:翻译的目标Language
(必需)file_path
:源文件的路径作为PathBuf
(必需)source_lang
:源Language
filename
:文件名,String
formality
:正式程度偏好,可以是以下之一正式程度::默认
正式程度::更正式
正式程度::不太正式
正式程度::更倾向于正式
正式程度::更倾向于不正式
glossary_id
:用于翻译的词汇表的 id,String
// Upload a file in the current directory called 'test.txt'
let target_lang = Language::DE;
let file_path = std::path::PathBuf::from("test.txt");
let opt = DocumentOptions::new(target_lang, file_path);
let doc = dl.document_upload(opt).unwrap();
println!("Document Id: {}", doc.document_id);
println!("Document Key: {}", doc.document_key);
document_upload
期望一个 DocumentOptions
实例,并返回一个 Result
,其 Ok
值是一个包含两个字段的 Document
处理程序:作为字符串的 document_id
和 document_key
。
在我们能够下载完成的文档之前,我们需要检查翻译过程的状态。我们通过在客户端调用 document_status
并传递我们之前收到的 Document
处理程序的引用来实现这一点。该方法返回一个 Result<DocumentStatus>
,其中 DocumentStatus
是一个具有以下字段的结构体
document_id
:唯一的文档 id,String
status
:一个枚举,DocState
在以下状态之一DocState::Queued
DocState::Translating
DocState::Done
DocState::Error
seconds_remaining
:翻译完成预计剩余时间,Option<u64>
billed_characters
:计费字符数,Option<u64>
error_message
:错误情况下来自服务器的消息Option<String>
翻译完成后,status
将处于DocState::Done
状态,在我们的DocumentStatus
对象上调用is_done
将返回true。然后我们可以进行下载。
// Get the status of a document translation in progress
let status = dl.document_status(&doc).unwrap();
if status.is_done() {
// Download translation result
let out_file = PathBuf::from("test-translated.txt");
let _ = dl.document_download(doc, Some(out_file.clone())).unwrap();
let content = std::fs::read_to_string(out_file).unwrap();
assert(!content.is_empty());
}
document_download
函数接受作为参数的是我们在上传后收到的相同的Document
句柄,以及一个表示完成文档将保存的文件路径的可选PathBuf
。该函数返回一个Result<PathBuf>
,其中PathBuf
是新翻译文档的路径。
如果用户提供的输出文件路径为None
,将在当前目录中创建一个文件,其名称包含唯一的document_id
。
术语表
DeepL支持为多个语言对创建自定义术语表,允许用户指定用于源文本中给定单词的确切翻译。为了演示,首先我们将查询支持的术语表语言对列表。
glossary_languages
方法不接受任何参数,并返回一个Result<GlossaryLanguagePairsResult>
,其Ok
值有一个单字段,即supported_languages
,它包含一个Vec<GlossaryLanguagePair>
。
GlossaryLanguagePair
包含两个字段:作为字符串的source_lang
和target_lang
。
// Get supported glossary language pairs
let result = dl.glossary_languages().unwrap();
let lang_pairs = result.supported_languages;
assert!(!lang_pairs.is_empty());
for pair in lang_pairs {
println!("{} -> {}", pair.source_lang, pair.target_lang);
// EN -> IT
}
现在,让我们创建一个源语言为英语、目标语言为意大利的术语表。为此,我们将创建一个名为my_glossary.csv的文件来保存术语表条目。条目格式为逗号分隔列表,有两列(源,目标),每行一个条目。因此,包含两个术语表条目的csv文件如下所示
my_glossary.csv
hello,ciao
goodbye,ciao
在rust中,我们将文件内容读取到名为entries
的字符串中,并将其与以下参数一起传递给glossary_new
(注意,DeepL还接受作为制表符分隔值的术语表条目)
name: String
source_lang:Language
target_lang:Language
entries: String
fmt
:我们的条目格式,必须是以下之一GlossaryEntriesFormat::Csv
GlossaryEntriesFormat::Tsv
glossary_new
返回一个Result<Glossary>
,其中Glossary
是一个具有以下字段的struct
glossary_id: String
ready: bool
name: String
source_lang: String
target_lang: String
creation_time: String
entry_count: u64
// Create a new glossary
let name = "my_glossary".to_string();
let src = Language::EN;
let trg = Language::IT;
let entries = std::fs::read_to_string("my_glossary.csv").unwrap();
let fmt = GlossaryEntriesFormat::Csv;
let glossary = dl.glossary_new(name, src, trg, entries, fmt).unwrap();
assert_eq!(glossary.entry_count, 2);
let glos_id = glossary.glossary_id; // remember this!
// List glossaries
let result = dl.glossaries().unwrap();
let glossaries = result.glossaries;
assert!(!glossaries.is_empty());
列出可用的glossaries
返回一个Result<GlossariesResult>
,其内部值有一个属性glossaries
,它包含一个Vec<Glossary>
。
我们可以通过不同的方式从术语表中获取信息。使用有效的glossary_id
调用glossary_info
将返回一个包含上述属性的Result<Glossary>
。此方法仅返回术语表元数据。
要获取实际的条目,我们使用带有有效 glossary_id
的 glossary_entries
方法。该函数返回一个 Result<HashMap<String, String>>
,其中 Ok
的值是一个将唯一源词映射到其目标翻译的集合。
// Get glossary info
// recall `glos_id` is the glossary id we obtained earlier
let glossary = dl.glossary_info(&glos_id).unwrap();
println!("{}", glossary.name);
// my_glossary
// Get entries from a glossary
let entries = dl.glossary_entries(&glos_id).unwrap();
for (key, value) in entries {
println!("{key} {value}");
/*
hello ciao
goodbye ciao
*/
}
// Remove an unwanted glossary
let result = dl.glossary_delete(&glos_id);
assert!(result.is_ok());
要删除术语表,调用 glossary_delete
方法并传递 glossary_id
的引用。该函数返回 Result<()>
,其中成功值是一个空元组。
依赖关系
~4–15MB
~229K SLoC