Skip to content

CON-1716 MT API endpoints #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 37 commits into
base: CON-1716-Project_layout
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
ecae272
CON-1716 API endpoints
Jun 18, 2025
d8d9707
added MT response types
Jun 19, 2025
3d617cf
implemented downloader functionality
Jun 19, 2025
263b0ce
implemented FileTranslator functionality
Jun 19, 2025
5d3ac73
implemented TranslationControl functionality
Jun 19, 2025
00d87e9
implemented Uploader functionality
Jun 19, 2025
3845ffe
Merge branch 'CON-1716-Project_layout' into CON-1716-MT_endpoints
Jun 23, 2025
30b21ab
fixed merge
Jun 23, 2025
8bb0aaf
Merge branch 'CON-1716-Project_layout' into CON-1716-MT_endpoints
Jun 23, 2025
e334f7e
Merge branch 'CON-1716-Project_layout' into CON-1716-MT_endpoints
Jun 24, 2025
04872b5
changed UploadFile
Jun 26, 2025
e1b4991
changed UploadFile
Jun 26, 2025
b109ddc
changed to type FileUID
Jun 26, 2025
1ae35ae
changed to type FileUID
Jun 26, 2025
38548b7
changed to type MtUID
Jun 26, 2025
fd54c12
added CompletedTranslatedState
Jun 26, 2025
cc6cfd9
more translated states
Jun 26, 2025
5436576
moved url
Jun 27, 2025
d4637a8
moved url
Jun 27, 2025
28bd1ec
moved url
Jun 27, 2025
5f4f29c
added request field for uploader
Jun 27, 2025
e96fef2
added request field for uploader
Jun 27, 2025
ef30269
added GetMTForm
Jun 27, 2025
f6bb3d1
updated GetMTForm
Jun 27, 2025
13c5a8a
updated GetMTForm
Jun 27, 2025
abcd608
updated GetMTForm
Jun 27, 2025
831e421
updated GetMTForm
Jun 27, 2025
d519530
updated GetMTForm
Jun 27, 2025
2eb2822
removed GetMTForm
Jun 27, 2025
2a54bb8
added PostJSON
Jun 28, 2025
afd6a93
updated translator and translation control
Jun 28, 2025
773201b
updated upload file
Jul 1, 2025
02a5ecd
added FileTypeByExt
Jul 1, 2025
493ea24
updated TranslationControl
Jul 1, 2025
42d924b
removed in func types TranslationControl
Jul 1, 2025
653adb2
added UploadFileRequest
Jul 2, 2025
8359d5a
updated Uploader with UploadFileRequest
Jul 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 33 additions & 0 deletions api/mt/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package mt

import (
"strings"

"github.com/Smartling/api-sdk-go/helpers/sm_client"
)

const (
SuccessResponseCode = "SUCCESS"
QueuedTranslatedState = "QUEUED"
ProcessingTranslatedState = "PROCESSING"
FailedTranslatedState = "FAILED"
CanceledTranslatedState = "CANCELED"
CompletedTranslatedState = "COMPLETED"
)

var (
mtBasePath = "/file-translations-api/v2/"
contentTypeApplicationJson = "Content-Type:application/json"
)

type base struct {
client *smclient.Client
}

func newBase(client *smclient.Client) *base {
return &base{client: client}
}

func joinPath(left, right string) string {
return strings.TrimRight(left, "/") + "/" + strings.TrimLeft(right, "/")
}
68 changes: 68 additions & 0 deletions api/mt/downloader.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package mt

import (
"fmt"
"io"

"github.com/Smartling/api-sdk-go/helpers/sm_client"
"github.com/Smartling/api-sdk-go/helpers/sm_file"
)

// Downloader defines downloader behaviour
type Downloader interface {
File(accountUID AccountUID, fileUID FileUID,
mtUID MtUID, localeID string) (io.Reader, error)
Batch(accountUID AccountUID, fileUID FileUID, mtUID MtUID) (io.Reader, error)
}

// NewDownloader returns new Downloader implementation
func NewDownloader(client *smclient.Client) Downloader {
return newHttpDownloader(newBase(client))
}

type httpDownloader struct {
base *base
}

func newHttpDownloader(base *base) *httpDownloader {
return &httpDownloader{base: base}
}

