Translation/Translate-XlfFile.ps1
function Translate-App { Param( [Parameter(Mandatory=$false)] [string]$TranslationSource, [Parameter(Mandatory=$false)] [string]$SourceDir = (Get-Location) ) $EnvJson = ConvertFrom-Json (Get-Content (Join-Path $SourceDir 'environment.json') -Raw) if ($TranslationSource -eq '' -or $null -eq $TranslationSource) { $TranslationSource = Join-Path $SourceDir $EnvJson.translationSource } if (!(Test-Path $TranslationSource)) { throw 'Could not find translation source file.' } Write-Host "Using translation source file $TranslationSource" foreach ($Translation in $EnvJson.translations) { Write-Host ('Translating to {0}-{1}' -f $Translation.language, $Translation.country) Translate-XlfFile -SourcePath $TranslationSource -TargetCountry $Translation.country -TargetLanguage $Translation.language } } function Translate-XlfFile { Param( [Parameter(Mandatory=$true)] [string]$SourcePath, [Parameter(Mandatory=$false)] [string]$OutputPath, [Parameter(Mandatory=$false)] [string]$TargetLanguage, [Parameter(Mandatory=$false)] [string]$TargetCountry ) if ($OutputPath -eq '' -or $null -eq $OutputPath) { $OutputPath = (Join-Path (Split-Path $SourcePath -Parent) ($TargetLanguage.ToLower() + "-" + $TargetCountry.ToUpper())) + ".xlf" } #create xlf file if it doesn't already exist if (!(Test-Path $OutputPath)) { cpi $SourcePath $OutputPath [xml]$OutputXml = Get-Content $OutputPath $TargetLanguageAtt = $OutputXml.CreateAttribute('target-language') $TargetLanguageAtt.Value = '{0}-{1}' -f $TargetLanguage.ToLower(), $TargetCountry.ToUpper() $OutputXml.xliff.file.Attributes.SetNamedItem($TargetLanguageAtt) $OutputXml.Save($OutputPath) } #add any translation units that are present in the source but not in the output Sync-TranslationUnits $SourcePath $OutputPath $StringsToTranslate = Get-StringsToTranslate -SourcePath $OutputPath if ($null -eq $StringsToTranslate) { Write-Host 'Already up to date' } while ($null -ne $StringsToTranslate) { $Strings = @() $StringsToTranslate | ForEach-Object {$Strings += $_.Source} $TranslatedStrings = Translate-Strings -Strings $Strings -TargetLanguage $TargetLanguage Write-TranslatedStrings -OutputPath $OutputPath -StringsToTranslate $StringsToTranslate -TranslatedStrings $TranslatedStrings $StringsToTranslate = Get-StringsToTranslate -SourcePath $OutputPath } } function Sync-TranslationUnits { Param( [Parameter(Mandatory=$true)] $SourcePath, [Parameter(Mandatory=$true)] $OutputPath ) [bool]$SaveFile = $false [xml]$SourceXml = Get-Content $SourcePath [xml]$OutputXml = Get-Content $OutputPath [System.Xml.XmlNamespaceManager]$NSMgr = [System.Xml.XmlNameSpaceManager]::new($OutputXml.NameTable) $NSMgr.AddNamespace('x',$SourceXml.DocumentElement.NamespaceURI) #add missing sources to the output file foreach ($SourceTUnit in $SourceXml.SelectNodes('/x:xliff/x:file/x:body/x:group/x:trans-unit',$NSMgr)) { $OutputTUnit = $OutputXml.SelectSingleNode(("/x:xliff/x:file/x:body/x:group/x:trans-unit[@id='{0}']" -f $SourceTUnit.Attributes.GetNamedItem('id')."#text"),$NSMgr) if ($null -eq $OutputTUnit) { $OutputXml.xliff.file.body.group.AppendChild($OutputXml.ImportNode($SourceTUnit,$true)) $SaveFile = $true } elseif ($OutputTUnit.source.Value -ne $SourceTUnit.source.Value) { $OutputTUnit.source = $SourceTUnit.source $OutputTUnit.RemoveChild($OutputTUnit.SelectSingleNode('./x:target',$NSMgr)) $SaveFile = $true } } #remove orphaned sources from the output foreach ($OutputTUnit in $OutputXml.SelectNodes('/x:xliff/x:file/x:body/x:group/x:trans-unit',$NSMgr)) { $SourceTUnit = $SourceXml.SelectSingleNode(("/x:xliff/x:file/x:body/x:group/x:trans-unit[@id='{0}']" -f $OutputTUnit.Attributes.GetNamedItem('id')."#text"),$NSMgr) if ($null -eq $SourceTUnit) { $OutputXml.xliff.file.body.group.RemoveChild($OutputTUnit) $SaveFile = $true } } if ($SaveFile) { $OutputXml.Save($OutputPath) } } function Get-StringsToTranslate { Param( [Parameter(Mandatory=$true)] [string]$SourcePath, [Parameter(Mandatory=$false)] [int]$Top = 100 ) $StringsToTranslate = @() $ElementNo = 1 [xml]$SourceXml = gc $SourcePath foreach ($TUnit in $SourceXml.xliff.file.body.group.'trans-unit') { if ($null -eq $TUnit.target) { $StringToTranslate = New-Object System.Object $StringToTranslate | Add-Member -MemberType NoteProperty -Name ID -Value $TUnit.id $SourceText = $TUnit.source.InnerText if ($null -eq $SourceText){ $SourceText = $TUnit.source } $StringToTranslate | Add-Member -MemberType NoteProperty -Name Source -Value $SourceText $StringToTranslate | Add-Member -MemberType NoteProperty -Name Target -Value '' $StringsToTranslate += $StringToTranslate $ElementNo++ if ($ElementNo -gt $Top) { break } } } $StringsToTranslate } function Translate-Strings { Param( [Parameter(Mandatory=$true)] [string[]]$Strings, [Parameter(Mandatory=$true)] $TargetLanguage ) #don't send English strings for translation if ($TargetLanguage -eq 'en') { $Translations = $Strings return $Translations } #convert input object into json request $Request = '[' foreach ($String in $Strings) { $String = $String.Replace('\','\\') $String = $String.Replace('"','\"') $Request += '{Text:"' + $String + '"},' } $Request = $Request.Substring(0,$Request.Length - 1) $Request += ']' $Key = Get-TFSConfigKeyValue 'translationkey' $Headers = @{'Ocp-Apim-Subscription-Key'=$Key} $Headers.Add('Content-Type','application/json') $Response = Invoke-WebRequest ('https://api.cognitive.microsofttranslator.com/translate?api-version=3.0&to={0}' -f $TargetLanguage) -Headers $Headers -Method Post -Body $Request $Translations = @() (ConvertFrom-Json $Response.Content).translations | % { $Text = $_.text $Text = $Text.Replace('% 10',' %10') $Text = $Text.Replace('% 1',' %1') $Text = $Text.Replace('% 2',' %2') $Text = $Text.Replace('% 3',' %3') $Text = $Text.Replace('% 4',' %4') $Text = $Text.Replace('% 5',' %5') $Text = $Text.Replace('% 6',' %6') $Text = $Text.Replace('% 7',' %7') $Text = $Text.Replace('% 8',' %8') $Text = $Text.Replace('% 9',' %9') $Translations += $Text } $Translations } function Write-TranslatedStrings { Param( [Parameter(Mandatory=$true)] [string]$OutputPath, [Parameter(Mandatory=$true)] $StringsToTranslate, [Parameter(Mandatory=$true)] [string[]]$TranslatedStrings ) [xml]$OutputXml = Get-Content $OutputPath $ElementNo = 0 foreach ($StringToTranslate in $StringsToTranslate) { $TUnit = $OutputXml.xliff.file.body.group.'trans-unit' | ? ID -eq $StringToTranslate.ID $TargetNode = $OutputXml.CreateElement('target',$OutputXml.DocumentElement.NamespaceURI) $TargetNode.InnerText = $TranslatedStrings.Get($ElementNo) $SourceNode = $TUnit.FirstChild.NextSibling $TUnit.InsertAfter($TargetNode,$SourceNode) $ElementNo++ } $OutputXml.Save($OutputPath) } Export-ModuleMember -Function Translate-XlfFile Export-ModuleMember -Function Translate-App Export-ModuleMember -Function Get-StringsToTranslate Export-ModuleMember -Function Sync-TranslationUnits |