PowerShell: Aus NAV-Translationsdatei eine XLIFF erzeugen

16. April 2015 16:08

Mit dieser Funktion kann auf direktem Wege aus einer NAV-Translationsdatei, wie vorhanden mehrsprachig in Kodierung OEM 850 eine XLIFF-Datei (*.xlf, Version 1.2) in Unicode UTF-8 erzeugt werden. Die Sprachdatei aus NAV wird im ersten Schritt in eine Zwischendatei in Unicode UTF-8 konvertiert, die dabei ebenfalls im Arbeitsverzeichnis mit Suffix _UTF8 abgelegt wird.
Die Quell- und Zielsprache (Source- und Target Language) können dabei jeweils vorher angeben werden. In der Translationsdatei werden die daraus resultierenden Suchmuster (Codestring bis zum Doppelpunkt) verwendet, um die Übersetzung zu finden und in der XLIFF unter der ID des Codestrings einzutragen. Nachtrag: Leerzeichen im Dateipfad sind nicht zulässig, wer die braucht, muss das Skript anpassen :wink: .

Ausgangsdatei, über Extras>Translate aus NAV exportiert:
NAVlangtxt.png

Beispiel 1: Bei Eingabe Quelle: A1031 (de) Ziel: A1033 (en)
XLFkonvEingabeDE_EN.png

entsteht diese XLIFF:
XLFde_enCOLOR.png


Beispiel 2: Bei Eingabe Quelle: A1033 (en) Ziel: A1031 (de)
XLFkonvEingabeEN_DE.png

entsteht aus der gleichen Ausgangsdatei diese XLIFF:
XLFen_deCOLOR.png


Weitere Sprachen als im Switchbefehl bereits vorhanden können natürlich jederzeit ergänzt werden.
XLFswitch.png

Für Polnisch als Zielsprache müsste z.B. diese Zeile hinzukommen:
Code:
"A1045" {$ISOTargetCode = 'pl'}

Außerdem wäre hier die Codepage der Quelldatei nicht 850 (Western Europe), sondern 852 (Central Europe), das muss im Skript ggf. angepasst werden, dann also:
Code:
$sourceEncoding = [System.Text.Encoding]::GetEncoding(852)
oder das SourceEncoding als weiteren Eingabeparameter hinzunehmen. Ob die Konvertierung der Sonderzeichen funktioniert hat, kann man sofort an der UTF-8-Zwischendatei kontrollieren, aus der das Skript dann im weiteren Verlauf die XLIFF erstellt.

Je nach Zielsystem muss man aber prüfen, ob die ISO 639-Codes dort bekannt sind.
Die Umsetzung von DES -> A2055 -> gsw (Swiss German) ist zwar korrekt, gsw ist aber im Translator Hub derzeit unbekannt, dort muss also A2055 als 'de' umgesetzt werden.

Außer im Translator Hub kann die XLIFF in Tools wie Virtaal,Transolution usw. genutzt werden.
XLFvirtaal.png