// File downloads file
func (d httpDownloader) File(accountUID AccountUID, fileUID FileUID,
mtUID MtUID, localeID string) (io.Reader, error) {
filePath := buildFilePath(accountUID, fileUID, mtUID, localeID)
path := joinPath(mtBasePath, filePath)
reader, _, err := d.base.client.Get(
path,
smfile.FileURIRequest{FileURI: string(fileUID)}.GetQuery(),
)
if err != nil {
return nil, fmt.Errorf("failed to download original file: %w", err)
}

return reader, nil
}

// Batch download files
func (d httpDownloader) Batch(accountUID AccountUID, fileUID FileUID, mtUID MtUID) (io.Reader, error) {
batchPath := buildBatchPath(accountUID, fileUID, mtUID)
path := joinPath(mtBasePath, batchPath)
reader, _, err := d.base.client.Get(
path,
smfile.FileURIRequest{FileURI: string(fileUID)}.GetQuery(),
)
if err != nil {
return nil, fmt.Errorf("failed to download original file: %w", err)
}

return reader, nil
}

func buildFilePath(accountUID AccountUID, fileUID FileUID, mtUID MtUID, localeID string) string {
return "/accounts/" + string(accountUID) + "/files/" + string(fileUID) + "/mt/" + string(mtUID) + "/locales/" + localeID + "/file"
}

func buildBatchPath(accountUID AccountUID, fileUID FileUID, mtUID MtUID) string {
return "/accounts/" + string(accountUID) + "/files/" + string(fileUID) + "/mt/" + string(mtUID) + "/locales/all/file/zip"
}
85 changes: 85 additions & 0 deletions api/mt/file_translator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package mt

import (
"encoding/json"
"fmt"

"github.com/Smartling/api-sdk-go/helpers/sm_client"
"github.com/Smartling/api-sdk-go/helpers/sm_file"
)

// FileTranslator defines file behaviour
type FileTranslator interface {
Start(accountUID AccountUID, fileUID FileUID, p StartParams) (StartResponse, error)
Progress(accountUID AccountUID, fileUID FileUID, mtUID MtUID) (ProgressResponse, error)
}

// NewFileTranslator returns new FileTranslator implementation
func NewFileTranslator(client *smclient.Client) FileTranslator {
return httpFileTranslator{base: newBase(client)}
}

type httpFileTranslator struct {
base *base
}

type StartParams struct {
SourceLocaleIO string `json:"sourceLocaleId"`
TargetLocaleIDs []string `json:"targetLocaleIds"`
}

// Start starts file translation
func (h httpFileTranslator) Start(accountUID AccountUID, fileUID FileUID, p StartParams) (StartResponse, error) {
startPath := buildStartPath(accountUID, fileUID)
path := joinPath(mtBasePath, startPath)

payload, err := json.Marshal(p)
if err != nil {
return StartResponse{}, err
}

resp, err := h.base.client.Post(path, payload)
if err != nil {
return StartResponse{}, fmt.Errorf("failed to start file translation: %w", err)
}
type startResponse struct {
Response struct {
Code string `json:"code"`
Data struct {
MtUID string `json:"mtUid"`
} `json:"data"`
} `json:"response"`
}
var res startResponse
if err := json.NewDecoder(resp.Body).Decode(&res); err != nil {
return StartResponse{}, fmt.Errorf("failed to parse response: %w", err)
}
return StartResponse{
Code: res.Response.Code,
MtUID: MtUID(res.Response.Data.MtUID),
}, nil
}

// Progress return progress of file translation
func (h httpFileTranslator) Progress(accountUID AccountUID, fileUID FileUID, mtUID MtUID) (ProgressResponse, error) {
var res ProgressResponse
progressPath := buildProgressPath(accountUID, fileUID, mtUID)
path := joinPath(mtBasePath, progressPath)
_, _, err := h.base.client.GetJSON(
path,
smfile.FileURIRequest{FileURI: string(fileUID)}.GetQuery(),
&res,
)
if err != nil {
return ProgressResponse{}, fmt.Errorf("failed to get progress file translation: %w", err)
}
return res, nil
}

func buildStartPath(accountUID AccountUID, fileUID FileUID) string {
return "/accounts/" + string(accountUID) + "/files/" + string(fileUID) + "/mt"
}

