Skip to content

Commit 56046cf

Browse files
authored
feat(ai): add AI Translate Strings method support (#250)
1 parent 40dda5b commit 56046cf

3 files changed

Lines changed: 201 additions & 29 deletions

File tree

crowdin_api/api_resources/ai/resource.py

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,33 @@
11
from typing import Iterable, Optional, Union
22

33
from crowdin_api.api_resources.abstract.resources import BaseResource
4-
from crowdin_api.api_resources.ai.enums import AIPromptAction, AiPromptFineTuningJobStatus, AIProviderType
4+
from crowdin_api.api_resources.ai.enums import (
5+
AIPromptAction,
6+
AiPromptFineTuningJobStatus,
7+
AIProviderType,
8+
)
59
from crowdin_api.api_resources.ai.types import (
10+
AddAiCustomPlaceholderRequest,
611
AddAIPromptRequestScheme,
712
AddAIProviderReqeustScheme,
8-
EditAIPromptScheme,
9-
EditAIProviderRequestScheme,
10-
GoogleGeminiChatProxy,
11-
OtherChatProxy,
12-
GenerateAIPromptFineTuningDatasetRequest,
13+
AiFileTranslationRequest,
14+
AiTranslateStringsRequest,
1315
CreateAIPromptFineTuningJobRequest,
14-
AddAiCustomPlaceholderRequest,
1516
EditAiCustomPlaceholderPatch,
17+
EditAIPromptScheme,
18+
EditAIProviderRequestScheme,
19+
EditAiSettingsPatch,
1620
GenerateAiPromptCompletionRequest,
21+
GenerateAIPromptFineTuningDatasetRequest,
1722
GenerateAiReportRequest,
18-
EditAiSettingsPatch,
19-
AiFileTranslationRequest,
23+
GoogleGeminiChatProxy,
24+
OtherChatProxy,
2025
)
2126
from crowdin_api.sorting import Sorting
22-
from crowdin_api.utils import convert_enum_collection_to_string_if_exists, convert_enum_to_string_if_exists
27+
from crowdin_api.utils import (
28+
convert_enum_collection_to_string_if_exists,
29+
convert_enum_to_string_if_exists,
30+
)
2331

2432

2533
class AIResource(BaseResource):
@@ -778,6 +786,24 @@ def download_ai_file_translation_strings(
778786
path=self.get_ai_file_translations_path(user_id, job_identifier) + "/translations",
779787
)
780788

789+
def translate_ai_strings(
790+
self,
791+
user_id: int,
792+
request_data: AiTranslateStringsRequest,
793+
):
794+
"""
795+
AI Translate Strings
796+
797+
Link to documentation:
798+
https://support.crowdin.com/developer/api/v2/#tag/AI/operation/api.users.ai.translate.strings.post
799+
"""
800+
801+
return self.requester.request(
802+
method="post",
803+
path=f"users/{user_id}/ai/translate",
804+
request_data=request_data,
805+
)
806+
781807

782808
class EnterpriseAIResource(BaseResource):
783809
"""
@@ -1497,3 +1523,20 @@ def download_ai_file_translation_strings(
14971523
method="get",
14981524
path=self.get_ai_file_translations_path(job_identifier) + "/translations",
14991525
)
1526+
1527+
def translate_ai_strings(
1528+
self,
1529+
request_data: AiTranslateStringsRequest,
1530+
):
1531+
"""
1532+
AI Translate Strings
1533+
1534+
Link to documentation:
1535+
https://support.crowdin.com/developer/enterprise/api/v2/#tag/AI/operation/api.ai.translate-strings.post
1536+
"""
1537+
1538+
return self.requester.request(
1539+
method="post",
1540+
path="ai/translate",
1541+
request_data=request_data,
1542+
)

crowdin_api/api_resources/ai/tests/test_ai_resources.py

Lines changed: 132 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,39 @@
22
from unittest import mock
33

44
import pytest
5-
65
from crowdin_api.api_resources.ai.enums import (
76
AIPromptAction,
7+
AiPromptFineTuningJobStatus,
88
AIProviderType,
9+
AiReportFormat,
10+
AiToolType,
911
DatasetPurpose,
10-
AiPromptFineTuningJobStatus,
11-
ListAiPromptFineTuningJobsOrderBy,
1212
EditAiCustomPlaceholderPatchPath,
13-
AiToolType,
14-
AiReportFormat,
15-
EditAiSettingsPatchPath, ListSupportedAiModelsOrderBy
13+
EditAiSettingsPatchPath,
14+
ListAiPromptFineTuningJobsOrderBy,
15+
ListSupportedAiModelsOrderBy,
1616
)
1717
from crowdin_api.api_resources.ai.resource import AIResource, EnterpriseAIResource
1818
from crowdin_api.api_resources.ai.types import (
19+
AiFileTranslationRequest,
1920
AIPromptOperation,
20-
EditAIPromptPath,
21-
CreateAIPromptFineTuningJobRequest,
22-
HyperParameters,
23-
TrainingOptions,
24-
GenerateAIPromptFineTuningDatasetRequest,
25-
GenerateAiPromptCompletionRequest,
26-
PreTranslateActionAiPromptContextResources,
2721
AiTool,
28-
AiToolObject,
2922
AiToolFunction,
30-
GenerateAiReportRequest,
23+
AiToolObject,
24+
AiTranslateStringsRequest,
25+
CreateAIPromptFineTuningJobRequest,
26+
EditAIPromptPath,
3127
GeneralReportSchema,
32-
AiFileTranslationRequest,
28+
GenerateAiPromptCompletionRequest,
29+
GenerateAIPromptFineTuningDatasetRequest,
30+
GenerateAiReportRequest,
31+
HyperParameters,
32+
PreTranslateActionAiPromptContextResources,
33+
TrainingOptions,
3334
)
3435
from crowdin_api.api_resources.enums import PatchOperation
3536
from crowdin_api.requester import APIRequester
36-
from crowdin_api.sorting import Sorting, SortingRule, SortingOrder
37+
from crowdin_api.sorting import Sorting, SortingOrder, SortingRule
3738

3839

3940
class TestAIResources:
@@ -1205,6 +1206,64 @@ def test_download_ai_file_translation_strings(self, m_request, base_absolut_url)
12051206
path=f"users/{user_id}/ai/file-translations/{job_identifier}/translations",
12061207
)
12071208

1209+
@pytest.mark.parametrize(
1210+
"incoming_data, request_data",
1211+
(
1212+
(
1213+
AiTranslateStringsRequest(
1214+
strings=["Some text to translate!"],
1215+
targetLanguageId="uk",
1216+
),
1217+
{
1218+
"strings": ["Some text to translate!"],
1219+
"targetLanguageId": "uk",
1220+
},
1221+
),
1222+
(
1223+
AiTranslateStringsRequest(
1224+
strings=["Some text to translate!"],
1225+
targetLanguageId="uk",
1226+
sourceLanguageId="en",
1227+
tmIds=[123],
1228+
glossaryIds=[456],
1229+
styleGuideIds=[654],
1230+
aiPromptId=789,
1231+
aiProviderId=12,
1232+
aiModelId="gpt-4.1",
1233+
instructions=["Keep a formal tone"],
1234+
attachmentIds=[123],
1235+
),
1236+
{
1237+
"strings": ["Some text to translate!"],
1238+
"targetLanguageId": "uk",
1239+
"sourceLanguageId": "en",
1240+
"tmIds": [123],
1241+
"glossaryIds": [456],
1242+
"styleGuideIds": [654],
1243+
"aiPromptId": 789,
1244+
"aiProviderId": 12,
1245+
"aiModelId": "gpt-4.1",
1246+
"instructions": ["Keep a formal tone"],
1247+
"attachmentIds": [123],
1248+
},
1249+
),
1250+
),
1251+
)
1252+
@mock.patch("crowdin_api.requester.APIRequester.request")
1253+
def test_translate_ai_strings(self, m_request, incoming_data, request_data, base_absolut_url):
1254+
m_request.return_value = "response"
1255+
1256+
user_id = 1
1257+
1258+
resource = self.get_resource(base_absolut_url)
1259+
assert resource.translate_ai_strings(user_id, incoming_data) == "response"
1260+
1261+
m_request.assert_called_once_with(
1262+
method="post",
1263+
path=f"users/{user_id}/ai/translate",
1264+
request_data=request_data,
1265+
)
1266+
12081267

12091268
class TestEnterpriseAIResources:
12101269
resource_class = EnterpriseAIResource
@@ -2301,3 +2360,59 @@ def test_download_ai_file_translation_strings(self, m_request, base_absolut_url)
23012360
method="get",
23022361
path=f"ai/file-translations/{job_identifier}/translations",
23032362
)
2363+
2364+
@pytest.mark.parametrize(
2365+
"incoming_data, request_data",
2366+
(
2367+
(
2368+
AiTranslateStringsRequest(
2369+
strings=["Some text to translate!"],
2370+
targetLanguageId="uk",
2371+
),
2372+
{
2373+
"strings": ["Some text to translate!"],
2374+
"targetLanguageId": "uk",
2375+
},
2376+
),
2377+
(
2378+
AiTranslateStringsRequest(
2379+
strings=["Some text to translate!"],
2380+
targetLanguageId="uk",
2381+
sourceLanguageId="en",
2382+
tmIds=[123],
2383+
glossaryIds=[456],
2384+
styleGuideIds=[654],
2385+
aiPromptId=789,
2386+
aiProviderId=12,
2387+
aiModelId="gpt-4.1",
2388+
instructions=["Keep a formal tone"],
2389+
attachmentIds=[123],
2390+
),
2391+
{
2392+
"strings": ["Some text to translate!"],
2393+
"targetLanguageId": "uk",
2394+
"sourceLanguageId": "en",
2395+
"tmIds": [123],
2396+
"glossaryIds": [456],
2397+
"styleGuideIds": [654],
2398+
"aiPromptId": 789,
2399+
"aiProviderId": 12,
2400+
"aiModelId": "gpt-4.1",
2401+
"instructions": ["Keep a formal tone"],
2402+
"attachmentIds": [123],
2403+
},
2404+
),
2405+
),
2406+
)
2407+
@mock.patch("crowdin_api.requester.APIRequester.request")
2408+
def test_translate_ai_strings(self, m_request, incoming_data, request_data, base_absolut_url):
2409+
m_request.return_value = "response"
2410+
2411+
resource = self.get_resource(base_absolut_url)
2412+
assert resource.translate_ai_strings(incoming_data) == "response"
2413+
2414+
m_request.assert_called_once_with(
2415+
method="post",
2416+
path="ai/translate",
2417+
request_data=request_data,
2418+
)

crowdin_api/api_resources/ai/types.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44
AIPromptAction,
55
AIPromptOperation,
66
AIProviderType,
7+
AiToolType,
8+
EditAiCustomPlaceholderPatchPath,
79
EditAIPromptPath,
810
EditAIProviderPath,
9-
EditAiCustomPlaceholderPatchPath,
10-
AiToolType,
1111
EditAiSettingsPatchPath,
1212
)
1313
from crowdin_api.api_resources.enums import PatchOperation
@@ -302,3 +302,17 @@ class AiFileTranslationRequest(TypedDict):
302302
aiModelId: Optional[str]
303303
instructions: Optional[Iterable[str]]
304304
attachmentIds: Optional[Iterable[int]]
305+
306+
307+
class AiTranslateStringsRequest(TypedDict):
308+
strings: Iterable[str]
309+
targetLanguageId: str
310+
sourceLanguageId: Optional[str]
311+
tmIds: Optional[Iterable[int]]
312+
glossaryIds: Optional[Iterable[int]]
313+
styleGuideIds: Optional[Iterable[int]]
314+
aiPromptId: Optional[int]
315+
aiProviderId: Optional[int]
316+
aiModelId: Optional[str]
317+
instructions: Optional[Iterable[str]]
318+
attachmentIds: Optional[Iterable[int]]

0 commit comments

Comments
 (0)