Skip to content

Commit

Permalink
Improve usage of functional options and add some doccomments
Browse files Browse the repository at this point in the history
  • Loading branch information
cluttrdev committed Feb 19, 2023
1 parent 6768694 commit 0b2c566
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 55 deletions.
7 changes: 1 addition & 6 deletions pkg/api/http_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,11 @@ import (
"time"
)

const (
BaseURLPro = "https://api.deepl.com/v2"
BaseURLFree = "https://api-free.deepl.com/v2"
)

type Client struct {
httpClient *http.Client
}

func NewClient(baseURL string, authKey string, timeout time.Duration) *Client {
func NewClient(timeout time.Duration) *Client {
client := &http.Client{
Timeout: timeout,
}
Expand Down
96 changes: 60 additions & 36 deletions pkg/api/translate.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,87 +4,110 @@ import (
"encoding/json"
"net/http"
"net/url"

"github.com/pkg/errors"
)

type Translation struct {
DetectedSourceLanguage string `json:"detected_source_language"`
Text string `json:"text"`
}

// TranslateOption is a functional option for configuring text translation parameters
type TranslateOption func(url.Values)

// The language to be translated.
// If this parameter is omitted, the API will attempt to detect the language of the text and translate it.
func SourceLang(lang string) TranslateOption {
// If this parameter is omitted, the API will attempt to detect the language of the text and translate it
func SourceLang(lang string) (TranslateOption, error) {
return func(vals url.Values) {
vals.Set("source_lang", lang)
}
}, nil
}

// Sets whether the translation engine should first split the input into sentences.
func SplitSentences(split string) TranslateOption {
return func(vals url.Values) {
vals.Set("split_sentences", split)
// SplitSentences sets whether the translation engine should first split the input into sentences
func SplitSentences(split string) (TranslateOption, error) {
switch split {
case "0", "1", "nonewlines":
return func(vals url.Values) {
vals.Set("split_sentences", split)
}, nil
}
return nil, errors.Errorf("Invalid SplitSentence value: %s", split)
}

// Sets whether the translation engine should respect the original formatting, even if it would usually correct some aspects.
func PreserveFormatting(preserve string) TranslateOption {
return func(vals url.Values) {
vals.Set("preserve_formatting", preserve)
// PreserveFormatting sets whether the translation engine should respect the original formatting, even if it would usually correct some aspects
func PreserveFormatting(preserve string) (TranslateOption, error) {
switch preserve {
case "0", "1":
return func(vals url.Values) {
vals.Set("preserve_formatting", preserve)
}, nil
}
return errors.Errorf("Invalid PreserveFormatting value: %s", preserve)
}

// Sets whether the translated text should lean towards formal or informal language.
func Formality(formality string) TranslateOption {
return func(vals url.Values) {
vals.Set("formality", formality)
// Formality sets whether the translated text should lean towards formal or informal language
func Formality(formality string) (TranslateOption, error) {
switch formality {
case "default", "more", "less", "prefer_more", "prefer_less":
return func(vals url.Values) {
vals.Set("formality", formality)
}, nil
}
return nil, errors.Errorf("Invalid Formality value: %s", formality)
}

// Specify the glossary to use for the translation.
func GlossaryId(glossary string) TranslateOption {
// GlossaryId specifies the glossary to use for the translation
func GlossaryId(glossary string) (TranslateOption, error) {
return func(vals url.Values) {
vals.Set("glossary_id", glossary)
}
}, nil
}

// Sets which kind of tags should be handled.
func TagHandling(handling string) TranslateOption {
return func(vals url.Values) {
vals.Set("tag_handling", handling)
// TagHandling sets which kind of tags should be handled
func TagHandling(handling string) (TranslateOption, error) {
switch handling {
case "html", "xml":
return func(vals url.Values) {
vals.Set("tag_handling", handling)
}, nil
}
return nil, errors.Errorf("Invalid TagHandling value: %s", handling)
}

// Comma-separated list of XML tags which never split sentences.
func NonSplittingTags(tags string) TranslateOption {
// NonSplittingTags specifies a comma-separated list of XML tags which never split sentences
func NonSplittingTags(tags string) (TranslateOption, error) {
return func(vals url.Values) {
vals.Set("non_splitting_tags", tags)
}
}, nil
}

// Disable the automatic detection of the XML structure.
func OutlineDetection(detect string) TranslateOption {
return func(vals url.Values) {
vals.Set("outline_detection", detect)
// OutlineDetection can be used to disable the automatic detection of the XML structure
func OutlineDetection(detect string) (TranslateOption, error) {
switch detect {
case "0":
return func(vals url.Values) {
vals.Set("outline_detection", detect)
}, nil
}
return nil, errors.Errorf("Invalid OutlineDetection value: %s", detect)
}

// Comma-separated list of XML tags which always cause splts.
func SplittingTags(tags string) TranslateOption {
// SplittingTags specifies a comma-separated list of XML tags which always cause splts
func SplittingTags(tags string) (TranslateOption, error) {
return func(vals url.Values) {
vals.Set("splitting_tags", tags)
}
}, nil
}

// Comma-separated list of XML tags that indicate text not to be translated.
func IgnoreTags(tags string) TranslateOption {
// IgnoeTags specifies a comma-separated list of XML tags that indicate text not to be translated
func IgnoreTags(tags string) (TranslateOption, error) {
return func(vals url.Values) {
vals.Set("ignore_tags", tags)
}
}, nil
}

// The translate function.
// TranslateText translates the given text(s) into the specified target language
func (t *Translator) TranslateText(texts []string, targetLang string, options ...TranslateOption) ([]Translation, error) {
vals := make(url.Values)

Expand All @@ -94,6 +117,7 @@ func (t *Translator) TranslateText(texts []string, targetLang string, options ..

vals.Set("target_lang", targetLang)

// Apply translation parameter options
for _, opt := range options {
opt(vals)
}
Expand Down
60 changes: 47 additions & 13 deletions pkg/api/translator.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,36 +8,69 @@ import (
"time"
)

type TranslatorOptions struct {
ServerUrl string `default:""`
}
const (
ServerURLPro = "https://api.deepl.com/v2"
ServerURLFree = "https://api-free.deepl.com/v2"
)

type Translator struct {
httpClient *Client
serverURL string
authKey string
}

func NewTranslator(authKey string, options TranslatorOptions) *Translator {
var serverURL string
if options.ServerUrl == "" {
if authKeyIsFreeAccount(authKey) {
serverURL = BaseURLFree
} else {
serverURL = BaseURLPro
// TranslatorOption is a functional option for configuring the Translator
type TranslatorOption func(*Translator) error

// ServerURL allows overriding the default server url
func ServerURL(url string) TranslatorOption {
return func(t *Translator) error {
t.serverURL = url
return nil
}
}

// parseOptions apllies the supplied functional options to the Translator
func (t *Translator) parseOptions(opts ...TranslatorOption) error {
for _, opt := range opts {
err := opt(t)
if err != nil {
return err
}
}

timeout := 10 * time.Second
httpClient := NewClient(serverURL, authKey, timeout)
return nil
}

return &Translator{
// NewTranslator creates a new translator
func NewTranslator(authKey string, opts ...TranslatorOption) (*Translator, error) {
// Determine default server url based on auth key
var serverURL string
if authKeyIsFreeAccount(authKey) {
serverURL = ServerURLFree
} else {
serverURL = ServerURLPro
}

// Set up default http client
timeout := time.Second * 30
httpClient := NewClient(timeout)

t := &Translator{
httpClient: httpClient,
serverURL: serverURL,
authKey: authKey,
}

// Parse and apply options
if err := t.parseOptions(opts...); err != nil {
return nil, err
}

return t, nil
}

// callAPI calls the supplied API endpoint with the provided parameters and returns the response
func (t *Translator) callAPI(method string, endpoint string, data url.Values, headers http.Header) (*http.Response, error) {
url := fmt.Sprintf("%s/%s", t.serverURL, endpoint)

Expand All @@ -54,6 +87,7 @@ func (t *Translator) callAPI(method string, endpoint string, data url.Values, he
return res, err
}

// authKeyIsFreeAccount determines whether the supplied auth key belongs to a Free account
func authKeyIsFreeAccount(authKey string) bool {
return strings.HasSuffix(authKey, ":fx")
}

0 comments on commit 0b2c566

Please sign in to comment.