func buildProgressPath(accountUID AccountUID, fileUID FileUID, mtUID MtUID) string {
return "/accounts/" + string(accountUID) + "/files/" + string(fileUID) + "/mt/" + string(mtUID) + "/status"
}
99 changes: 99 additions & 0 deletions api/mt/file_translator_ent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package mt

// StartResponse defines start translation response
type StartResponse struct {
Code string
MtUID MtUID
}

// StartResponse defines start translation response
type startResponse struct {
Response struct {
Code string `json:"code"`
Data struct {
MtUID string `json:"mtUid"`
} `json:"data"`
} `json:"response"`
}

func toStartResponse(r startResponse) StartResponse {
return StartResponse{
Code: r.Response.Code,
MtUID: MtUID(r.Response.Data.MtUID),
}
}

// ProgressResponse defines progress translation response
type ProgressResponse struct {
Code string
State string
RequestedStringCount int
Error string
LocaleProcessStatuses []LocaleProcessStatusResponse
}

// LocaleProcessStatusResponse defines locale process status response
type LocaleProcessStatusResponse struct {
LocaleID string
State string
ProcessedStringCount int
Error ErrorResponse
}

// ErrorResponse defines error response
type ErrorResponse struct {
Key string
Message string
ErrorID string
}

// IsSet checks if ErrorResponse is set
func (e ErrorResponse) IsSet() bool {
return e.Key != ""
}

type progressResponse struct {
Response struct {
Code string `json:"code"`
Data struct {
State string `json:"state"`
RequestedStringCount int `json:"requestedStringCount"`
Error string `json:"error;omitempty"`
LocaleProcessStatuses []struct {
LocaleID string `json:"localeId"`
State string `json:"state"`
ProcessedStringCount int `json:"processedStringCount"`
Error *struct {
Key string `json:"key"`
Message string `json:"message"`
Details struct {
ErrorID string `json:"errorId"`
} `json:"details"`
} `json:"error"`
} `json:"localeProcessStatuses"`
} `json:"data"`
} `json:"response"`
}

func toProgressResponse(r progressResponse) ProgressResponse {
localeProcessStatuses := make([]LocaleProcessStatusResponse, len(r.Response.Data.LocaleProcessStatuses))
for key, val := range r.Response.Data.LocaleProcessStatuses {
localeProcessStatuses[key] = LocaleProcessStatusResponse{
LocaleID: val.LocaleID,
State: val.State,
ProcessedStringCount: val.ProcessedStringCount,
Error: ErrorResponse{
Key: val.Error.Key,
Message: val.Error.Message,
ErrorID: val.Error.Details.ErrorID,
},
}
}
return ProgressResponse{
Code: r.Response.Code,
State: r.Response.Data.State,
RequestedStringCount: r.Response.Data.RequestedStringCount,
Error: r.Response.Data.Error,
LocaleProcessStatuses: localeProcessStatuses,
}
}
58 changes: 58 additions & 0 deletions api/mt/file_type.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package mt

// FileType is type for file types
//
//go:generate stringer -type=FileType
type FileType int

const (
DOCX FileType = iota + 1
DOCM
RTF
PPTX
XLSX
IDML
RESX
PLAIN_TEXT
XML
HTML
PRES
SRT
MARKDOWN
DITA
VTT
FLARE
SVG
XLIFF2
CSV
JSON
XLSX_TEMPLATE
)

// FileTypeByExt contains map with FileType by file extension
var FileTypeByExt = map[string]FileType{
".docx": DOCX,
".docm": DOCM,
".rtf": RTF,
".pptx": PPTX,
".xlsx": XLSX,
".idml": IDML,
".resx": RESX,
".txt": PLAIN_TEXT,
".xml": XML,
".html": HTML,
".htm": HTML,
".pres": PRES,
".srt": SRT,
".md": MARKDOWN,
".markdown": MARKDOWN,
".dita": DITA,
".vtt": VTT,
".zip": FLARE,
".svg": SVG,
".xlf": XLIFF2,
".xliff": XLIFF2,
".csv": CSV,
".json": JSON,
".xlsx_template": XLSX_TEMPLATE,
}
44 changes: 44 additions & 0 deletions api/mt/filetype_string.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading