Skip to content

Commit 59ffb65

Browse files
committed
refactor: Move translate options to separate file
1 parent 84e5425 commit 59ffb65

File tree

2 files changed

+293
-287
lines changed

2 files changed

+293
-287
lines changed

api/options.go

Lines changed: 293 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,293 @@
1+
package deepl
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
type TranslateOptions map[string]string
8+
9+
func (o TranslateOptions) Gather(opts ...TranslateOptionFunc) error {
10+
for _, optfunc := range opts {
11+
if err := optfunc(o); err != nil {
12+
return err
13+
}
14+
}
15+
return nil
16+
}
17+
18+
// TranslateOptionFunc can be used to customize the translation engine.
19+
type TranslateOptionFunc func(TranslateOptions) error
20+
21+
func translateOptionInvalidValueError(name string, value string) error {
22+
return fmt.Errorf("Invalid value for option `%s`: %s", name, value)
23+
}
24+
25+
// WithSourceLang specifies the language of the text to be translated.
26+
// If this parameter is omitted, the API will attempt to detect the language of the text and translate it
27+
func WithSourceLang(value string) TranslateOptionFunc {
28+
const name string = "source_lang"
29+
return func(o TranslateOptions) error {
30+
o[name] = value
31+
return nil
32+
}
33+
}
34+
35+
// WithSplitSentences sets whether the translation engine should first split
36+
// the input into sentences.
37+
//
38+
// For text translations where `tag_handling` is not set to `html`, the default
39+
// value is `1`, meaning the engine splits on punctuation and on newlines.
40+
// For text translations where `tag_handling=html`, the default value is
41+
// `nonewlines`, meaning the engine splits on punctuation only, ignoring
42+
// newlines.
43+
//
44+
// The use of `nonewlines` as the default value for text translations where
45+
// `tag_handling=html` is new behavior that was implemented in November 2022,
46+
// when HTML handling was moved out of beta.
47+
//
48+
// Possible values are:
49+
//
50+
// `0` - no splitting at all, whole input is treated as one sentence
51+
// `1` - splits on punctuation and on newlines (default when `tag_handling` is not set to `html`)
52+
// `nonewlines` - splits on punctuation only, ignoring newlines (default when `tag_handling=html`)
53+
//
54+
// For applications that send one sentence per text parameter, we recommend
55+
// setting `split_sentences` to `0`, in order to prevent the engine from splitting
56+
// the sentence unintentionally.
57+
//
58+
// Please note that newlines will split sentences when `split_sentences=1`. We
59+
// recommend cleaning files so they don't contain breaking sentences or setting
60+
// the parameter `split_sentences` to `nonewlines`.
61+
func WithSplitSentences(value string) TranslateOptionFunc {
62+
const name string = "split_sentence"
63+
return func(o TranslateOptions) error {
64+
switch value {
65+
case "0", "1", "nonewlines":
66+
o[name] = value
67+
return nil
68+
}
69+
return translateOptionInvalidValueError(name, value)
70+
}
71+
}
72+
73+
// WithPreserveFormatting sets whether the translation engine should respect
74+
// the original formatting, even if it would usually correct some aspects.
75+
//
76+
// The formatting aspects affected by this setting include:
77+
// - Punctuation at the beginning and end of the sentence
78+
// - Upper/lower case at the beginning of the sentence
79+
func WithPreserveFormatting(value string) TranslateOptionFunc {
80+
const name string = "preserve_formatting"
81+
return func(o TranslateOptions) error {
82+
switch value {
83+
case "0", "1":
84+
o[name] = value
85+
return nil
86+
}
87+
return translateOptionInvalidValueError(name, value)
88+
}
89+
}
90+
91+
// WithFormality sets whether the translated text should lean towards formal or
92+
// informal language.
93+
//
94+
// This feature currently only works for target languages DE (German), FR
95+
// (French), IT (Italian), ES (Spanish), NL (Dutch), PL (Polish), PT-BR and
96+
// PT-PT (Portuguese), JA (Japanese), and RU (Russian).
97+
// Learn more about the plain/polite feature for Japanese [here][formality-japanese].
98+
//
99+
// Setting this parameter with a target language that does not support
100+
// formality will fail, unless one of the `prefer_...` options are used.
101+
//
102+
// Possible options are:
103+
// - `default` (default)
104+
// - `more` - for a more formal language
105+
// - `less` - for a more informal language
106+
// - `prefer_more` - for a more formal language if available, otherwise fallback to default formality
107+
// - `prefer_less` - for a more informal language if available, otherwise fallback to default formality
108+
//
109+
// [formality-japanese]: https://support.deepl.com/hc/en-us/articles/6306700061852-About-the-plain-polite-feature-in-Japanese
110+
func WithFormality(value string) TranslateOptionFunc {
111+
const name string = "formality"
112+
return func(o TranslateOptions) error {
113+
switch value {
114+
case "default", "more", "less", "prefer_more", "prefer_less":
115+
o[name] = value
116+
return nil
117+
}
118+
return translateOptionInvalidValueError(name, value)
119+
}
120+
}
121+
122+
// WithGlossaryId specifies the glossary to use for the translation.
123+
//
124+
// *Important*: This requires the `source_lang` parameter to be set and the
125+
// language pair of the glossary has to match the language pair of the request.
126+
func WithGlossaryId(value string) TranslateOptionFunc {
127+
const name string = "glossary_id"
128+
return func(o TranslateOptions) error {
129+
o[name] = value
130+
return nil
131+
}
132+
}
133+
134+
// WithTagHandling sets which kind of tags should be handled.
135+
//
136+
// Options currently available:
137+
// - `xml`: Enable XML tag handling; see [XML Handling][xml-handling].
138+
// - `html`: Enable HTML tag handling; see [HTML Handling][html-handling].
139+
//
140+
// [xml-handling]: https://www.deepl.com/docs-api/xml
141+
// [html-handling]: https://www.deepl.com/docs-api/html
142+
func WithTagHandling(value string) TranslateOptionFunc {
143+
const name string = "tag_handling"
144+
return func(o TranslateOptions) error {
145+
switch value {
146+
case "html", "xml":
147+
o[name] = value
148+
return nil
149+
}
150+
return translateOptionInvalidValueError(name, value)
151+
}
152+
}
153+
154+
// WithOutlineDetection can be used to disable the automatic detection of the
155+
// XML structure.
156+
//
157+
// The automatic detection of the XML structure won't yield best results in all
158+
// XML files. You can disable this automatic mechanism altogether by setting
159+
// the `outline_detection` parameter to `0` and selecting the tags that should
160+
// be considered structure tags. This will split sentences using the
161+
// `splitting_tags` parameter.
162+
//
163+
// In the example below, we achieve the same results as the automatic engine by
164+
// disabling automatic detection with `outline_detection=0` and setting the
165+
// parameters manually to `tag_handling=xml`, `split_sentences=nonewlines`, and
166+
// `splitting_tags=par,title`.
167+
//
168+
// Example request:
169+
// ```
170+
// <document>
171+
//
172+
// <meta>
173+
// <title>A document's title</title>
174+
// </meta>
175+
// <content>
176+
// <par>This is the first sentence. Followed by a second one.</par>
177+
// <par>This is the third sentence.</par>
178+
// </content>
179+
//
180+
// </document>
181+
// ```
182+
//
183+
// Example response:
184+
// ```
185+
// <document>
186+
//
187+
// <meta>
188+
// <title>Der Titel eines Dokuments</title>
189+
// </meta>
190+
// <content>
191+
// <par>Das ist der erste Satz. Gefolgt von einem zweiten.</par>
192+
// <par>Dies ist der dritte Satz.</par>
193+
// </content>
194+
//
195+
// </document>
196+
// ```
197+
//
198+
// While this approach is slightly more complicated, it allows for greater
199+
// control over the structure of the translation output.
200+
func WithOutlineDetection(value string) TranslateOptionFunc {
201+
const name string = "outline_detection"
202+
return func(o TranslateOptions) error {
203+
switch value {
204+
case "0":
205+
o[name] = value
206+
return nil
207+
}
208+
return translateOptionInvalidValueError(name, value)
209+
}
210+
}
211+
212+
// WithNonSplittingTags specifies a comma-separated list of XML tags which
213+
// never split sentences.
214+
//
215+
// For some XML files, finding tags with textual content and splitting
216+
// sentences using those tags won't yield the best results. The following
217+
// example shows the engine splitting sentences on `par` tags and proceeding to
218+
// translate the parts separately, resulting in an incorrect translation:
219+
//
220+
// Example request:
221+
// ```
222+
// <par>The firm said it had been </par><par> conducting an internal investigation.</par>
223+
// ```
224+
//
225+
// Example response:
226+
// ```
227+
// <par>Die Firma sagte, es sei eine gute Idee gewesen.</par><par> Durchführung einer internen Untersuchung.</par>
228+
// ```
229+
//
230+
// As this can lead to bad translations, this type of structure should either
231+
// be avoided, or the `non_splitting_tags` parameter should be set.
232+
//
233+
// The following example shows the same call, with the parameter set to `par`:
234+
//
235+
// Example request:
236+
// ```
237+
// <par>The firm said it had been </par><par> conducting an internal investigation.</par>
238+
// ```
239+
//
240+
// Example response:
241+
// ```
242+
// <par>Die Firma sagte, dass sie</par><par> eine interne Untersuchung durchgeführt</par><par> habe</par><par>.</par>
243+
// ```
244+
//
245+
// This time, the sentence is translated as a whole. The XML tags are now
246+
// considered markup and copied into the translated sentence. As the
247+
// translation of the words "had been" has moved to another position in the
248+
// German sentence, the two `par` tags are duplicated (which is expected here).
249+
func WithNonSplittingTags(value string) TranslateOptionFunc {
250+
const name string = "non_splitting_tags"
251+
return func(o TranslateOptions) error {
252+
o[name] = value
253+
return nil
254+
}
255+
}
256+
257+
// WithSplittingTags specifies a comma-separated list of XML tags which always
258+
// cause splits.
259+
//
260+
// See the example in the `outline_detection` parameter's description.
261+
func WithSplittingTags(value string) TranslateOptionFunc {
262+
const name string = "splitting_tags"
263+
return func(o TranslateOptions) error {
264+
o[name] = value
265+
return nil
266+
}
267+
}
268+
269+
// WithIgnoreTags specifies a comma-separated list of XML tags that indicate
270+
// text not to be translated.
271+
//
272+
// Use this parameter to ensure that elements in the original text are not
273+
// altered in the translation (e.g., trademarks, product names) and insert tags
274+
// into your original text. In the following example, the `ignore_tags` parameter
275+
// is set to `keep`:
276+
//
277+
// Example request:
278+
// ```
279+
// Please open the page <keep>Settings</keep> to configure your system.
280+
// ```
281+
//
282+
// Example response:
283+
// ```
284+
// Bitte öffnen Sie die Seite <keep>Settings</keep> um Ihr System zu konfigurieren.
285+
// ```
286+
func WithIgnoreTags(value string) TranslateOptionFunc {
287+
const name string = "ignore_tags"
288+
return func(o TranslateOptions) error {
289+
o[name] = value
290+
return nil
291+
}
292+
}
293+

0 commit comments

Comments
 (0)