How to use Azure AI Translator service for text translation

How to use Azure AI Translator service for text translation

Introduction

Azure AI Translator is a potent cloud-based tool provided by Microsoft that automates language translation and localization in applications, websites, and services. If you require translation capabilities in an application, Azure AI Translator can provide the solution.

Provisioning resource

To begin, we'll utilize the Azure CLI to deploy the necessary resources. Follow these steps:

  1. Create a resource group named translator-rg in the westeurope region:

     az group create --location westeurope --name translator-rg
    
  2. Create a Text Translator service named mytranslator within the translator-rg resource group:

     az cognitiveservices account create \
         --kind TextTranslation \ # We need TextTranslator
         --location WestEurope \
         --name mytranslator \
         --resource-group translator-rg \
         --sku S1 \
         --subscription 00000000-0000-0000-0000-000000000000 # Your subscription
         --yes
    

With these steps, you've established a resource group and created a Text Translator service.

To communicate with Translator API we need to have the endpoint of the service and keys. For text translation, we need to use the global endpoint https://api.cognitive.microsofttranslator.com/.

To retrieve the keys we need to execute the following command

az cognitiveservices account keys list --name mytranslator -g translator-rg

Copy and paste one key to the notepad.

For the production environment use Azure Key Vault to store keys. See "Use Azure Key Vault to store key" below in the article.

Now we have everything to make some translations using Azure AI Translator.

Working with API

Basic approach

We need to have some objects for request and response. Let's use records to create them.

internal record TranslationRequest(string Text) { }
internal record TranslationResponse(Translation[] Translations) { }
internal record Translation(string Text, string To) { }

Now we are ready to call the API.

using System.Net.Http.Json;

const string TranslatorKey = "[api-key]";
const string TranslatorEndpoint = "https://api.cognitive.microsofttranslator.com";
const string Location = "[location-of-resource]";

var text = "Let's translate some text";

using var request = new HttpRequestMessage(HttpMethod.Post, 
    $"{TranslatorEndpoint}/translate?api-version=3.0&from=en&to=es&to=cs&to=nl");
request.Headers.Add("Ocp-Apim-Subscription-Key", TranslatorKey);
request.Headers.Add("Ocp-Apim-Subscription-Region", Location);
request.Content = JsonContent.Create(new [] { new TranslationRequest(text) });

var response = await new HttpClient().SendAsync(request);
response.EnsureSuccessStatusCode();

var responseContent = await response.Content.ReadFromJsonAsync<TranslationResponse[]>();
var translations = responseContent?.First()?.Translations;

foreach (var translation in translations)
    Console.WriteLine($"{translation.To}: {translation.Text}");

Make sure to replace [api-key] with the key obtained from the translator account and [location-of-resource] with the location where your translation resource was created.

Pay attention to the requested URL $"{TranslatorEndpoint}/translate?api-version=3.0&from=en&to=es&to=fr&to=de" . Let's have a look into it more closely.

  • version=3.0 is the API version we want to use

  • from=en indicating that we would like to have a translation from English. This parameter is optional so if it is missing translator will try to detect the language.

  • &to=es&to=cs&to=nl the list of languages to translate text to. This is a required parameter. To get the list of all supported languages follow this link.

The result of running this code

Use Azure Key Vault to store key

The problem with the code is that we need to copy-paste and store the key with the application. From a security perspective, it is a breach because everyone can access it, and if for the testing environment, it is not a big problem it is better not to leak production keys.

To solve this problem we can use Azure Key Vault to store our key. Our application will know only about the key name and how to access it. Let's have a look at how to implement such an approach.

  1. Create a Key Vault with the name translatorappvault in the resource group translator-rg using Azure CLI.

     az keyvault create --location WestEurope \
        --name translatorappvault \
        --resource-group translator-rg
    
  2. Set key from Azure AI Translator.

    Note: Replace [api-key] with the actual key from the Translator resource.

     az keyvault secret set --vault-name translatorappvault \
        --name "TranslatorKey" \
        --value "[api-key]"
    
  3. Add the following packages to the solution:

     dotnet add package Azure.Security.KeyVault.Secrets
     dotnet add package Azure.Identity
    

    Azure.Security.KeyVault.Secrets provides the implementation of the API necessary to access Key Vault. Azure.Identity provides the authentication possibility.

  4. Accessing Key Vault and retrieving the key

     const string TranslatorKey = "TranslatorKey";
     const string KeyVaultEndpoint = "https://translatorappvault.vault.azure.net/";
    
     var client = new SecretClient(new Uri(KeyVaultEndpoint), new DefaultAzureCredential());
     var secretResponse = await client.GetSecretAsync(TranslatorKey);
    

    Notice that we use DefaultAzureCredential during the instantiation of SecretClient. This type of credential allows us to use passwordless authentication and the most important part is that this code will work similarly in every environment either development, testing, or production.

  5. In the last part, we need to change the header Ocp-Apim-Subscription-Key to use the key retrieved from Azure Key Vault.

     request.Headers.Add("Ocp-Apim-Subscription-Key", secretResponse.Value.Value);
    

