Sitecore Translation using ChatGPT and PowerShell

In recent times IT professionals or someone who has interest in Technology and stuffs would definitely heard about ChatGPT . Right? Of course a BIG YES.

Onto my next question. Can we communicate with it & leverage its power to make something out of it in Sitecore? To my surprise it was so simple to do that via PowerShell.

Recently I was working on a POC about Semi-Automated Content Translation in Sitecore and found out this.

Problem statement : Translate a Sitecore Item’s field value from one language to another.

Lets jump into development …

Steps to get started…

1) Login/Signup with OpenAI (https://platform.openai.com/login) and get secret API key (https://help.openai.com/en/articles/4936850-where-do-i-find-my-secret-api-key)

2) Create a template in Sitecore to define the fields to be translated & API key

3) Create a Translation settings item based on this template and add values (Fields to be translated & API key) under /sitecore/system/Modules/GPT Translation/GPT Translate Settings

4) Create a PowerShell module and add the following script 
#Grab the Context Item
$sourceItem = Get-Item .

#Load our Settings including Languages and Fields to Translate
$settings = Get-Item  "master:\sitecore\system\Modules\GPT Translation\GPT Translate Settings" -Language "en"

$apiKey = $settings["ChatGPT API Key"]

$filterFields = ([Sitecore.Data.Fields.MultilistField]$settings.Fields["Fields To Be Translated"]).GetItems()

$commonLanguages =  Get-ChildItem  -Item $settings -Language "en"

$fieldsOptions = @{}

$filterFields | ForEach-Object {
    $fieldsOptions.Add($_.Name, $_.ID)
}

#Grab languages from the system
$languages = Get-ChildItem  "master:\sitecore\system\Languages" -Language "en"

#Grab workflows from the system
$workflows = Get-ChildItem "master:\sitecore\system\Workflows" -Language "en"

$languageOptions = @{}

$languages | ForEach-Object {
    $languageOptions.Add($_.Name, $_.Name)
}

$workflowOptions = @{}

$workflows | ForEach-Object {
    $workflowOptions.Add($_.Name, $_.Name)
}

#Remove Current Language
$languageOptions.Remove($SitecoreContextItem.Language.Name)

$props = @{
    Parameters = @(
        @{Name="fieldsToTranslateOption"; Editor="Checklist"; Title="Choose which fields to translate"; Options=$fieldsOptions; Tooltip="This list is configurable."}
        @{Name="languagesToTranslateOption"; Title="Choose which language to translate to."; Options=$languageOptions}
		@{Name="workflowtobeapplied"; Title="Choose which workflow to apply for translated item."; Options=$workflowOptions}

    )
    Title = "GPT Translation"
    Description = "Choose the right option."
    Width = 600
    Height = 400
    ShowHints = $true
}

$res = Read-Variable @props

#We need to map our ISO Code (es-MX) to a friendly language (Spanish)
$languages | Foreach-Object {
    
    $langCode = $_.Name
    #Write-Host "LangCode:" $langCode "languagesToTranslateOption selected :" $languagesToTranslateOption
    if($langCode -eq $languagesToTranslateOption)
    {
        $commonLang = $_.DisplayName
        #Write-Host "Common Lang"$_.DisplayName
    }
    
}

Write-Host "API Key:" $apiKey
Write-Host "Fields to Translate:" $fieldsToTranslateOption
Write-Host "Current Language:" $SitecoreContextItem.Language.Name
Write-Host "Selected Language:" $languagesToTranslateOption
Write-Host "Selected Language (Common):" $commonLang 
Write-Host "Translating for: " $sourceItem.Name
Write-Host "Filter Count: " $filterFields.Count.ToString()

#If we didn't click OK, then it isn't OK!
if($res -ne "ok")
{
    Show-Alert "Aborted"
    Exit
}

#we need to make sure all the fields to translate exist on this item and remove the ones that don't
$filteredFields = New-Object -TypeName 'System.Collections.ArrayList'

$sourceItem.Fields | ForEach-Object {
    $sourceField = $_
    
    
    $filterFields | ForEach-Object { 
        
        if($_.ID -eq $sourceField.ID)
        {
            Write-Host "Found" $_.Name
            $filteredFields.Add($_)
        }
    }
}

Write-Host "Translatable Fields Count: " $filteredFields.Count.ToString()

#Using our fields, let's create a list of translation objects we'll iterate through
$translations = New-Object -TypeName 'System.Collections.ArrayList'

