From fdcd40d392cc9344844e69532d00794cf133de3d Mon Sep 17 00:00:00 2001 From: Laurynas Butkus Date: Tue, 29 Jul 2025 22:42:43 +0300 Subject: [PATCH 1/5] Switch to v3 api --- README.md | 2 +- user.go => account.go | 6 ++--- user_test.go => account_test.go | 4 ++-- client.go | 9 ++++---- detect.go | 39 +++++++++------------------------ detect_test.go | 5 ++--- languages.go | 4 +++- version.go | 2 +- 8 files changed, 26 insertions(+), 45 deletions(-) rename user.go => account.go (77%) rename user_test.go => account_test.go (72%) diff --git a/README.md b/README.md index 36033dc..b3adcfa 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ You can get it by signing up at https://detectlanguage.com ## Installation ``` -go get -u github.com/detectlanguage/detectlanguage-go@v1.0.1 +go get -u github.com/detectlanguage/detectlanguage-go@v2.0.0 ``` ### Configuration diff --git a/user.go b/account.go similarity index 77% rename from user.go rename to account.go index 41f6f59..f2ccf4b 100644 --- a/user.go +++ b/account.go @@ -1,7 +1,7 @@ package detectlanguage // UserStatusResponse is the resource containing account status information -type UserStatusResponse struct { +type AccountStatusResponse struct { Date string `json:"date,omitempty"` Requests int `json:"requests"` Bytes int `json:"bytes"` @@ -13,7 +13,7 @@ type UserStatusResponse struct { } // UserStatus fetches account status -func (c *Client) UserStatus() (out *UserStatusResponse, err error) { - err = c.get(nil, "user/status", &out) +func (c *Client) AccountStatus() (out *AccountStatusResponse, err error) { + err = c.get(nil, "account/status", &out) return } diff --git a/user_test.go b/account_test.go similarity index 72% rename from user_test.go rename to account_test.go index 1742053..65baaed 100644 --- a/user_test.go +++ b/account_test.go @@ -6,8 +6,8 @@ import ( "github.com/stretchr/testify/assert" ) -func TestUserStatus(t *testing.T) { - response, err := client.UserStatus() +func TestAccountStatus(t *testing.T) { + response, err := client.AccountStatus() if assert.NoError(t, err) { assert.NotEmpty(t, response.Date) diff --git a/client.go b/client.go index d3b5403..ff04279 100644 --- a/client.go +++ b/client.go @@ -5,7 +5,6 @@ import ( "context" "encoding/json" "io" - "io/ioutil" "net/http" "net/url" "time" @@ -16,7 +15,7 @@ const defaultUserAgent = "detectlanguage-go/" + Version const defaultTimeout = 10 * time.Second var apiBaseURL = &url.URL{ - Scheme: "https", Host: "ws.detectlanguage.com", Path: "/0.2/", + Scheme: "https", Host: "ws.detectlanguage.com", Path: "/v3/", } // A Client provides an HTTP client for DetectLanguage API operations. @@ -70,9 +69,9 @@ func (c *Client) setBody(req *http.Request, in interface{}) error { if err != nil { return err } - req.Body = ioutil.NopCloser(bytes.NewReader(buf)) + req.Body = io.NopCloser(bytes.NewReader(buf)) req.GetBody = func() (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewReader(buf)), nil + return io.NopCloser(bytes.NewReader(buf)), nil } req.Header.Set("Content-Type", "application/json") req.ContentLength = int64(len(buf)) @@ -107,7 +106,7 @@ func (c *Client) do(ctx context.Context, method, path string, in, out interface{ return nil } - buf, _ := ioutil.ReadAll(res.Body) + buf, _ := io.ReadAll(res.Body) apiErr := &APIError{Status: res.Status, StatusCode: res.StatusCode} if json.Unmarshal(buf, &apiErrorResponse{Error: apiErr}) != nil { apiErr.Message = string(buf) diff --git a/detect.go b/detect.go index ab1420a..ccf6a1e 100644 --- a/detect.go +++ b/detect.go @@ -1,25 +1,16 @@ package detectlanguage +import "context" + // DetectRequest contains language detection request params type DetectRequest struct { Query string `json:"q"` } -// DetectResponse is a resource containing language detection response -type DetectResponse struct { - Data *DetectResponseData `json:"data"` -} - -// DetectResponseData contains language detection response data -type DetectResponseData struct { - Detections []*DetectionResult `json:"detections"` -} - // DetectionResult is single language detection result type DetectionResult struct { - Language string `json:"language"` - Reliable bool `json:"isReliable"` - Confidence float32 `json:"confidence"` + Language string `json:"language"` + Score float64 `json:"score"` } // DetectBatchRequest contains batch language detection request params @@ -27,26 +18,16 @@ type DetectBatchRequest struct { Query []string `json:"q"` } -// DetectBatchResponse is a resource batch containing language detection response -type DetectBatchResponse struct { - Data *DetectBatchResponseData `json:"data"` -} - -// DetectBatchResponseData contains batch language detection response data -type DetectBatchResponseData struct { - Detections [][]*DetectionResult `json:"detections"` -} - // Detect executes language detection for a single text func (c *Client) Detect(in string) (out []*DetectionResult, err error) { - var response DetectResponse - err = c.post(nil, "detect", &DetectRequest{Query: in}, &response) + var response []*DetectionResult + err = c.post(context.TODO(), "detect", &DetectRequest{Query: in}, &response) if err != nil { return nil, err } - return response.Data.Detections, err + return response, err } // DetectCode executes language detection for a single text and returns detected language code @@ -67,12 +48,12 @@ func (c *Client) DetectCode(in string) (out string, err error) { // DetectBatch executes language detection with multiple texts. // It is significantly faster than doing a separate request for each text indivdually. func (c *Client) DetectBatch(in []string) (out [][]*DetectionResult, err error) { - var response DetectBatchResponse - err = c.post(nil, "detect", &DetectBatchRequest{Query: in}, &response) + var response [][]*DetectionResult + err = c.post(nil, "detect-batch", &DetectBatchRequest{Query: in}, &response) if err != nil { return nil, err } - return response.Data.Detections, err + return response, err } diff --git a/detect_test.go b/detect_test.go index 24b9aa0..6fc0247 100644 --- a/detect_test.go +++ b/detect_test.go @@ -11,8 +11,7 @@ func TestDetect(t *testing.T) { if assert.NoError(t, err) { assert.Equal(t, "lt", detections[0].Language) - assert.True(t, detections[0].Reliable) - assert.Greater(t, detections[0].Confidence, float32(0)) + assert.Greater(t, detections[0].Score, float64(0)) } } @@ -25,7 +24,7 @@ func TestDetectCode(t *testing.T) { } func TestDetectCodeFailure(t *testing.T) { - code, err := client.DetectCode("") + code, err := client.DetectCode(" ") assert.EqualError(t, err, "Language not detected") assert.Equal(t, code, "") diff --git a/languages.go b/languages.go index d7b7750..eea984c 100644 --- a/languages.go +++ b/languages.go @@ -1,5 +1,7 @@ package detectlanguage +import "context" + // Language is the resource representing language type Language struct { Code string `json:"code"` @@ -8,6 +10,6 @@ type Language struct { // Languages retrieves the list of supported languages func (c *Client) Languages() (out []*Language, err error) { - err = c.get(nil, "languages", &out) + err = c.get(context.TODO(), "languages", &out) return } diff --git a/version.go b/version.go index 330379a..16b1f2f 100644 --- a/version.go +++ b/version.go @@ -1,4 +1,4 @@ package detectlanguage // Version is the API client version -const Version = "1.0.1" +const Version = "2.0.0" From 4283bc5112d5057272a52e92d62901b3c91fbd98 Mon Sep 17 00:00:00 2001 From: Laurynas Butkus Date: Wed, 30 Jul 2025 19:01:25 +0300 Subject: [PATCH 2/5] Switch back to ioutil --- client.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/client.go b/client.go index ff04279..1e432e8 100644 --- a/client.go +++ b/client.go @@ -5,6 +5,7 @@ import ( "context" "encoding/json" "io" + "io/ioutil" "net/http" "net/url" "time" @@ -69,9 +70,9 @@ func (c *Client) setBody(req *http.Request, in interface{}) error { if err != nil { return err } - req.Body = io.NopCloser(bytes.NewReader(buf)) + req.Body = ioutil.NopCloser(bytes.NewReader(buf)) req.GetBody = func() (io.ReadCloser, error) { - return io.NopCloser(bytes.NewReader(buf)), nil + return ioutil.NopCloser(bytes.NewReader(buf)), nil } req.Header.Set("Content-Type", "application/json") req.ContentLength = int64(len(buf)) @@ -106,7 +107,7 @@ func (c *Client) do(ctx context.Context, method, path string, in, out interface{ return nil } - buf, _ := io.ReadAll(res.Body) + buf, _ := ioutil.ReadAll(res.Body) apiErr := &APIError{Status: res.Status, StatusCode: res.StatusCode} if json.Unmarshal(buf, &apiErrorResponse{Error: apiErr}) != nil { apiErr.Message = string(buf) From 292407d889c9bb4b1a3ac1d953f5bb170bcf6f94 Mon Sep 17 00:00:00 2001 From: Laurynas Butkus Date: Wed, 30 Jul 2025 19:06:42 +0300 Subject: [PATCH 3/5] Require context --- account.go | 10 ++++++---- account_test.go | 3 ++- detect.go | 12 ++++++------ detect_test.go | 9 +++++---- languages.go | 4 ++-- languages_test.go | 3 ++- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/account.go b/account.go index f2ccf4b..e2740a3 100644 --- a/account.go +++ b/account.go @@ -1,6 +1,8 @@ package detectlanguage -// UserStatusResponse is the resource containing account status information +import "context" + +// AccountStatusResponse is the resource containing account status information type AccountStatusResponse struct { Date string `json:"date,omitempty"` Requests int `json:"requests"` @@ -12,8 +14,8 @@ type AccountStatusResponse struct { Status string `json:"status"` } -// UserStatus fetches account status -func (c *Client) AccountStatus() (out *AccountStatusResponse, err error) { - err = c.get(nil, "account/status", &out) +// AccountStatus fetches account status +func (c *Client) AccountStatus(ctx context.Context) (out *AccountStatusResponse, err error) { + err = c.get(ctx, "account/status", &out) return } diff --git a/account_test.go b/account_test.go index 65baaed..86a0cc4 100644 --- a/account_test.go +++ b/account_test.go @@ -1,13 +1,14 @@ package detectlanguage_test import ( + "context" "testing" "github.com/stretchr/testify/assert" ) func TestAccountStatus(t *testing.T) { - response, err := client.AccountStatus() + response, err := client.AccountStatus(context.TODO()) if assert.NoError(t, err) { assert.NotEmpty(t, response.Date) diff --git a/detect.go b/detect.go index ccf6a1e..f20819a 100644 --- a/detect.go +++ b/detect.go @@ -19,9 +19,9 @@ type DetectBatchRequest struct { } // Detect executes language detection for a single text -func (c *Client) Detect(in string) (out []*DetectionResult, err error) { +func (c *Client) Detect(ctx context.Context, in string) (out []*DetectionResult, err error) { var response []*DetectionResult - err = c.post(context.TODO(), "detect", &DetectRequest{Query: in}, &response) + err = c.post(ctx, "detect", &DetectRequest{Query: in}, &response) if err != nil { return nil, err @@ -31,8 +31,8 @@ func (c *Client) Detect(in string) (out []*DetectionResult, err error) { } // DetectCode executes language detection for a single text and returns detected language code -func (c *Client) DetectCode(in string) (out string, err error) { - detections, err := c.Detect(in) +func (c *Client) DetectCode(ctx context.Context, in string) (out string, err error) { + detections, err := c.Detect(ctx, in) if err != nil { return "", err @@ -47,9 +47,9 @@ func (c *Client) DetectCode(in string) (out string, err error) { // DetectBatch executes language detection with multiple texts. // It is significantly faster than doing a separate request for each text indivdually. -func (c *Client) DetectBatch(in []string) (out [][]*DetectionResult, err error) { +func (c *Client) DetectBatch(ctx context.Context, in []string) (out [][]*DetectionResult, err error) { var response [][]*DetectionResult - err = c.post(nil, "detect-batch", &DetectBatchRequest{Query: in}, &response) + err = c.post(ctx, "detect-batch", &DetectBatchRequest{Query: in}, &response) if err != nil { return nil, err diff --git a/detect_test.go b/detect_test.go index 6fc0247..2ea00b6 100644 --- a/detect_test.go +++ b/detect_test.go @@ -1,13 +1,14 @@ package detectlanguage_test import ( + "context" "testing" "github.com/stretchr/testify/assert" ) func TestDetect(t *testing.T) { - detections, err := client.Detect("labas rytas") + detections, err := client.Detect(context.TODO(), "labas rytas") if assert.NoError(t, err) { assert.Equal(t, "lt", detections[0].Language) @@ -16,7 +17,7 @@ func TestDetect(t *testing.T) { } func TestDetectCode(t *testing.T) { - code, err := client.DetectCode("labas rytas") + code, err := client.DetectCode(context.TODO(), "labas rytas") if assert.NoError(t, err) { assert.Equal(t, "lt", code) @@ -24,7 +25,7 @@ func TestDetectCode(t *testing.T) { } func TestDetectCodeFailure(t *testing.T) { - code, err := client.DetectCode(" ") + code, err := client.DetectCode(context.TODO(), " ") assert.EqualError(t, err, "Language not detected") assert.Equal(t, code, "") @@ -32,7 +33,7 @@ func TestDetectCodeFailure(t *testing.T) { func TestDetectBatch(t *testing.T) { query := []string{"labas rytas", "good morning"} - detections, err := client.DetectBatch(query) + detections, err := client.DetectBatch(context.TODO(), query) if assert.NoError(t, err) { assert.Equal(t, "lt", detections[0][0].Language) diff --git a/languages.go b/languages.go index eea984c..74e2a21 100644 --- a/languages.go +++ b/languages.go @@ -9,7 +9,7 @@ type Language struct { } // Languages retrieves the list of supported languages -func (c *Client) Languages() (out []*Language, err error) { - err = c.get(context.TODO(), "languages", &out) +func (c *Client) Languages(ctx context.Context) (out []*Language, err error) { + err = c.get(ctx, "languages", &out) return } diff --git a/languages_test.go b/languages_test.go index 8b43141..ae45930 100644 --- a/languages_test.go +++ b/languages_test.go @@ -1,13 +1,14 @@ package detectlanguage_test import ( + "context" "testing" "github.com/stretchr/testify/assert" ) func TestLanguages(t *testing.T) { - languages, err := client.Languages() + languages, err := client.Languages(context.TODO()) if assert.NoError(t, err) { assert.NotEmpty(t, languages[0].Code) From f0ae4fd594287c70516b71eccd476b817986f575 Mon Sep 17 00:00:00 2001 From: Laurynas Butkus Date: Wed, 30 Jul 2025 19:14:22 +0300 Subject: [PATCH 4/5] Update readme --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b3adcfa..d12bd47 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ go get -u github.com/detectlanguage/detectlanguage-go@v2.0.0 ### Configuration ```go -client := detectlanguage.New("YOUR API KEY") +dl := detectlanguage.New("YOUR API KEY") ``` ## Usage @@ -27,7 +27,7 @@ client := detectlanguage.New("YOUR API KEY") ### Language detection ```go -detections, err := client.Detect("Buenos dias señor") +detections, err := dl.Detect(context.TODO(), "Dolce far niente") if err != nil { fmt.Fprintln(os.Stderr, "error detecting language:", err) @@ -36,8 +36,7 @@ if err != nil { } fmt.Fprintln(os.Stdout, "Language:", detections[0].Language) -fmt.Fprintln(os.Stdout, "Reliable:", detections[0].Reliable) -fmt.Fprintln(os.Stdout, "Confidence:", detections[0].Confidence) +fmt.Fprintln(os.Stdout, "Score:", detections[0].Score) ``` ### Single language code detection @@ -45,7 +44,7 @@ fmt.Fprintln(os.Stdout, "Confidence:", detections[0].Confidence) If you need just a language code you can use `DetectCode`. It returns first detected language code. ```go -language, err := client.DetectCode("Buenos dias señor") +language, err := dl.DetectCode(context.TODO(), "Dolce far niente") if err != nil { fmt.Fprintln(os.Stderr, "error detecting language:", err) @@ -64,7 +63,7 @@ To use batch detection just pass multiple texts to `DetectBatch` method. ```go texts := []string{"labas rytas", "good morning"} -results, err := client.DetectBatch(texts) +results, err := dl.DetectBatch(context.TODO(), texts) if err != nil { fmt.Fprintln(os.Stderr, "error detecting language:", err) @@ -79,10 +78,10 @@ fmt.Fprintln(os.Stdout, "Second text language:", detections[1][0].Language) ### Getting your account status ```go -result, err := client.UserStatus() +result, err := dl.AccountStatus(context.TODO()) if err != nil { - fmt.Fprintln(os.Stderr, "error getting user status:", err) + fmt.Fprintln(os.Stderr, "error getting account status:", err) os.Exit(1) return } @@ -100,7 +99,7 @@ fmt.Fprintln(os.Stdout, "Date:", result.Date) ### Getting list supported languages ```go -languages, err := client.Languages() +languages, err := dl.Languages(context.TODO()) if err != nil { fmt.Fprintln(os.Stderr, "error getting languages list:", err) From a8ca9bcb325d1b4ae33bf2833194bff9f33b687c Mon Sep 17 00:00:00 2001 From: Laurynas Butkus Date: Wed, 30 Jul 2025 19:18:36 +0300 Subject: [PATCH 5/5] Add changelog --- CHANGELOG.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..2003a91 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,17 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + + +## v2.0.0 + +### Added +- `context` to all API methods + +### Changed +- Switched to v3 API which uses updated language detection model +- Language detection results contains `Language` and `Score` +- `UserStatus()` renamed to `AccountStatus()`