Running this code will give the same translations as before with the only difference that we don't provide any key.

We still have room for improvement. As you remember we set the key to Key Vault manually and if for some reason we need to change it (leaks or key rotation) we need to perform the same steps. Not only is it error-prone but also a potential place for leaking credentials.

Small deployment improvement

To improve our solution we can use Bicep. The domain-specific language developed by Microsoft to describe and deploy Azure resources.

The following script describes our resources.

param principalId string
param location string = resourceGroup().location

var tenant = subscription().tenantId
var secretsUserRoleId = '4633458b-17de-408a-b874-0445c86b69e6'

resource translator 'Microsoft.CognitiveServices/accounts@2023-05-01' = {
  name: 'mytranslator'
  location: location
  sku: {
    name: 'S1'
    tier: 'Standard'
  }
  kind: 'TextTranslation'
  identity: {
    type: 'SystemAssigned'
  }
  properties: {  
  }
}

resource keyvault 'Microsoft.KeyVault/vaults@2023-02-01' = {
  name: 'translatorappvault'
  location: location
  properties: {
    tenantId: tenant
    sku: {
      family: 'A'
      name: 'standard'
    }
    enableRbacAuthorization: true
    accessPolicies: []
  }
}

resource translatorKeySecret 'Microsoft.KeyVault/vaults/secrets@2023-02-01' = {
  name: 'translatorKey'
  parent: keyvault
  properties: {
    value: translator.listKeys().key1
  }
}

resource secretsUserAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(keyvault.id, secretsUserRoleId, principalId)
  scope: keyvault
  properties: {
    roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', secretsUserRoleId)  
    principalId: principalId
    principalType: 'User'
  }
}

We have four different resources here translator, keyvault, translatorKeySecret and secretsUserAssignment let's have a look at them.

translator and keyvault are the resources we previously created with Azure CLI, but why do we need two others?

Previously we created translatorKeySecret as well as with the command az keyvault secret set. This resource holds the key to the translator API. The interesting part of this code is the following:

value: translator.listKeys().key1

In such a declarative way we say that the value for TranslatorKey is the key1 of translator. So that every time we deploy our resources this value would be set, thus the key would be up-to-date.

The latest resource is secretsUserAssignment with the type Microsoft.Authorization/roleAssignments permits the user to read secrets. Because right now we run our app on behalf of the user account we give such permission to the user. If our application were running in the cloud we would permit it instead of a user.

To execute the deployment script we need to obtain the principal ID of the user who runs the application. Execute the following command in the Azure CLI replacing [email-address-of-the-user] with your email address.

az ad user show --id "[email-address-of-the-user]" --query id --output tsv

Now we are ready to deploy our resources.

az deployment group create --resource-group translator-rg \
    --template-file resources.bicep \
    --parameters principalId="[guid-from-previous-step]"

resources.bicep is the file name of the deployment script. If you name it differently don't forget to change it in the command.

Running the application after the script has been finished should give identical translations.

Let's check that new keys are applied automatically. For that, we manually regenerate the key1 using this command.

az cognitiveservices account keys regenerate --name mytranslator \
    -g translator-rg \
    --key-name key1

Run the application and it should fail with 401 Unauthorized response.

It is expected because we changed the keys but did not redeploy our resources thus Key Vault still has the old key. Run the deployment command. When it is finished run the application to check that everything works as expected.

Summary

Azure AI Translator offers robust text translation capabilities that are fast and provide high-quality translations. At the same time, the use of keys instead of managed identity might be considered as a downside. We can use Azure Key Vault to eliminate this problem.

For more detailed information on available methods and features, refer to the official documentation.

Image credits: "Books" by Emily