Skip to content

Commit 3e3297a

Browse files
jrjrguoJiarui GuoCopilot
authored
Text translation v2 ga (#46435)
* v2 init * update version & docs * update test setup to reuse preview endpoints * Fix Entra ID validation: resource_id required, region optional * fix pylint & pyright CI checks * feedback applied: + IO[bytes] overloads; hide internal models Co-authored-by: Copilot <copilot@github.com> --------- Co-authored-by: Jiarui Guo <jiarguo@microsoft.com> Co-authored-by: Copilot <copilot@github.com>
1 parent 06f23a2 commit 3e3297a

25 files changed

Lines changed: 675 additions & 439 deletions

sdk/translation/azure-ai-translation-text/CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Release History
22

3+
## 2.0.0 (2026-06-06)
4+
5+
### Features Added
6+
7+
- GA release of Azure AI Translator Text Translation SDK version 2.0.0.
8+
- Updated to stable API version 2026-06-06.
9+
- Added `TranslationTone` and `TranslationGender` enums for type-safe tone and gender options.
10+
11+
### Breaking Changes
12+
13+
- Removed `grade` parameter from translation options.
14+
15+
### Other Changes
16+
17+
- Simplified client constructor and internal authentication handling.
18+
319
## 2.0.0b1 (2026-01-08)
420

521
### Features Added
Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
{
2-
"apiVersion": "2025-10-01-preview"
2+
"apiVersion": "2026-06-06",
3+
"apiVersions": {
4+
"TextTranslation": "2026-06-06"
5+
}
36
}

sdk/translation/azure-ai-translation-text/apiview-properties.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
"azure.ai.translation.text.models.TextType": "TextTranslation.TextType",
2525
"azure.ai.translation.text.models.ProfanityAction": "TextTranslation.ProfanityAction",
2626
"azure.ai.translation.text.models.ProfanityMarker": "TextTranslation.ProfanityMarker",
27+
"azure.ai.translation.text.models.TranslationTone": "TextTranslation.TranslationTone",
28+
"azure.ai.translation.text.models.TranslationGender": "TextTranslation.TranslationGender",
2729
"azure.ai.translation.text.TextTranslationClient.get_supported_languages": "TextTranslation.getSupportedLanguages",
2830
"azure.ai.translation.text.aio.TextTranslationClient.get_supported_languages": "TextTranslation.getSupportedLanguages",
2931
"azure.ai.translation.text.TextTranslationClient.translate": "TextTranslation.translate",

sdk/translation/azure-ai-translation-text/azure/ai/translation/text/_client.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,46 @@
77
# --------------------------------------------------------------------------
88

99
from copy import deepcopy
10-
from typing import Any
10+
from typing import Any, Optional, TYPE_CHECKING, Union
1111
from typing_extensions import Self
1212

1313
from azure.core import PipelineClient
14+
from azure.core.credentials import AzureKeyCredential
1415
from azure.core.pipeline import policies
1516
from azure.core.rest import HttpRequest, HttpResponse
1617

1718
from ._configuration import TextTranslationClientConfiguration
1819
from ._operations import _TextTranslationClientOperationsMixin
1920
from ._utils.serialization import Deserializer, Serializer
2021

22+
if TYPE_CHECKING:
23+
from azure.core.credentials import TokenCredential
2124

22-
class TextTranslationClient(_TextTranslationClientOperationsMixin):
23-
"""Text translation is a cloud-based REST API feature of the Translator service that uses neural
24-
machine translation technology to enable quick and accurate source-to-target text translation
25-
in real time across all supported languages.
26-
27-
The following methods are supported by the Text Translation feature:
28-
29-
Languages. Returns a list of languages supported by Translate, Transliterate, and Dictionary
30-
Lookup operations.
3125

32-
Translate. Renders single source-language text to multiple target-language texts with a single
33-
request.
34-
35-
Transliterate. Converts characters or letters of a source language to the corresponding
36-
characters or letters of a target language.
37-
38-
Detect. Returns the source code language code and a boolean variable denoting whether the
39-
detected language is supported for text translation and transliteration.
26+
class TextTranslationClient(_TextTranslationClientOperationsMixin):
27+
"""Azure Translator is a cloud-based, multilingual, neural machine translation service. The Text
28+
Translation API enables robust and scalable translation capabilities suitable for diverse
29+
applications.
4030
4131
:param endpoint: Supported Text Translation endpoints (protocol and hostname, for example:
42-
`https://api.cognitive.microsofttranslator.com
32+
`https://api.cognitive.microsofttranslator.com
4333
<https://api.cognitive.microsofttranslator.com>`_). Required.
4434
:type endpoint: str
45-
:keyword api_version: Mandatory API version parameter. Default value is "2025-10-01-preview".
46-
Note that overriding this default value may result in unsupported behavior.
35+
:param credential: Credential used to authenticate requests to the service. Is either a key
36+
credential type or a token credential type. Default value is None.
37+
:type credential: ~azure.core.credentials.AzureKeyCredential or
38+
~azure.core.credentials.TokenCredential
39+
:keyword api_version: Mandatory API version parameter. Known values are "2026-06-06". Default
40+
value is "2026-06-06". Note that overriding this default value may result in unsupported
41+
behavior.
4742
:paramtype api_version: str
4843
"""
4944

50-
def __init__( # pylint: disable=missing-client-constructor-parameter-credential
51-
self, endpoint: str, **kwargs: Any
45+
def __init__(
46+
self, endpoint: str, credential: Optional[Union[AzureKeyCredential, "TokenCredential"]] = None, **kwargs: Any
5247
) -> None:
5348
_endpoint = "{Endpoint}"
54-
self._config = TextTranslationClientConfiguration(endpoint=endpoint, **kwargs)
49+
self._config = TextTranslationClientConfiguration(endpoint=endpoint, credential=credential, **kwargs)
5550

5651
_policies = kwargs.pop("policies", None)
5752
if _policies is None:

sdk/translation/azure-ai-translation-text/azure/ai/translation/text/_configuration.py

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,16 @@
66
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
77
# --------------------------------------------------------------------------
88

9-
from typing import Any
9+
from typing import Any, Optional, TYPE_CHECKING, Union
1010

11+
from azure.core.credentials import AzureKeyCredential
1112
from azure.core.pipeline import policies
1213

1314
from ._version import VERSION
1415

16+
if TYPE_CHECKING:
17+
from azure.core.credentials import TokenCredential
18+
1519

1620
class TextTranslationClientConfiguration: # pylint: disable=too-many-instance-attributes
1721
"""Configuration for TextTranslationClient.
@@ -20,26 +24,42 @@ class TextTranslationClientConfiguration: # pylint: disable=too-many-instance-a
2024
attributes.
2125
2226
:param endpoint: Supported Text Translation endpoints (protocol and hostname, for example:
23-
`https://api.cognitive.microsofttranslator.com
27+
`https://api.cognitive.microsofttranslator.com
2428
<https://api.cognitive.microsofttranslator.com>`_). Required.
2529
:type endpoint: str
26-
:keyword api_version: Mandatory API version parameter. Default value is "2025-10-01-preview".
27-
Note that overriding this default value may result in unsupported behavior.
30+
:param credential: Credential used to authenticate requests to the service. Is either a key
31+
credential type or a token credential type. Default value is None.
32+
:type credential: ~azure.core.credentials.AzureKeyCredential or
33+
~azure.core.credentials.TokenCredential
34+
:keyword api_version: Mandatory API version parameter. Known values are "2026-06-06". Default
35+
value is "2026-06-06". Note that overriding this default value may result in unsupported
36+
behavior.
2837
:paramtype api_version: str
2938
"""
3039

31-
def __init__(self, endpoint: str, **kwargs: Any) -> None:
32-
api_version: str = kwargs.pop("api_version", "2025-10-01-preview")
40+
def __init__(
41+
self, endpoint: str, credential: Optional[Union[AzureKeyCredential, "TokenCredential"]] = None, **kwargs: Any
42+
) -> None:
43+
api_version: str = kwargs.pop("api_version", "2026-06-06")
3344

3445
if endpoint is None:
3546
raise ValueError("Parameter 'endpoint' must not be None.")
3647

3748
self.endpoint = endpoint
49+
self.credential = credential
3850
self.api_version = api_version
51+
self.credential_scopes = kwargs.pop("credential_scopes", ["https://cognitiveservices.azure.com/.default"])
3952
kwargs.setdefault("sdk_moniker", "ai-translation-text/{}".format(VERSION))
4053
self.polling_interval = kwargs.get("polling_interval", 30)
4154
self._configure(**kwargs)
4255

56+
def _infer_policy(self, **kwargs):
57+
if isinstance(self.credential, AzureKeyCredential):
58+
return policies.AzureKeyCredentialPolicy(self.credential, "Ocp-Apim-Subscription-Key", **kwargs)
59+
if hasattr(self.credential, "get_token"):
60+
return policies.BearerTokenCredentialPolicy(self.credential, *self.credential_scopes, **kwargs)
61+
raise TypeError(f"Unsupported credential: {self.credential}")
62+
4363
def _configure(self, **kwargs: Any) -> None:
4464
self.user_agent_policy = kwargs.get("user_agent_policy") or policies.UserAgentPolicy(**kwargs)
4565
self.headers_policy = kwargs.get("headers_policy") or policies.HeadersPolicy(**kwargs)
@@ -50,3 +70,5 @@ def _configure(self, **kwargs: Any) -> None:
5070
self.redirect_policy = kwargs.get("redirect_policy") or policies.RedirectPolicy(**kwargs)
5171
self.retry_policy = kwargs.get("retry_policy") or policies.RetryPolicy(**kwargs)
5272
self.authentication_policy = kwargs.get("authentication_policy")
73+
if self.credential and not self.authentication_policy:
74+
self.authentication_policy = self._infer_policy(**kwargs)

sdk/translation/azure-ai-translation-text/azure/ai/translation/text/_model_base.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,7 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915,
687687

688688
# is it optional?
689689
try:
690+
# pylint: disable=unidiomatic-typecheck
690691
if any(a for a in annotation.__args__ if a == type(None)): # pyright: ignore
691692
if len(annotation.__args__) <= 2: # pyright: ignore
692693
if_obj_deserializer = _get_deserialize_callable_from_annotation(
@@ -697,6 +698,7 @@ def _get_deserialize_callable_from_annotation( # pylint: disable=R0911, R0915,
697698
# the type is Optional[Union[...]], we need to remove the None type from the Union
698699
annotation_copy = copy.copy(annotation)
699700
annotation_copy.__args__ = [a for a in annotation_copy.__args__ if a != type(None)] # pyright: ignore
701+
# pylint: enable=unidiomatic-typecheck
700702
return _get_deserialize_callable_from_annotation(annotation_copy, module, rf)
701703
except AttributeError:
702704
pass

sdk/translation/azure-ai-translation-text/azure/ai/translation/text/_operations/_operations.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def build_text_translation_get_supported_languages_request( # pylint: disable=n
5454
_headers = case_insensitive_dict(kwargs.pop("headers", {}) or {})
5555
_params = case_insensitive_dict(kwargs.pop("params", {}) or {})
5656

57-
api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2025-10-01-preview"))
57+
api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-06"))
5858
accept = _headers.pop("Accept", "application/json")
5959

6060
# Construct URL
@@ -86,7 +86,7 @@ def build_text_translation_translate_request(*, client_trace_id: Optional[str] =
8686
_params = case_insensitive_dict(kwargs.pop("params", {}) or {})
8787

8888
content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None))
89-
api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2025-10-01-preview"))
89+
api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-06"))
9090
accept = _headers.pop("Accept", "application/json")
9191

9292
# Construct URL
@@ -112,7 +112,7 @@ def build_text_translation_transliterate_request( # pylint: disable=name-too-lo
112112
_params = case_insensitive_dict(kwargs.pop("params", {}) or {})
113113

114114
content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None))
115-
api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2025-10-01-preview"))
115+
api_version: str = kwargs.pop("api_version", _params.pop("api-version", "2026-06-06"))
116116
accept = _headers.pop("Accept", "application/json")
117117

118118
# Construct URL
@@ -218,6 +218,7 @@ def get_supported_languages(
218218
}
219219
_request.url = self._client.format_url(_request.url, **path_format_arguments)
220220

221+
_decompress = kwargs.pop("decompress", True)
221222
_stream = kwargs.pop("stream", False)
222223
pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access
223224
_request, stream=_stream, **kwargs
@@ -243,7 +244,7 @@ def get_supported_languages(
243244
response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag"))
244245

245246
if _stream:
246-
deserialized = response.iter_bytes()
247+
deserialized = response.iter_bytes() if _decompress else response.iter_raw()
247248
else:
248249
deserialized = _deserialize(_models.GetSupportedLanguagesResult, response.json())
249250

@@ -334,7 +335,7 @@ def translate(
334335
@api_version_validation(
335336
method_added_on="2025-10-01-preview",
336337
params_added_on={"2025-10-01-preview": ["client_trace_id", "api_version", "content_type", "accept"]},
337-
api_versions_list=["2025-10-01-preview"],
338+
api_versions_list=["2025-10-01-preview", "2026-06-06"],
338339
)
339340
def translate(
340341
self,
@@ -391,6 +392,7 @@ def translate(
391392
}
392393
_request.url = self._client.format_url(_request.url, **path_format_arguments)
393394

395+
_decompress = kwargs.pop("decompress", True)
394396
_stream = kwargs.pop("stream", False)
395397
pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access
396398
_request, stream=_stream, **kwargs
@@ -417,7 +419,7 @@ def translate(
417419
response_headers["x-metered-usage"] = self._deserialize("int", response.headers.get("x-metered-usage"))
418420

419421
if _stream:
420-
deserialized = response.iter_bytes()
422+
deserialized = response.iter_bytes() if _decompress else response.iter_raw()
421423
else:
422424
deserialized = _deserialize(_models.TranslationResult, response.json())
423425

@@ -563,7 +565,7 @@ def transliterate(
563565
"accept",
564566
]
565567
},
566-
api_versions_list=["2025-10-01-preview"],
568+
api_versions_list=["2025-10-01-preview", "2026-06-06"],
567569
)
568570
def transliterate(
569571
self,
@@ -638,6 +640,7 @@ def transliterate(
638640
}
639641
_request.url = self._client.format_url(_request.url, **path_format_arguments)
640642

643+
_decompress = kwargs.pop("decompress", True)
641644
_stream = kwargs.pop("stream", False)
642645
pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access
643646
_request, stream=_stream, **kwargs
@@ -662,7 +665,7 @@ def transliterate(
662665
response_headers["X-RequestId"] = self._deserialize("str", response.headers.get("X-RequestId"))
663666

664667
if _stream:
665-
deserialized = response.iter_bytes()
668+
deserialized = response.iter_bytes() if _decompress else response.iter_raw()
666669
else:
667670
deserialized = _deserialize(_models.TransliterateResult, response.json())
668671

sdk/translation/azure-ai-translation-text/azure/ai/translation/text/_operations/_patch.py

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ class _TextTranslationClientOperationsMixin(
2828
):
2929
"""Mixin class that delegates to the generated operations class while providing custom method signatures."""
3030

31-
def _get_generated_operations(self) -> _TextTranslationClientOperationsMixinGenerated: # pylint: disable=protected-access
31+
def _get_generated_operations(
32+
self,
33+
) -> _TextTranslationClientOperationsMixinGenerated: # pylint: disable=protected-access
3234
"""Get an instance of the generated operations mixin.
3335
3436
This creates a wrapper object that shares the same _client, _config, _serialize, and _deserialize
@@ -191,6 +193,32 @@ def translate(
191193
:raises ~azure.core.exceptions.HttpResponseError:
192194
"""
193195

196+
@overload # type: ignore[override]
197+
def translate(
198+
self,
199+
body: IO[bytes],
200+
*,
201+
client_trace_id: Optional[str] = None,
202+
content_type: str = "application/json",
203+
**kwargs: Any
204+
) -> List[_models.TranslatedTextItem]:
205+
"""Translate text.
206+
207+
Translates text using a raw bytes stream as the request body.
208+
209+
:param body: The request body as a file-like stream of bytes. Required.
210+
:type body: IO[bytes]
211+
:keyword client_trace_id: A client-generated GUID to uniquely identify the request. Default
212+
value is None.
213+
:paramtype client_trace_id: str
214+
:keyword content_type: Body Parameter content-type. Content type parameter for JSON body.
215+
Default value is "application/json".
216+
:paramtype content_type: str
217+
:return: list of TranslatedTextItem
218+
:rtype: list[~azure.ai.translation.text.models.TranslatedTextItem]
219+
:raises ~azure.core.exceptions.HttpResponseError:
220+
"""
221+
194222
def translate( # pyright: ignore[reportIncompatibleMethodOverride]
195223
self,
196224
body: Union[List[str], List[_models.TranslateInputItem], JSON, IO[bytes]],
@@ -352,6 +380,47 @@ def transliterate(
352380
:raises ~azure.core.exceptions.HttpResponseError:
353381
"""
354382

383+
@overload # type: ignore[override]
384+
def transliterate(
385+
self,
386+
body: IO[bytes],
387+
*,
388+
language: str,
389+
from_script: str,
390+
to_script: str,
391+
client_trace_id: Optional[str] = None,
392+
content_type: str = "application/json",
393+
**kwargs: Any
394+
) -> List[_models.TransliteratedText]:
395+
"""Transliterate Text.
396+
397+
Transliterates text using a raw bytes stream as the request body.
398+
399+
:param body: The request body as a file-like stream of bytes. Required.
400+
:type body: IO[bytes]
401+
:keyword language: Specifies the language of the text to convert from one script to another.
402+
Possible languages are listed in the transliteration scope obtained by querying the service
403+
for its supported languages. Required.
404+
:paramtype language: str
405+
:keyword from_script: Specifies the script used by the input text. Look up supported languages
406+
using the transliteration scope,
407+
to find input scripts available for the selected language. Required.
408+
:paramtype from_script: str
409+
:keyword to_script: Specifies the output script. Look up supported languages using the
410+
transliteration scope, to find output
411+
scripts available for the selected combination of input language and input script. Required.
412+
:paramtype to_script: str
413+
:keyword client_trace_id: A client-generated GUID to uniquely identify the request. Default
414+
value is None.
415+
:paramtype client_trace_id: str
416+
:keyword content_type: Body Parameter content-type. Content type parameter for JSON body.
417+
Default value is "application/json".
418+
:paramtype content_type: str
419+
:return: list of TransliteratedText
420+
:rtype: list[~azure.ai.translation.text.models.TransliteratedText]
421+
:raises ~azure.core.exceptions.HttpResponseError:
422+
"""
423+
355424
def transliterate( # pyright: ignore[reportIncompatibleMethodOverride]
356425
self,
357426
body: Union[List[str], List[_models.InputTextItem], JSON, IO[bytes]],

0 commit comments

Comments
 (0)