[27.04.22]Neue Version v2 (schnell, mit Hashtables statt langsamen Filterungen in der Quelldatei)
Hashtable-Variante mit optional leeren Targetcaptions hier.
Code:
function NAVTransToXLF_v2
 {
   
   #Declare ordered hashtables
   $NAVUTF8sourcehash = [ordered]@{}
   $NAVUTF8targethash = [ordered]@{}   
   
    function WriteToFile
     {
      out-file $XLFoutfile -inputobject $args -force -append -Width 500 -Encoding utf8
     }

 
   function WriteXLFHeader
     {
      $CurrLine = "<xliff version='1.2' xmlns='urn:oasis:names:tc:xliff:document:1.2'>"
      # out-file C:\Temp\Translations.xlf -inputobject $Currline -force -append -Width 500 -Encoding utf8
      writetofile $CurrLine
      $OrigFileName = [IO.Path]::GetFileName($NAVtransfile)
     
      $CurrLine = "    <file original='$OrigFileName' source-language='$ISOsourceCode' target-language='$ISOTargetCode' datatype='plaintext'>"
      writetofile $CurrLine
      $CurrLine = "        <body>"
      writetofile $CurrLine
    }
   function WriteBodyLines
     {
      $SourceCaption = $SourceCaption -replace '&','&amp;'
      $TargetCaption = $TargetCaption -replace '&','&amp;'
      $SourceCaption = $SourceCaption -replace '<','&lt;'
      $TargetCaption = $TargetCaption -replace '<','&lt;'
      $SourceCaption = $SourceCaption -replace '>','&gt;'
      $TargetCaption = $TargetCaption -replace '>','&gt;'
      $SourceCaption = $SourceCaption -replace '"','&quot;'
      $TargetCaption = $TargetCaption -replace '"','&quot;'
      $SourceCaption = $SourceCaption -replace $([char]39),'&apos;'
      $TargetCaption = $TargetCaption -replace $([char]39),'&apos;'
      $CurrLine = "            <trans-unit id=$([char]34)$SourceCodestringID$([char]34)>"
      writetofile $CurrLine
      $CurrLine = "                <source xml:lang=$([char]34)$ISOsourceCode$([char]34)>$SourceCaption</source>"
      writetofile $CurrLine
      $CurrLine = "                <target xml:lang=$([char]34)$ISOtargetCode$([char]34)>$TargetCaption</target>"
      writetofile $CurrLine         
      $CurrLine = '            </trans-unit>'
      writetofile $CurrLine
     
     }
   function WriteXLFfooter
     {
        $CurrLine = '        </body>'
        writetofile $CurrLine
        $CurrLine = '    </file>'
        writetofile $CurrLine
        $CurrLine = '</xliff>'
        writetofile $CurrLine
     }
   $NAVtransfile = Read-host "Existing NAV translation file"
   $XLFoutfile = Read-host "Name of new XLF translation file"
     
   if ($NAVtransfile -eq $XLFoutfile)
     {
       Throw "Source and target file are identical. Source: $NAVtransfile Target: $XLFoutfile"
     }
     
   if (Test-Path $XLFoutfile) {Remove-Item $XLFoutfile}
     
   $lines = Get-Content $NAVtransfile | Measure-Object -Line
   $Nooflines = $lines.Lines
   write-host "File has $Nooflines lines"
 
   $sourceEncoding = [Text.Encoding]::GetEncoding(850)
   $targetEncoding = [Text.Encoding]::GetEncoding(65001)
       
   $convertedFileName = [IO.Path]::GetDirectoryName($NAVtransfile) + "\"+ [IO.Path]::GetFileNameWithoutExtension($NAVtransfile) +"_UTF8" + [IO.Path]::GetExtension($NAVtransfile)
   if (Test-Path $convertedFileName) {Remove-Item $convertedFileName}
       
   $convertedfile = New-Item -path $convertedFileName -type file
       
   $textfile = [IO.File]::ReadAllText($NAVtransfile, $sourceencoding)
   [IO.File]::WriteAllText($convertedfile, $textfile, $targetencoding)
   Write-host $NAVtransfile 'converted to' $convertedFileName
     
   
   $SourceLangCode = Read-host "NAV-Code for source language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   $TargetLangCode = Read-host "NAV-Code for target language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   if ($SourceLangCode -eq $TargetLangCode)
     {
       Throw "Source and target language code are identical. Source: $SourceLangCode Target: $TargetLangCode"
     }

   
   Switch ($SourceLangCode)
     {
       "A1031" {$ISOsourceCode = 'de'}
       "A1033" {$ISOsourceCode = 'en'}
       "A1034" {$ISOsourceCode = 'es'}
       "A1036" {$ISOsourceCode = 'fr'}
       "A1040" {$ISOsourceCode = 'it'}
       "A1046" {$ISOsourceCode = 'pt'}       
       "A2055" {$ISOsourceCode = 'gsw'}
       "A2057" {$ISOsourceCode = 'en-gb'}
       "A3079" {$ISOsourceCode = 'de'}
       default {Throw "Please assign an ISO code for $SourceLangCode in the script"}
     }
   Switch ($TargetLangCode)
     {
             "A1030" {$ISOTargetCode = 'dk'}
             "A1031" {$ISOTargetCode = 'de'}
             "A1033" {$ISOTargetCode = 'en'}
             "A1034" {$ISOTargetCode = 'es'}
             "A1035" {$ISOTargetCode = 'fi'}
             "A1036" {$ISOTargetCode = 'fr'}
             "A1040" {$ISOTargetCode = 'it'}
             "A1043" {$ISOTargetCode = 'nl'}
             "A1044" {$ISOTargetCode = 'no'}
             "A1045" {$ISOTargetCode = 'pl'}
             "A1046" {$ISOTargetCode = 'pt'}
             "A1053" {$ISOTargetCode = 'se'}
             "A2055" {$ISOTargetCode = 'gsw'}
             "A2057" {$ISOTargetCode = 'en-gb'}
             "A3079" {$ISOTargetCode = 'de'}
       default {Throw "Please assign an ISO code for $TargetLangCode in the script"}
     }
 
     Write-host "ISO 639 language codes source: $ISOsourceCode, target: $ISOTargetCode"
     $SourceLangCode = "-"+ $SourceLangCode + "-"
     $TargetLangCode = "-"+ $TargetLangCode + "-"
     
     # Write-host "Writing XLF-Header…"
     WriteXLFHeader

   
     Write-host "Building hash, this may take a while…"
     foreach ($line in [IO.File]::ReadLines($convertedFileName))
     {
       $k += 1
       if ($k % 1000 -eq 0) {Write-host "Line $k of $Nooflines"}
       $SourceTextLine = $line.ToString()
       if ($SourceTextLine.contains($SourceLangCode))
       {
         $pos1 = $SourceTextLine.IndexOf(":")     
         $SourceCodestringID = $SourceTextLine.Substring(0,$pos1)
         $SourceCaption = $SourceTextLine.Substring($pos1 + 1)
         $NAVUTF8sourcehash.add($SourceCodestringID,$SourceCaption)
       }   
       if ($SourceTextLine.contains($TargetLangCode))
         {
         $pos1 = $SourceTextLine.IndexOf(":")     
         $TargetCodestringID = $SourceTextLine.Substring(0,$pos1)
         $TargetCaption = $SourceTextLine.Substring($pos1 + 1)
         $NAVUTF8targethash.add($TargetCodestringID,$TargetCaption)
       }           
     }

     foreach ($key in $NAVUTF8sourcehash.keys)
       {
           
           $SourceCodestringID = $key
           $SourceCaption = $NAVUTF8sourcehash[$key]
           $TargetCodestringID = $SourceCodestringID -replace $SourceLangCode,$TargetLangCode
           $TargetCaption = $NAVUTF8targethash[$TargetCodestringID]
         
             IF (![string]::IsNullOrEmpty($TargetCaption))
                {
                  IF ($TargetCaption -eq 'System.Object[]') {$TargetCaption = ''}
                  WriteBodyLines
                  $i += 1
                  if ($i % 10 -eq 0) {Write-Host "Writing line $i"}
                }
         
      }
   
   WriteXLFfooter
 }
NAVTransToXLF_v2


Erste Version (bei großen Dateien (z.B. 50000 Zeilen) sehr langsam, nur noch zu Vergleichszwecken)
Code:
function NAVTransToXLF
 {
   function WriteToFile
     {
      out-file $XLFoutfile -inputobject $args -force -append -Width 500 -Encoding utf8
     }
 
   function WriteXLFHeader
     {
      $CurrLine = "<xliff version='1.2' xmlns='urn:oasis:names:tc:xliff:document:1.2'>"
      # out-file C:\Temp\Translations.xlf -inputobject $Currline -force -append -Width 500 -Encoding utf8
      writetoFile $CurrLine
      $OrigFileName = [System.IO.Path]::GetFileName($NAVtransfile)
      
      $CurrLine = "    <file original='$OrigFileName' source-language='$ISOsourceCode' target-language='$ISOTargetCode' datatype='plaintext'>"
      writetoFile $CurrLine
      $CurrLine = "        <body>"
      writetoFile $CurrLine
    }
   function WriteBodyLines
     {
      $SourceCaption = $SourceCaption -replace '&','&amp;'
      $TargetCaption = $TargetCaption -replace '&','&amp;'
      $SourceCaption = $SourceCaption -replace '<','&lt;'
      $TargetCaption = $TargetCaption -replace '<','&lt;'
      $SourceCaption = $SourceCaption -replace '>','&gt;'
      $TargetCaption = $TargetCaption -replace '>','&gt;'
      $SourceCaption = $SourceCaption -replace '"','&quot;'
      $TargetCaption = $TargetCaption -replace '"','&quot;'
      $SourceCaption = $SourceCaption -replace $([char]39),'&apos;'
      $TargetCaption = $TargetCaption -replace $([char]39),'&apos;'
      $CurrLine = "            <trans-unit id=$([char]34)$SourceCodestringID$([char]34)>"
      writetoFile $CurrLine
      $CurrLine = "                <source xml:lang=$([char]34)$ISOsourceCode$([char]34)>$SourceCaption</source>"
      writetoFile $CurrLine
      $CurrLine = "                <target xml:lang=$([char]34)$ISOtargetCode$([char]34)>$TargetCaption</target>"
      writetoFile $CurrLine         
      $CurrLine = '            </trans-unit>'
      writetoFile $CurrLine
     
     }
   function WriteXLFfooter
     {
        $CurrLine = '        </body>'
        writetoFile $CurrLine
        $CurrLine = '    </file>'
        writetoFile $CurrLine
        $CurrLine = '</xliff>'
        writetoFile $CurrLine
     }
   $NAVtransfile = Read-host "Existing NAV translation file"
   $XLFoutfile = Read-host "Name of new XLF translation file"
     
   if ($NAVtransfile -eq $XLFoutfile)
     {
       Throw "Source and target file are identical. Source: $NAVtransfile Target: $XLFoutfile"
     }
     
   if (Test-Path $XLFoutfile) {Remove-Item $XLFoutfile}
     
   $lines = Get-Content $NAVtransfile | Measure-Object –Line
   $Nooflines = $lines.Lines
   write-host "File has $Nooflines lines"
 
   $sourceEncoding = [System.Text.Encoding]::GetEncoding(850)
   $targetEncoding = [System.Text.Encoding]::GetEncoding(65001)
       
   $convertedFileName = [System.IO.Path]::GetDirectoryName($NAVtransfile) + "\"+ [System.IO.Path]::GetFileNameWithoutExtension($NAVtransfile) +"_UTF8" + [System.IO.Path]::GetExtension($NAVtransfile)
   if (Test-Path $convertedFileName) {Remove-Item $convertedFileName}
       
   $convertedfile = New-Item -path $convertedFileName -type file
       
   $textfile = [System.IO.File]::ReadAllText($NAVtransfile, $sourceencoding)
   [System.IO.File]::WriteAllText($convertedfile, $textfile, $targetencoding)
   Write-host $NAVtransfile 'converted to' $convertedFileName
     
   $SourceLangCode = Read-host "NAV-Code for source language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   $TargetLangCode = Read-host "NAV-Code for target language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   if ($SourceLangCode -eq $TargetLangCode)
     {
       Throw "Source and target language code are identical. Source: $SourceLangCode Target: $TargetLangCode"
     }

   
   Switch ($SourceLangCode)
     {
       "A1031" {$ISOsourceCode = 'de'}
       "A1033" {$ISOsourceCode = 'en'}
       "A1034" {$ISOsourceCode = 'es'}
       "A1036" {$ISOsourceCode = 'fr'}
       "A1040" {$ISOsourceCode = 'it'}
       "A1046" {$ISOsourceCode = 'pt'}       
       "A2055" {$ISOsourceCode = 'gsw'}
       "A2057" {$ISOsourceCode = 'en-gb'}
       "A3079" {$ISOsourceCode = 'de'}
       default {Throw "Please assign an ISO code for $SourceLangCode in the script"}
     }
   Switch ($TargetLangCode)
     {
             "A1030" {$ISOTargetCode = 'dk'}
             "A1031" {$ISOTargetCode = 'de'}
             "A1033" {$ISOTargetCode = 'en'}
             "A1034" {$ISOTargetCode = 'es'}
             "A1035" {$ISOTargetCode = 'fi'}
             "A1036" {$ISOTargetCode = 'fr'}
             "A1040" {$ISOTargetCode = 'it'}
             "A1043" {$ISOTargetCode = 'nl'}
             "A1044" {$ISOTargetCode = 'no'}
             "A1045" {$ISOTargetCode = 'pl'}
             "A1046" {$ISOTargetCode = 'pt'}
             "A1053" {$ISOTargetCode = 'se'}
             "A2055" {$ISOTargetCode = 'gsw'}
             "A2057" {$ISOTargetCode = 'en-gb'}
             "A3079" {$ISOTargetCode = 'de'}
       default {Throw "Please assign an ISO code for $TargetLangCode in the script"}
     }
 
     Write-host "ISO 639 language codes source: $ISOsourceCode, target: $ISOTargetCode"
     $SourceLangCode = "-"+ $SourceLangCode + "-"
     $TargetLangCode = "-"+ $TargetLangCode + "-"
     
     # Write-host "Writing XLF-Header…"
     WriteXLFHeader
     # Write-host "UTF8 file: $convertedFileName"
   
     foreach ($line in [System.IO.File]::ReadLines($convertedFileName))
       {
       $SourceTextLine = $line.ToString()
         if ($SourceTextLine.contains($SourceLangCode))
       {
         $TargetLine = ''
       # Write-host "Source line $SourceTextLine"
 
       $pos1 = $SourceTextLine.IndexOf(":")
     
       $SourceCodestringID = $SourceTextLine.Substring(0,$pos1)
     
       
        $SourceCaption = $SourceTextLine.Substring($pos1 + 1)
        # Write-host "Source Caption $SourceCaption"
        $TargetCodestringID = $SourceCodestringID -replace $SourceLangCode,$TargetLangCode
        # Write-host "Token Target $TargetCodestringID"
        $TargetTextLine = ''
        $TargetLine = select-string -path $convertedFileName -pattern $TargetCodestringID -SimpleMatch
     
     
        IF (![string]::IsNullOrEmpty($TargetLine))
           {
             $TargetTextLine = $TargetLine.ToString()
             $posFileNameEnd = $TargetTextLine.IndexOf(":")
             $TargetTextLine = $TargetTextLine.Substring($posFileNameEnd + 1)
             $poslineno = $TargetTextLine.IndexOf(":")
             $TargetTextLine = $TargetTextLine.Substring($poslineno + 1)
             $posNAVcodeEnd = $TargetTextLine.IndexOf(":")
             $TargetTextLine = $TargetTextLine.Substring($posNAVcodeEnd + 1)
             # Write-host "Target line $TargetTextLine"
     
             IF (![string]::IsNullOrEmpty($TargetTextLine))
                {
                  $pos2 = $TargetTextLine.IndexOf(":")
                  $TargetCaption = $TargetTextLine.Substring($pos2 + 1)
                  IF ($TargetCaption -eq 'System.Object[]') {$TargetCaption = ''}
                  WriteBodyLines
                  $i = $i + 1
                  if ($i%10 -eq 0) {Write-Host "Writing line $i"}
                }
            }
        }
      }
   WriteXLFfooter
}



Edit 28.08.15:

Mein Skript zur Rückumwandlung nach erfolgter Bearbeitung liegt hier :greenarrow: Aus XLIFF eine NAV-Translationsdatei erzeugen
Tags: Sprachdatei, translations file
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Variante: XLIFF eingrenzen auf Add-on-Captions

16. April 2015 17:37

In dieser Variante ist am Anfang eine Zusatzfunktion IsAddonCaption, die anhand der im Add-on vorkommenden Teilen von IDs innerhalb des ID-Codestrings prüft (die müssen natürlich jeweils an das eigene Add-on angepasst werden), ob es sich um eine Add-on-Caption handelt. Nur diese werden dann in die XLIFF übernommen.

XLF_OPPcaptions.png


Code:
function NAVTransOPPToXLF
 {
   function IsAddonCaption($Codestring)
     {
      return($Codestring.contains('51578') -or $Codestring.contains('51579') -or $Codestring.contains('51580') -or $Codestring.StartsWith('M1055') -or $Codestring.StartsWith('M55'))
     }
 
   function WriteToFile
     {
      out-file $XLFoutfile -inputobject $args -force -append -Width 500 -Encoding utf8
     }
 
   function WriteXLFHeader
     {
      $CurrLine = "<xliff version='1.2' xmlns='urn:oasis:names:tc:xliff:document:1.2'>"
      # out-file C:\Temp\Translations.xlf -inputobject $Currline -force -append -Width 500 -Encoding utf8
      writetoFile $CurrLine
      $OrigFileName = [System.IO.Path]::GetFileName($NAVtransfile)
      
      $CurrLine = "    <file original='$OrigFileName' source-language='$ISOsourceCode' target-language='$ISOTargetCode' datatype='plaintext'>"
      writetoFile $CurrLine
      $CurrLine = "        <body>"
      writetoFile $CurrLine
    }
   function WriteBodyLines
     {
      $SourceCaption = $SourceCaption -replace '&','&amp;'
      $TargetCaption = $TargetCaption -replace '&','&amp;'
      $SourceCaption = $SourceCaption -replace '<','&lt;'
      $TargetCaption = $TargetCaption -replace '<','&lt;'
      $SourceCaption = $SourceCaption -replace '>','&gt;'
      $TargetCaption = $TargetCaption -replace '>','&gt;'
      $SourceCaption = $SourceCaption -replace '"','&quot;'
      $TargetCaption = $TargetCaption -replace '"','&quot;'
      $SourceCaption = $SourceCaption -replace $([char]39),'&apos;'
      $TargetCaption = $TargetCaption -replace $([char]39),'&apos;'
      $CurrLine = "            <trans-unit id=$([char]34)$SourceCodestringID$([char]34)>"
      writetoFile $CurrLine
      $CurrLine = "                <source xml:lang=$([char]34)$ISOsourceCode$([char]34)>$SourceCaption</source>"
      writetoFile $CurrLine
      $CurrLine = "                <target xml:lang=$([char]34)$ISOtargetCode$([char]34)>$TargetCaption</target>"
      writetoFile $CurrLine         
      $CurrLine = '            </trans-unit>'
      writetoFile $CurrLine
     
     }
   function WriteXLFfooter
     {
        $CurrLine = '        </body>'
        writetoFile $CurrLine
        $CurrLine = '    </file>'
        writetoFile $CurrLine
        $CurrLine = '</xliff>'
        writetoFile $CurrLine
     }
   $NAVtransfile = Read-host "Existing NAV translation file"
   $XLFoutfile = Read-host "Name of new XLF translation file"
     
   if ($NAVtransfile -eq $XLFoutfile)
     {
       Throw "Source and target file are identical. Source: $NAVtransfile Target: $XLFoutfile"
     }
     
   if (Test-Path $XLFoutfile) {Remove-Item $XLFoutfile}
     
   $lines = Get-Content $NAVtransfile | Measure-Object –Line
   $Nooflines = $lines.Lines
   write-host "File has $Nooflines lines"
 
   $sourceEncoding = [System.Text.Encoding]::GetEncoding(850)
   $targetEncoding = [System.Text.Encoding]::GetEncoding(65001)
       
   $convertedFileName = [System.IO.Path]::GetDirectoryName($NAVtransfile) + "\"+ [System.IO.Path]::GetFileNameWithoutExtension($NAVtransfile) +"_UTF8" + [System.IO.Path]::GetExtension($NAVtransfile)
   if (Test-Path $convertedFileName) {Remove-Item $convertedFileName}
       
   $convertedfile = New-Item -path $convertedFileName -type file
       
   $textfile = [System.IO.File]::ReadAllText($NAVtransfile, $sourceencoding)
   [System.IO.File]::WriteAllText($convertedfile, $textfile, $targetencoding)
   Write-host $NAVtransfile 'converted to' $convertedFileName
     
   $SourceLangCode = Read-host "NAV-Code for source language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   $TargetLangCode = Read-host "NAV-Code for target language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   if ($SourceLangCode -eq $TargetLangCode)
     {
       Throw "Source and target language code are identical. Source: $SourceLangCode Target: $TargetLangCode"
     }

   
   Switch ($SourceLangCode)
     {
       "A1031" {$ISOsourceCode = 'de'}
       "A1033" {$ISOsourceCode = 'en'}
       "A1034" {$ISOsourceCode = 'es'}
       "A1036" {$ISOsourceCode = 'fr'}
       "A2055" {$ISOsourceCode = 'gsw'}
       "A2057" {$ISOsourceCode = 'en-gb'}
       "A3079" {$ISOsourceCode = 'de'}
       default {Throw "Please assign an ISO code for $SourceLangCode in the script"}
     }
   Switch ($TargetLangCode)
     {
       "A1031" {$ISOTargetCode = 'de'}
       "A1033" {$ISOTargetCode = 'en'}
       "A1034" {$ISOTargetCode = 'es'}
       "A1036" {$ISOTargetCode = 'fr'}
       "A2055" {$ISOTargetCode = 'gsw'}
       "A2057" {$ISOTargetCode = 'en-gb'}
       "A3079" {$ISOTargetCode = 'de'}
       default {Throw "Please assign an ISO code for $TargetLangCode in the script"}
     }
 
     Write-host "ISO 639 language codes source: $ISOsourceCode, target: $ISOTargetCode"
     $SourceLangCode = "-"+ $SourceLangCode + "-"
     $TargetLangCode = "-"+ $TargetLangCode + "-"
     
     # Write-host "Writing XLF-Header…"
     WriteXLFHeader
     # Write-host "UTF8 file: $convertedFileName"
   
     foreach ($line in [System.IO.File]::ReadLines($convertedFileName))
       {
       $SourceTextLine = $line.ToString()
         if ($SourceTextLine.contains($SourceLangCode))
       {
       $TargetLine = ''
       # Write-host "Source line $SourceTextLine"
 
       $pos1 = $SourceTextLine.IndexOf(":")
     
     $SourceCodestringID = $SourceTextLine.Substring(0,$pos1)
     IF (IsAddonCaption($SourceCodestringID))
        {
        $SourceCaption = $SourceTextLine.Substring($pos1 + 1)
        # Write-host "Source Caption $SourceCaption"
        $TargetCodestringID = $SourceCodestringID -replace $SourceLangCode,$TargetLangCode
        # Write-host "Token Target $TargetCodestringID"
        $TargetTextLine = ''
        $TargetLine = select-string -path $convertedFileName -pattern $TargetCodestringID -SimpleMatch
     
     
        IF (![string]::IsNullOrEmpty($TargetLine))
           {
             $TargetTextLine = $TargetLine.ToString()
             $posFileNameEnd = $TargetTextLine.IndexOf(":")
             $TargetTextLine = $TargetTextLine.Substring($posFileNameEnd + 1)
             $poslineno = $TargetTextLine.IndexOf(":")
             $TargetTextLine = $TargetTextLine.Substring($poslineno + 1)
             $posNAVcodeEnd = $TargetTextLine.IndexOf(":")
             $TargetTextLine = $TargetTextLine.Substring($posNAVcodeEnd + 1)
             # Write-host "Target line $TargetTextLine"
     
             IF (![string]::IsNullOrEmpty($TargetTextLine))
                {
                  $pos2 = $TargetTextLine.IndexOf(":")
                  $TargetCaption = $TargetTextLine.Substring($pos2 + 1)
                  IF ($TargetCaption -eq 'System.Object[]') {$TargetCaption = ''}
                  WriteBodyLines
                  $i = $i + 1
                  if ($i%10 -eq 0) {Write-Host "Writing line $i"}
                }
            }
        }
      }
    }
   WriteXLFfooter
}
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Leere Targetcaptions optional zulassen

19. Mai 2015 17:24

Mit diesen erweiterten Funktionen ist es optional möglich (Zusatzfrage: Allow empty target captions in XLIFF if no caption translation is available (yes,no) ?), bei fehlenden Übersetzungen für der Zielsprache in der NAV-Translationsdatei leere Targetcaptions in der XLIFF zu exportieren (im Bild rot eingekreist).
XLFwithEmptyCaptions2.png

Bei der Ansicht mit Virtaal werden die Lücken dann deutlich dargestellt:
XLFwithEmptyCaptions.png


Neue Version v2, mit Hashtables deutlich schneller.
Code:
function NAVTransToXLF_v2_AllowEmptyTargetCaptions
 {
   
   #Declare ordered hashtables
   $NAVUTF8sourcehash = [ordered]@{}
   $NAVUTF8targethash = [ordered]@{}
     
    function WriteToFile
     {
      out-file $XLFoutfile -inputobject $args -force -append -Width 500 -Encoding utf8
     }

 
   function WriteXLFHeader
     {
      $CurrLine = "<xliff version='1.2' xmlns='urn:oasis:names:tc:xliff:document:1.2'>"
      # out-file C:\Temp\Translations.xlf -inputobject $Currline -force -append -Width 500 -Encoding utf8
      writetofile $CurrLine
      $OrigFileName = [IO.Path]::GetFileName($NAVtransfile)
     
      $CurrLine = "    <file original='$OrigFileName' source-language='$ISOsourceCode' target-language='$ISOTargetCode' datatype='plaintext'>"
      writetofile $CurrLine
      $CurrLine = "        <body>"
      writetofile $CurrLine
    }
   function WriteBodyLines
     {
      $SourceCaption = $SourceCaption -replace '&','&amp;'
      $TargetCaption = $TargetCaption -replace '&','&amp;'
      $SourceCaption = $SourceCaption -replace '<','&lt;'
      $TargetCaption = $TargetCaption -replace '<','&lt;'
      $SourceCaption = $SourceCaption -replace '>','&gt;'
      $TargetCaption = $TargetCaption -replace '>','&gt;'
      $SourceCaption = $SourceCaption -replace '"','&quot;'
      $TargetCaption = $TargetCaption -replace '"','&quot;'
      $SourceCaption = $SourceCaption -replace $([char]39),'&apos;'
      $TargetCaption = $TargetCaption -replace $([char]39),'&apos;'
      $CurrLine = "            <trans-unit id=$([char]34)$SourceCodestringID$([char]34)>"
      writetofile $CurrLine
      $CurrLine = "                <source xml:lang=$([char]34)$ISOsourceCode$([char]34)>$SourceCaption</source>"
      writetofile $CurrLine
      $CurrLine = "                <target xml:lang=$([char]34)$ISOtargetCode$([char]34)>$TargetCaption</target>"
      writetofile $CurrLine         
      $CurrLine = '            </trans-unit>'
      writetofile $CurrLine
     
     }
   function WriteXLFfooter
     {
        $CurrLine = '        </body>'
        writetofile $CurrLine
        $CurrLine = '    </file>'
        writetofile $CurrLine
        $CurrLine = '</xliff>'
        writetofile $CurrLine
     }
   $NAVtransfile = Read-host "Existing NAV translation file"
   $XLFoutfile = Read-host "Name of new XLF translation file"
   
   [ValidateSet('yes','no')]$AllowEmptyTargetCaptions = Read-Host "Allow empty target captions in XLIFF if no caption translation is available (yes,no) ?"
                 
     
   if ($NAVtransfile -eq $XLFoutfile)
     {
       Throw "Source and target file are identical. Source: $NAVtransfile Target: $XLFoutfile"
     }
     
   if (Test-Path $XLFoutfile) {Remove-Item $XLFoutfile}
     
   $lines = Get-Content $NAVtransfile | Measure-Object -Line
   $Nooflines = $lines.Lines
   write-host "File has $Nooflines lines"
 
   $sourceEncoding = [Text.Encoding]::GetEncoding(850)
   $targetEncoding = [Text.Encoding]::GetEncoding(65001)
       
   $convertedFileName = [IO.Path]::GetDirectoryName($NAVtransfile) + "\"+ [IO.Path]::GetFileNameWithoutExtension($NAVtransfile) +"_UTF8" + [IO.Path]::GetExtension($NAVtransfile)
   if (Test-Path $convertedFileName) {Remove-Item $convertedFileName}
       
   $convertedfile = New-Item -path $convertedFileName -type file
       
   $textfile = [IO.File]::ReadAllText($NAVtransfile, $sourceencoding)
   [IO.File]::WriteAllText($convertedfile, $textfile, $targetencoding)
   Write-host $NAVtransfile 'converted to' $convertedFileName
     
   
   $SourceLangCode = Read-host "NAV-Code for source language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   $TargetLangCode = Read-host "NAV-Code for target language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
   if ($SourceLangCode -eq $TargetLangCode)
     {
       Throw "Source and target language code are identical. Source: $SourceLangCode Target: $TargetLangCode"
     }

   
   Switch ($SourceLangCode)
     {
       "A1031" {$ISOsourceCode = 'de'}
       "A1033" {$ISOsourceCode = 'en'}
       "A1034" {$ISOsourceCode = 'es'}
       "A1036" {$ISOsourceCode = 'fr'}
       "A1040" {$ISOsourceCode = 'it'}
       "A1046" {$ISOsourceCode = 'pt'}       
       "A2055" {$ISOsourceCode = 'gsw'}
       "A2057" {$ISOsourceCode = 'en-gb'}
       "A3079" {$ISOsourceCode = 'de'}
       default {Throw "Please assign an ISO code for $SourceLangCode in the script"}
     }
   Switch ($TargetLangCode)
     {
             "A1030" {$ISOTargetCode = 'dk'}
             "A1031" {$ISOTargetCode = 'de'}
             "A1033" {$ISOTargetCode = 'en'}
             "A1034" {$ISOTargetCode = 'es'}
             "A1035" {$ISOTargetCode = 'fi'}
             "A1036" {$ISOTargetCode = 'fr'}
             "A1040" {$ISOTargetCode = 'it'}
             "A1043" {$ISOTargetCode = 'nl'}
             "A1044" {$ISOTargetCode = 'no'}
             "A1045" {$ISOTargetCode = 'pl'}
             "A1046" {$ISOTargetCode = 'pt'}
             "A1053" {$ISOTargetCode = 'se'}
             "A2055" {$ISOTargetCode = 'gsw'}
             "A2057" {$ISOTargetCode = 'en-gb'}
             "A3079" {$ISOTargetCode = 'de'}
       default {Throw "Please assign an ISO code for $TargetLangCode in the script"}
     }
 
     Write-host "ISO 639 language codes source: $ISOsourceCode, target: $ISOTargetCode"
     $SourceLangCode = "-"+ $SourceLangCode + "-"
     $TargetLangCode = "-"+ $TargetLangCode + "-"
     
     # Write-host "Writing XLF-Header…"
     WriteXLFHeader

   
     Write-host "Building hash, this may take a while…"
     foreach ($line in [IO.File]::ReadLines($convertedFileName))
     {
       $k += 1
       if ($k % 1000 -eq 0) {Write-host "Line $k of $Nooflines"}
       $SourceTextLine = $line.ToString()
       if ($SourceTextLine.contains($SourceLangCode))
       {
         $pos1 = $SourceTextLine.IndexOf(":")     
         $SourceCodestringID = $SourceTextLine.Substring(0,$pos1)
         $SourceCaption = $SourceTextLine.Substring($pos1 + 1)
         $NAVUTF8sourcehash.add($SourceCodestringID,$SourceCaption)
       }   
       if ($SourceTextLine.contains($TargetLangCode))
         {
         $pos1 = $SourceTextLine.IndexOf(":")     
         $TargetCodestringID = $SourceTextLine.Substring(0,$pos1)
         $TargetCaption = $SourceTextLine.Substring($pos1 + 1)
         $NAVUTF8targethash.add($TargetCodestringID,$TargetCaption)
       }           
     }

     foreach ($key in $NAVUTF8sourcehash.keys)
       {
           
           $SourceCodestringID = $key
           $SourceCaption = $NAVUTF8sourcehash[$key]
           $TargetCodestringID = $SourceCodestringID -replace $SourceLangCode,$TargetLangCode
           $TargetCaption = $NAVUTF8targethash[$TargetCodestringID]
           
         
             IF (![string]::IsNullOrEmpty($TargetCaption) -or ($AllowEmptyTargetCaptions -eq 'yes'))
                {
                  IF ($TargetCaption -eq 'System.Object[]') {$TargetCaption = ''}
                  WriteBodyLines
                  $i += 1
                  if ($i % 100 -eq 0) {Write-Host "Writing line $i"}
                }
         
      }
   
   WriteXLFfooter
   Write-host $NAVtransfile 'processed to' $XLFoutfile
 }
