Create Local Translations with Microsoft Translator to Update Display Names and Tooltips for Sensitivity Labels

Microsoft Purview Sensitivity Labels support multilingual values for display names and tooltips. This is a nice feature to have when tenant users work in multiple languages. The downside is that PowerShell is the only public method to write language (locale) values into a label. So far, Microsoft hasn’t released a Graph API covering this task.

Breaking out PowerShell and coping with the esoteric formatting requirements to pass language codes and translated text in hash tables is acceptable for a one-time operation involving just a few labels. It becomes boring when there’s more than a few languages to deal with, the display names and tooltips change, or the organization uses a large set of sensitivity labels.

A more developed version of Microsoft’s example PowerShell code seemed like a good idea, especially if I could use an automated method to translate the English-language display names and tooltips into a set of target languages. The alternative is to enter text into a web-based translation service and paste the result into a script. That works for one label but becomes tiresome after two or three labels.

Cybersecurity Risk Management for Active Directory

Discover how to prevent and recover from AD attacks through these Cybersecurity Risk Management Solutions.

Using the Microsoft Translator Service

The first challenge was finding a suitable translation service accessible from PowerShell. Microsoft Translator is a cloud-based translation service that has a REST API offering free translation of up to 2 million characters per month, which is more than enough to translate some label display names and tooltips. The prerequisite is that you must have an Azure subscription connected to Microsoft Translator to use the service. The steps to configure the connection are straightforward. The outcome is a subscription key that allows Translator to identify the source of a call to translate some string data.

$TranslatorKey = "10e21011ba2747a0996c4134492bfc17"  # This key depends on your subscription...

$global:BaseUri = "https://api.cognitive.microsofttranslator.com/translate?api-version=3.0"
$global:Headers = @{
    'Ocp-Apim-Subscription-Key' = $translatorKey
    'Ocp-Apim-Subscription-Region' = 'northeurope' # added (change if needed)
    'Content-type' = 'application/json; charset=utf-8'
}

With the translator key and other information defined, a simple function to translate a string looks like this:

Function Translate-String {
  [cmdletbinding()]
    Param(
        [string]$InputString,
        [string]$LanguageCode )

$textJson = @{
        "Text" = $InputString
    } | ConvertTo-Json
$Body = "[$textJson]"

$Uri = "$($global:BaseUri)&to=$($LanguageCode)&textType=html"
$Status = Invoke-RestMethod -Method Post -Uri $Uri -Headers $global:Headers -Body $Body
$Translation = $Status[0].translations[0].text

Return $Translation }

The Google Alternative

Google Translate is another option if you don’t have an Azure subscription. Here’s the function written to use Google Translate:

Function Translate-String {
  [cmdletbinding()]
    Param(
        [string]$InputString,
        [string]$LanguageCode )

# See https://github.com/ssut/py-googletrans/issues/268
# Language codes https://developers.google.com/admin-sdk/directory/v1/languages

$Uri = "https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=$($LanguageCode)&dt=t&q=$InputString"
$Response = Invoke-RestMethod -Uri $Uri -Method Get

$Translation = $Response[0].SyncRoot | foreach { $_[0] }

Return $Translation}

I found details of how to use Google Translator through an internet search. However, the method is not from a formal Google website and doesn’t appear to have a connection to Google, so I have no idea how long this method of using Google Translate will work. With that thought in mind, it might be best to focus on Microsoft Translator.

Finding and Processing Local Language Values for Sensitivity Labels

Now that we’ve identified a suitable translation service, the next step is to find the set of sensitivity labels to process. You could process all labels, but it’s more reasonable to process the set used with files and documents. This code uses the Get-Label cmdlet to find the full set of sensitivity labels and filters the site to select the labels used for information protection. You could translate the names of sensitivity labels used for container management, but since administrators primarily use those labels and know what the labels do, translation is possibly not as valuable.

Before running Get-Label, you need to connect to the Exchange Online management endpoint with Connect-ExchangeOnline and then to the compliance endpoint with Connect-IPPSSession.

# Find set of labels that support LLV strings
[array]$FileLabels = Get-Label | Where-Object {$_.ContentType -Like "*File*"}

We also declare a set of languages that we’re going to translate in an array. There’s no real need to do this because you can specify the language codes when updating label properties. I do so in the script to define the codes that I plan to use and the order to pass the local language values to the Set-Label cmdlet.

$Languages = @("fr-fr","it-it","de-de")

To translate the label names and tooltips, the code loops through the set of labels to:

  • Fetch the English text for the display name and tooltip properties.
  • Translate the label name and tooltip into the set of target languages (French, Italian, and German),
  • Update the label with the local settings for the target languages. When calling Set-Label to update a label, specify the target language using the ISO639-1 code (Microsoft 365 must support the language).

The script creates two PowerShell objects containing the translated values for the display name and tooltip to apply to a sensitivity label. Here’s what the hash table for the translated values of the display name for the Public sensitivity label looks like. You can see four languages here because I tested with multiple language combinations:

$DisplayNameLocaleSettings | Select-Object -ExpandProperty Settings

Name                           Value
----                           -----
key                            fr-fr
Value                          Public
key                            it-it
Value                          Pubblico
key                            de-de
Value                          Öffentlich
key                            ar-ar
Value                          علني

Here’s the code that does the work to translate sensitivity label names and tooltips and update the labels with the new settings:

ForEach ($Label in $FileLabels) {
   $FrenchDisplayName = $Null; $GermanDisplayName = $Null; $ItalianDisplayName = $Null
   $FrenchTooltip = $Null; $GermanToolTip = $Null; $FrenchToolTip = $Null
   Write-Host ("Setting language values for the {0} label" -f $Label.displayname)
   [string]$FrenchDisplayName = Translate-String -InputString $Label.DisplayName -LanguageCode "fr"
   [string]$FrenchTooltip = Translate-String -InputString $Label.ToolTip -LanguageCode "fr"
   [string]$ItalianDisplayName = Translate-String -InputString $Label.DisplayName -LanguageCode "it"
   [string]$ItalianTooltip = Translate-String -InputString $Label.ToolTip -LanguageCode "it"
   [string]$GermanDisplayName = Translate-String -InputString $Label.DisplayName -LanguageCode "de"
   [string]$GermanTooltip = Translate-String -InputString $Label.ToolTip -LanguageCode "de"
   $DisplayNameLocaleSettings = [PSCustomObject]@{LocaleKey='DisplayName';
    Settings=@(
       @{key=$Languages[0];Value=$FrenchDisplayName;}
       @{key=$Languages[1];Value=$ItalianDisplayName;}   
       @{key=$Languages[2];Value=$GermanDisplayName;})}
  $TooltipLocaleSettings = [PSCustomObject]@{LocaleKey='Tooltip';
   Settings=@(
       @{key=$Languages[0];Value=$FrenchToolTip;}
       @{key=$Languages[1];Value=$ItalianToolTip;}
       @{key=$Languages[2];Value=$GermanToolTip;})}
 Set-Label -Identity $Label.ImmutableId -LocaleSettings (ConvertTo-Json $DisplayNameLocaleSettings -Depth 3 -Compress),(ConvertTo-Json $TooltipLocaleSettings -Depth 3 -Compress)
}

If you use different languages in your tenant, you can update the script to replace the two-character language code used by Translator. For instance, the code for Spanish is “es” while it’s “bg” for Bulgarian. If you want to support additional languages, copy the code for an existing language, update it for the chosen language, and add the language settings to the hash tables passed to the Set-Label cmdlet. The advantage of using automatic translation is that adding an extra language should take you less than ten minutes.

Pausing for Cache Refreshes

After the script runs, a short delay is necessary to allow clients like OWA and the SharePoint browser to refresh their label cache before clients configured in the target languages use the translated values. Figure 1 shows the set of sensitivity labels when the OWA language is French, including a tooltip.

French translations of sensitivity label display names and tooltip generated by Microsoft Translator and shown by OWA
Figure 1: French translations of sensitivity label display names and tooltip shown by OWA

The text for display names and tooltip shown in Figure 1 comes from Microsoft Translator. Like any automatic process, it’s possible that some of the automatically-generated text might benefit from human tweaking to ensure that a name or tooltip accurately conveys the purpose of a sensitivity label.

You can download the full script from GitHub.

Catching Changes

To make sure that updates for the English text in sensitivity labels are transposed into local languages, you could schedule the script as an Azure Automation runbook to run as a monthly job. I don’t imagine that the English values will change often, but the scheduled job will apply local language values for new sensitivity labels too.

Perhaps your international colleagues have no need of translated sensitivity labels because they understand the English names and tooltips (perhaps helped by the colors assigned to labels). If not, it’s good to be able to assign local language values, and even better to have those values translated automatically. And the knowledge of using Microsoft Translator to translate strings into different languages might prove useful in the future.

The Microsoft 365 Kill Chain and Attack Path Management

An effective cybersecurity strategy requires a clear and comprehensive understanding of how attacks unfold. Read this whitepaper to get the expert insight you need to defend your organization!

About the Author

Tony Redmond

Tony Redmond has written thousands of articles about Microsoft technology since 1996. He is the lead author for the Office 365 for IT Pros eBook, the only book covering Office 365 that is updated monthly to keep pace with change in the cloud. Apart from contributing to Practical365.com, Tony also writes at Office365itpros.com to support the development of the eBook. He has been a Microsoft MVP since 2004.

Comments

  1. Elmar

    Thanks Tony, thats a great help! BTW, would you know how M365 handles different languages, where the labels and tool-tipps are not available in the target language? So, I would have English and German labels, but someone in Bulgaria uses a Bulgarian version of M365. Which language labels would they see?

    1. Avatar photo
      Tony Redmond

      They see the default language name, which is often in English (but need not be).

  2. Mats Gustafsson

    Nicely done, thanks
    Is there a way to translate ‘context marking’ in a similar way?

      1. Ruediger Riediger

        I assume this is a reference to the header (ApplyContentMarkingHeaderText) or footer marking text (ApplyContentMarkingFooterText), or the watermark (ApplyWaterMarkingText).
        We are facing the same challenge, so I am interested in the options.

        1. Avatar photo
          Tony Redmond

          Translated values for the label displayname are stored in LocaleSettings. There is no equivalent to apply localized versions of watermarks, headers, or footers.

          LocaleSettings : {{“LocaleKey”:”displayName”,”Settings”:[{“Key”:”default”,”Value”:”Market
          Sensitive”},{“Key”:”fr-fr”,”Value”:”Sensible au marché”},{“Key”:”it-it”,”Value”:”Sensibile al
          mercato”},{“Key”:”de-de”,”Value”:”Marktsensibel”}]},
          {“LocaleKey”:”tooltip”,”Settings”:[{“Key”:”default”,”Value”:”Information that if it leaked out could compromise
          our business”},{“Key”:”fr-fr”,”Value”:”Des informations qui, si elles fuyaient, pourraient compromettre notre
          entreprise”},{“Key”:”it-it”,”Value”:”Informazioni che se trapelate potrebbero compromettere la nostra
          attività”},{“Key”:”de-de”,”Value”:”Informationen, die, wenn sie durchsickern, unser Geschäft gefährden
          könnten”}]}}

  3. Enrique Saggese

    This is amazing work Tony!

Leave a Reply