Skip to content

Commit 8cf9e1f

Browse files
authored
Merge pull request #123 from Smartling/DEVORTEX-5169-Add-string-mt-api
DEVORTEX-5169 Added strings MT API
2 parents 0b83384 + 48df7b1 commit 8cf9e1f

8 files changed

+249
-3
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
interface TranslationTextItemDto {
2+
key: string;
3+
translationText: string;
4+
}
5+
6+
export { TranslationTextItemDto };

api/mt/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { SmartlingBaseApi } from "../base/index";
2+
import { SmartlingAuthApi } from "../auth/index";
3+
import { Logger } from "../logger";
4+
import { SmartlingMTParameters } from "./params/smartling-mt-parameters";
5+
import { SmartlingListResponse } from "../http/smartling-list-response";
6+
import { TranslationTextItemDto } from "./dto/translation-text-item-dto";
7+
8+
export class SmartlingMachineTranslationsApi extends SmartlingBaseApi {
9+
constructor(smartlingApiBaseUrl: string, authApi: SmartlingAuthApi, logger: Logger) {
10+
super(logger);
11+
this.authApi = authApi;
12+
this.entrypoint = `${smartlingApiBaseUrl}/mt-router-api/v2/accounts`;
13+
}
14+
15+
async translate(
16+
accountUid: string,
17+
params: SmartlingMTParameters
18+
): Promise<SmartlingListResponse<TranslationTextItemDto>> {
19+
return await this.makeRequest(
20+
"post",
21+
`${this.entrypoint}/${accountUid}/smartling-mt`,
22+
JSON.stringify(params.export())
23+
);
24+
}
25+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { SmartlingException } from "../../exception";
2+
import { BaseParameters } from "../../parameters";
3+
import { SourceTextItem } from "./source-text-item";
4+
5+
const MAX_ALLOWED_SOURCE_ITEMS = 1000;
6+
const MAX_ALLOWED_KEY_LENGTH = 255;
7+
const MAX_ALLOWED_SOURCE_TEXT_LENGTH = 64 * 1024;
8+
9+
export class SmartlingMTParameters extends BaseParameters {
10+
constructor(sourceLocaleId: string, targetLocaleId: string, items: SourceTextItem[]) {
11+
super();
12+
13+
if (!items.length) {
14+
throw new SmartlingException("At least one source text item is required.");
15+
}
16+
17+
if (items.length > MAX_ALLOWED_SOURCE_ITEMS) {
18+
throw new SmartlingException(`The request contains too many source text items: ${items.length}. Maximum allowed items number is ${MAX_ALLOWED_SOURCE_ITEMS}.`);
19+
}
20+
21+
items.forEach((sourceTextItem, index) => {
22+
if (!sourceTextItem.key.length) {
23+
throw new SmartlingException(`The key is requred for items[${index}].`);
24+
}
25+
if (sourceTextItem.key.length > MAX_ALLOWED_KEY_LENGTH) {
26+
throw new SmartlingException(`The key is too long for items[${index}]: ${sourceTextItem.key.length}. Maximum allowed key length is ${MAX_ALLOWED_KEY_LENGTH}.`);
27+
}
28+
if (!sourceTextItem.sourceText.length) {
29+
throw new SmartlingException(`The source text is requred for items[${index}].`);
30+
}
31+
if (sourceTextItem.sourceText.length > MAX_ALLOWED_SOURCE_TEXT_LENGTH) {
32+
throw new SmartlingException(`The source text is too long for items[${index}]: ${sourceTextItem.sourceText.length}. Maximum allowed source text length is ${MAX_ALLOWED_SOURCE_TEXT_LENGTH}.`);
33+
}
34+
});
35+
36+
this.set("sourceLocaleId", sourceLocaleId);
37+
this.set("targetLocaleId", targetLocaleId);
38+
this.set("items", items);
39+
}
40+
}

api/mt/params/source-text-item.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
interface SourceTextItem {
2+
key: string;
3+
sourceText: string;
4+
}
5+
6+
export { SourceTextItem };

index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,7 @@ export * from "./api/locales/dto/direction";
110110
export * from "./api/locales/dto/word-delimeter";
111111
export * from "./api/locales/params/get-locales-parameters";
112112
export * from "./api/locales/index";
113+
export * from "./api/mt/index";
114+
export * from "./api/mt/params/smartling-mt-parameters";
115+
export * from "./api/mt/params/source-text-item";
116+
export * from "./api/mt/dto/translation-text-item-dto";

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "smartling-api-sdk-nodejs",
3-
"version": "2.18.0",
3+
"version": "2.19.0",
44
"description": "Package for Smartling API",
55
"main": "built/index.js",
66
"engines": {

test/mt.spec.ts

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import sinon from "sinon";
2+
import assert from "assert";
3+
import { SmartlingMachineTranslationsApi } from "../api/mt";
4+
import { SmartlingMTParameters } from "../api/mt/params/smartling-mt-parameters";
5+
import { SmartlingAuthApi } from "../api/auth/index";
6+
import { SmartlingException } from "../api/exception/index";
7+
import { loggerMock, authMock, responseMock } from "./mock";
8+
9+
describe("SmartlinMachineTranslationsApi class tests.", () => {
10+
const accountUid = "testAccountUid";
11+
let mtApi;
12+
let mtApiFetchStub;
13+
let mtApiUaStub;
14+
let responseMockTextStub;
15+
16+
beforeEach(() => {
17+
mtApi = new SmartlingMachineTranslationsApi("https://test.com", authMock as unknown as SmartlingAuthApi, loggerMock);
18+
19+
mtApiFetchStub = sinon.stub(mtApi, "fetch");
20+
mtApiUaStub = sinon.stub(mtApi, "ua");
21+
responseMockTextStub = sinon.stub(responseMock, "text");
22+
23+
mtApiUaStub.returns("test_user_agent");
24+
mtApiFetchStub.returns(responseMock);
25+
responseMockTextStub.returns("{\"response\": {}}");
26+
});
27+
28+
afterEach(() => {
29+
mtApiFetchStub.restore();
30+
responseMockTextStub.restore();
31+
mtApiUaStub.restore();
32+
});
33+
34+
it("Translate using Smartling MT", async () => {
35+
const params = new SmartlingMTParameters(
36+
"en-US",
37+
"es-ES",
38+
[{
39+
key: "text.key",
40+
sourceText: "This is text for translation"
41+
}]
42+
);
43+
await mtApi.translate(accountUid, params);
44+
45+
sinon.assert.calledOnce(mtApiFetchStub);
46+
sinon.assert.calledWithExactly(
47+
mtApiFetchStub,
48+
`https://test.com/mt-router-api/v2/accounts/${accountUid}/smartling-mt`, {
49+
headers: {
50+
Authorization: "test_token_type test_access_token",
51+
"Content-Type": "application/json",
52+
"User-Agent": "test_user_agent"
53+
},
54+
method: "post",
55+
body: JSON.stringify({
56+
sourceLocaleId: "en-US",
57+
targetLocaleId: "es-ES",
58+
items: [{
59+
key: "text.key",
60+
sourceText: "This is text for translation"
61+
}]
62+
})
63+
}
64+
);
65+
});
66+
67+
it("Validation of MT parameters throws error when no source items specified", async () => {
68+
try {
69+
// eslint-disable-next-line no-new
70+
new SmartlingMTParameters(
71+
"en-US",
72+
"es-ES",
73+
[]
74+
);
75+
assert.fail("must throw SmartlingException");
76+
} catch (e) {
77+
assert.ok(e instanceof SmartlingException);
78+
}
79+
});
80+
81+
it("Validation of MT parameters throws error when number of source items exceeds limit", async () => {
82+
try {
83+
// eslint-disable-next-line no-new
84+
new SmartlingMTParameters(
85+
"en-US",
86+
"es-ES",
87+
Array(1001).fill({
88+
key: "key",
89+
sourceText: "string for translation"
90+
})
91+
);
92+
assert.fail("must throw SmartlingException");
93+
} catch (e) {
94+
assert.ok(e instanceof SmartlingException);
95+
}
96+
});
97+
98+
it("Validation of MT parameters throws error when source item has empty key", async () => {
99+
try {
100+
// eslint-disable-next-line no-new
101+
new SmartlingMTParameters(
102+
"en-US",
103+
"es-ES",
104+
[{
105+
key: "",
106+
sourceText: "text"
107+
}]
108+
);
109+
assert.fail("must throw SmartlingException");
110+
} catch (e) {
111+
assert.ok(e instanceof SmartlingException);
112+
}
113+
});
114+
115+
it("Validation of MT parameters throws error when source item has long key", async () => {
116+
try {
117+
// eslint-disable-next-line no-new
118+
new SmartlingMTParameters(
119+
"en-US",
120+
"es-ES",
121+
[{
122+
key: "A".repeat(256),
123+
sourceText: "text"
124+
}]
125+
);
126+
assert.fail("must throw SmartlingException");
127+
} catch (e) {
128+
assert.ok(e instanceof SmartlingException);
129+
}
130+
});
131+
132+
it("Validation of MT parameters throws error when source item has empty text", async () => {
133+
try {
134+
// eslint-disable-next-line no-new
135+
new SmartlingMTParameters(
136+
"en-US",
137+
"es-ES",
138+
[{
139+
key: "key",
140+
sourceText: ""
141+
}]
142+
);
143+
assert.fail("must throw SmartlingException");
144+
} catch (e) {
145+
assert.ok(e instanceof SmartlingException);
146+
}
147+
});
148+
149+
it("Validation of MT parameters throws error when source item has long text", async () => {
150+
try {
151+
// eslint-disable-next-line no-new
152+
new SmartlingMTParameters(
153+
"en-US",
154+
"es-ES",
155+
[{
156+
key: "key",
157+
sourceText: "A".repeat((64 * 1024) + 1)
158+
}]
159+
);
160+
assert.fail("must throw SmartlingException");
161+
} catch (e) {
162+
assert.ok(e instanceof SmartlingException);
163+
}
164+
});
165+
});

0 commit comments

Comments
 (0)