$filteredFields | ForEach-Object {

     $fieldDef = Get-Item -Path master: -ID $_.ID
    
    $translationItem = @{
        FieldID = $_.ID
        Untranslated = $sourceItem.Fields[$_.ID].Value
        Translated = ""
        FieldType = $fieldDef.Type        
        
    }
        
    $translations.Add($translationItem)
    
}
$translations | ForEach-Object {

    $translationAsk = "Text"

   #making RichText field type as markup so that it does not break
    if($_.FieldType -eq "Rich Text")
    {
        $translationAsk = "markup"
    }
    #Removing unwanted quotes if any present in Untranslated text
     if($_.Untranslated[0] -eq "`"" -and $_.Untranslated[($_.Untranslated.Length-1)] -eq "`"")
    {
      $_.Untranslated = $_.Untranslated.substring(1, ($_.Untranslated.Length -2)).Trim()
    }
    $headers = @{
       Authorization = "Bearer " + $apiKey
    }
    
    #Generate our prompt
    #Translate the following Text/HTML to Target Language
    $data = @{
        model = "gpt-3.5-turbo"
        messages = @(
            @{
                role = "user"
                content = "Translate the following " + $translationAsk + " to " + $commonLang + " `"" + $_.Untranslated + "`""
            }
        )
    
    }
   Write-Host "PayLoad is:" "Translate the following " $translationAsk  " to " $commonLang $_.Untranslated
    $Params = @{
        Method = "POST"
        Headers = $headers
        
        Body = $data | ConvertTo-Json
        Uri = "https://api.openai.com/v1/chat/completions"
        ContentType = "application/json; charset=utf-8"
    }
    
    $result = (Invoke-RestMethod @Params).choices[0]
    
    $_.Translated = $result.message.content
}
$targetItem = Add-ItemVersion -Item $sourceItem -TargetLanguage $languagesToTranslateOption

$workflows | ForEach-Object {
    $workflw = $_.Name
    #Write-Host $_.Name
    if($workflw -eq $workflowtobeapplied)
    {
        $selectedworkflow = $_.ID
    }
    
}
$itemId = Get-Item master: -ID $selectedworkflow

$workflowstates = Get-ChildItem $itemId.Paths.FullPath -Language "en"
$workflowstateOptions = @{}

$workflowstates | ForEach-Object {
    $workflowstateOptions.Add($_.Name, $_.Name)
}

$props = @{
    Parameters = @(       
		@{Name="workstatetobeapplied"; Title="Choose which workflow state needs to be applied for translated item."; Options=$workflowstateOptions}
    )
    Title = "GPT Translation"
    Description = "Choose the right option."
    Width = 600
    Height = 400
    ShowHints = $true
}


$res = Read-Variable @props
if($res -ne "ok")
{
    Show-Alert "Aborted"
    Exit
}

$workflows | ForEach-Object {
    $workflw = $_.Name
    #Write-Host $_.Name
    if($workflw -eq $workflowtobeapplied)
    {
        $selectedworkflow = $_.ID
		Write-Host "WorkflowID to be applied" $selectedworkflow
		$itemId = Get-Item master: -ID $selectedworkflow
		$workflowstates = Get-ChildItem $itemId.Paths.FullPath -Language "en"
		$workflowstates | ForEach-Object {
		$workstte = $_.Name
         if($workstte -eq $workstatetobeapplied)
         {
        $selectedworkflowstate = $_.ID
          }
         }
    }
    
}
Write-Host "Selected workflowstate :" $selectedworkflowstate
$targetItem.Editing.BeginEdit()


$translations | ForEach-Object {

    Write-Host "Source:" $_.Untranslated
    Write-Host "Dest:" $_.Translated
    
    #we need to fix some encoding shenanigans
    $bytes = [System.Text.Encoding]::GetEncoding(1252).GetBytes($_.Translated);
    
    $fixed = [System.Text.Encoding]::UTF8.GetString($bytes).Trim();
    
    #Removing unwanted quotes if any present
     if($fixed[0] -eq "`"" -and $fixed[($fixed.Length-1)] -eq "`"")
    {
      $fixed = $fixed.substring(1, ($fixed.Length -2)).Trim()
    }
    
    Write-Host "Fixed:" $fixed
    
    $targetItem[$_.FieldID] = $fixed
    $targetItem.Fields["__workflow"].value=$selectedworkflow
    $targetItem.Fields["__Workflow state"].Value =$selectedworkflowstate
	
	
}

$targetItem.Editing.EndEdit()

5) Right click on an item – choose the PowerShell script created, choose the fields to be translated, choose the target language, choose the workflow to be applied and in next window choose the work state.

We can customize the code above to add more cool features.

Cheers!!! #LetsMakeSitecoreSimple #ChatGPT #PowerShell

Thanks to Rob Ahnemann for giving the kickstart


Leave a comment

Design a site like this with WordPress.com
Get started