NAVTransToXLF_v2_AllowEmptyTargetCaptions


Die alte Beispielfunktion ohne Hashtables ist inklusive der AddOn-Erweiterung. Nur noch zu Vergleichszwecken verwenden.
Code:
       
function NAVTransOPPToXLF_OptionalEmptyTargetCaptions
         {

         function IsAddonCaption($Codestring)
         {
         return($Codestring.contains('51578') -or $Codestring.contains('51579') -or $Codestring.contains('51580') -or $Codestring.StartsWith('M1055') -or $Codestring.StartsWith('M55'))
         }
         
         function WriteToFile
         {
         out-file $XLFoutfile -inputobject $args -force -append -Width 500 -Encoding utf8
         }
         
         function WriteXLFHeader
             {

             $CurrLine = "<xliff version='1.2' xmlns='urn:oasis:names:tc:xliff:document:1.2'>"

             # out-file C:\Temp\Translations.xlf -inputobject $Currline -force -append -Width 500 -Encoding utf8

             writetoFile $CurrLine
             $OrigFileName = [System.IO.Path]::GetFileName($NAVtransfile)
             
             $CurrLine = "    <file original='$OrigFileName' source-language='$ISOsourceCode' target-language='$ISOTargetCode' datatype='plaintext'>"

             writetoFile $CurrLine

             $CurrLine = "        <body>"

             writetoFile $CurrLine
             }

          function WriteBodyLines
             {

             
              $SourceCaption = $SourceCaption -replace '&','&amp;'
              $TargetCaption = $TargetCaption -replace '&','&amp;'
              $SourceCaption = $SourceCaption -replace '<','&lt;'
              $TargetCaption = $TargetCaption -replace '<','&lt;'
              $SourceCaption = $SourceCaption -replace '>','&gt;'
              $TargetCaption = $TargetCaption -replace '>','&gt;'
              $SourceCaption = $SourceCaption -replace '"','&quot;'
              $TargetCaption = $TargetCaption -replace '"','&quot;'
              $SourceCaption = $SourceCaption -replace $([char]39),'&apos;'
              $TargetCaption = $TargetCaption -replace $([char]39),'&apos;'

              $CurrLine = "            <trans-unit id=$([char]34)$SourceCodestringID$([char]34)>"
              writetoFile $CurrLine
              $CurrLine = "                <source xml:lang=$([char]34)$ISOsourceCode$([char]34)>$SourceCaption</source>"
              writetoFile $CurrLine
              $CurrLine = "                <target xml:lang=$([char]34)$ISOtargetCode$([char]34)>$TargetCaption</target>"
              writetoFile $CurrLine         
              $CurrLine = '            </trans-unit>'
              writetoFile $CurrLine
             
              }

              Function WriteXLFfooter
                {
                $CurrLine = '        </body>'
                writetoFile $CurrLine
                $CurrLine = '    </file>'
                writetoFile $CurrLine
                $CurrLine = '</xliff>'
                writetoFile $CurrLine
                }

             $NAVtransfile = Read-host "Existing NAV translation file"
             $XLFoutfile = Read-host "Name of new XLF translation file"
             
             [ValidateSet('yes','no')]$AllowEmptyTargetCaptions = Read-Host "Allow empty target captions in XLIFF if no caption translation is available (yes,no) ?"
             
             if ($NAVtransfile -eq $XLFoutfile)
               {
                 Throw "Source and target file are identical. Source: $NAVtransfile Target: $XLFoutfile"
               }
             
             if (Test-Path $XLFoutfile) {Remove-Item $XLFoutfile}
             
             $lines = Get-Content $NAVtransfile | Measure-Object –Line
             $Nooflines = $lines.Lines
             write-host "File has $Nooflines lines"
         
            $sourceEncoding = [System.Text.Encoding]::GetEncoding(850)
            $targetEncoding = [System.Text.Encoding]::GetEncoding(65001)
               
            $convertedFileName = [System.IO.Path]::GetDirectoryName($NAVtransfile) + "\"+ [System.IO.Path]::GetFileNameWithoutExtension($NAVtransfile) +"_UTF8" + [System.IO.Path]::GetExtension($NAVtransfile)
            if (Test-Path $convertedFileName) {Remove-Item $convertedFileName}
               
            $convertedfile = New-Item -path $convertedFileName -type file
               
            $textfile = [System.IO.File]::ReadAllText($NAVtransfile, $sourceencoding)
            [System.IO.File]::WriteAllText($convertedfile, $textfile, $targetencoding)
            Write-host $NAVtransfile 'converted to' $convertedFileName
             
             $SourceLangCode = Read-host "NAV-Code for source language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"
             $TargetLangCode = Read-host "NAV-Code for target language (e.g. A1031 for DEU, A1033 for ENU, A1036 for FRA)"

             if ($SourceLangCode -eq $TargetLangCode)
              {
              Throw "Source and target language code are identical. Source: $SourceLangCode Target: $TargetLangCode"
              }
       
           
            Switch ($SourceLangCode)
             {
             "A1031" {$ISOsourceCode = 'de'}
             "A1033" {$ISOsourceCode = 'en'}
             "A1034" {$ISOsourceCode = 'es'}
             "A1036" {$ISOsourceCode = 'fr'}
             "A1040" {$ISOsourceCode = 'it'}
             "A1046" {$ISOsourceCode = 'pt'}
             "A2055" {$ISOsourceCode = 'gsw'}
             "A2057" {$ISOsourceCode = 'en-gb'}
             "A3079" {$ISOsourceCode = 'de'}

             default {Throw "Please assign an ISO code for $SourceLangCode in the script"}
             }

            Switch ($TargetLangCode)
             {
             "A1030" {$ISOTargetCode = 'dk'}
             "A1031" {$ISOTargetCode = 'de'}
             "A1033" {$ISOTargetCode = 'en'}
             "A1034" {$ISOTargetCode = 'es'}
             "A1035" {$ISOTargetCode = 'fi'}
             "A1036" {$ISOTargetCode = 'fr'}
             "A1040" {$ISOTargetCode = 'it'}
             "A1043" {$ISOTargetCode = 'nl'}
             "A1044" {$ISOTargetCode = 'no'}
             "A1045" {$ISOTargetCode = 'pl'}
             "A1046" {$ISOTargetCode = 'pt'}
             "A1053" {$ISOTargetCode = 'se'}
             "A2055" {$ISOTargetCode = 'gsw'}
             "A2057" {$ISOTargetCode = 'en-gb'}
             "A3079" {$ISOTargetCode = 'de'}
             default {Throw "Please assign an ISO code for $TargetLangCode in the script"}
             }
         
             Write-host "ISO 639 language codes source: $ISOsourceCode, target: $ISOTargetCode"
             $SourceLangCode = "-"+ $SourceLangCode + "-"
             $TargetLangCode = "-"+ $TargetLangCode + "-"
             
             # Write-host "Writing XLF-Header…"
             WriteXLFHeader
             # Write-host "UTF8 file: $convertedFileName"
           
             foreach ($line in [System.IO.File]::ReadLines($convertedFileName))
             {
             $SourceTextLine = $line.ToString()
             if ($SourceTextLine.contains($SourceLangCode))
             {
               $TargetLine = ''
               # Write-host "Source line $SourceTextLine"
         
             
              $pos1 = $SourceTextLine.IndexOf(":")

             
              $SourceCodestringID = $SourceTextLine.Substring(0,$pos1)

              IF (IsAddonCaption($SourceCodestringID))
              {
                $SourceCaption = $SourceTextLine.Substring($pos1 + 1)
                # Write-host "Source Caption $SourceCaption"
                $TargetCodestringID = $SourceCodestringID -replace $SourceLangCode,$TargetLangCode
                # Write-host "Token Target $TargetCodestringID"
                $TargetTextLine = ''
                $TargetLine = select-string -path $convertedFileName -pattern $TargetCodestringID -SimpleMatch
             
             if (([string]::IsNullOrEmpty($TargetLine)) -and ($AllowEmptyTargetCaptions -eq 'yes'))
              {
               $TargetLine = '::::'
              }

               
               if (![string]::IsNullOrEmpty($TargetLine))
               {
                $TargetTextLine = $TargetLine.ToString()
                $posFileNameEnd = $TargetTextLine.IndexOf(":")
                $TargetTextLine = $TargetTextLine.Substring($posFileNameEnd + 1)
                $poslineno = $TargetTextLine.IndexOf(":")
                $TargetTextLine = $TargetTextLine.Substring($poslineno + 1)
                $posNAVcodeEnd = $TargetTextLine.IndexOf(":")
                $TargetTextLine = $TargetTextLine.Substring($posNAVcodeEnd + 1)
                # Write-host "Target line $TargetTextLine"
             
                if (![string]::IsNullOrEmpty($TargetTextLine))
                {
                $pos2 = $TargetTextLine.IndexOf(":")
               
               
                $TargetCaption = $TargetTextLine.Substring($pos2 + 1)
                If ($TargetCaption -eq 'System.Object[]') {$TargetCaption = ''}
               
                WriteBodyLines
                $i = $i + 1
                if ($i%10 -eq 0) {Write-Host "Writing line $i"}
                }
               }
              }
             }
           }
          WriteXLFfooter
        }
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.

Re: PowerShell: Aus NAV-Translationsdatei eine XLIFF erzeuge

27. Januar 2021 22:09

Der Dynamics Translation Service (DTS) kann (wie bisher schon der ältere stillgelegte Translator Hub) mit XLIFFs ggf. mittels Translation Memory Files vorab trainiert und für genauere Übersetzungen definierter Begriffe und Phrasen genutzt werden.

Re: PowerShell: Aus NAV-Translationsdatei eine XLIFF erzeuge

27. April 2023 14:38

Im Startbeitrag gibt es jetzt eine neue Version des Skripts, die geordnete Hashtables verwendet, damit die bislang notwendigen langsamen Filterungen auf der Quelldatei umgeht, und somit erheblich schneller die XLIFF erzeugt. Selbst große Dateien werden damit in ein paar Sekunden abgearbeitet (Test mit 51598 Zeilen in einer Datei mit Captions für ENU,DEU und FRA dauerte 12,5 sec, mit der alten Version 34 Minuten :!: ).
Nachtrag 28.04.23: Die Variante mit optional leeren Targetcaptions ist jetzt auch als Hashtable-Version hier vorhanden.