Erstellen Sie automatisch Android- und iOS-Lokalisierungsdateien aus einer Excel-Tabelle

Bild


Hallo, mein Name ist Alexander und ich bin ein Entwickler von Android-Anwendungen. Einmal kam ich zu einem Projekt mit 11 Schnittstellensprachen und mehr als 600 Zeilen. Auf Kundenseite gab es keine Programmierer, daher haben sie das Ganze in einer Excel-Tabelle gespeichert. Wenn sie etwas daran geändert haben, haben sie uns diese Tabelle mit den Worten "Wir haben Zellen mit Änderungen in Gelb hervorgehoben, aktualisieren Android- bzw. iOS-Anwendungen" gesendet. Danach haben zwei Entwickler einige Stunden verloren und Änderungen manuell vorgenommen. Und dann stellte sich heraus, dass jemand irgendwo etwas vergessen, einen Fehler gemacht oder nicht beendet hatte, es gab Diskrepanzen zwischen den Plattformen, der Kunde war nervös, die Entwickler flippten aus. Diese Situation passte nicht zu mir. Ich suchte nach Möglichkeiten, um das Entladen von Zeilen aus Excel zu automatisieren. Das Ergebnis war großartiger VBScript-Code, den wir immer noch gerne verwenden. Jetzt werde ich Ihnen dieses Skript vorstellen. Unter dem Schnitt eine bestimmte Anzahl von Bildern und Skriptcode.


Schauen Sie sich also zuerst die Tabelle selbst an und bewerten Sie das Ausmaß des Problems:


Bild


Da ist sie, Schönheit! Wie wir sehen können, gibt es mehrere Dienstspalten, globale Zeilennamen und deren Übersetzungen. Darüber hinaus werden einige Zeilen nur in Englisch und Deutsch dargestellt, da der Kunde in Version 2.0 der Anwendung beschlossen hat, vorerst nur zwei Sprachen zu belassen und den Rest später hinzuzufügen. Oder vielleicht hat er Mitleid mit dem Geld für Übersetzer. Aber das ist seine Sache, aber wir müssen das berücksichtigen. Das heißt, das Skript sollte leere Zellen überspringen und keine leeren Zeilen für eine solche Sprache erstellen. Außerdem müssen Formatierungszeichen wie "% s" in Zelle F5 berücksichtigt werden. Sie müssen damit arbeiten, denn was Android in iOS kann, sollte durch "% @" ersetzt werden. Ich erzähle Ihnen von den anderen Nuancen auf dem Weg.


Um nicht zu schmachten und die Katze nicht am Schwanz zu ziehen, werde ich jetzt das gesamte Skript veröffentlichen:


VBScript in seiner ganzen Pracht
option explicit ' Start it with: cscript ConvertExcelToTXTandXML.vbs If UCASE(right(wscript.fullname,11)) <> "CSCRIPT.EXE" Then Msgbox "Please enter: cscript ConvertExcelToTXTandXML.vbs <filename>.xlsx" WScript.Quit 255 End If ' The column of the key is 4 Const KeyColumn = 4 ' Names of destination files to create Const outFileiOS="\Localizable.strings" Const outFileiOSLocale="\InfoPlist.strings" Const outFileAndroid="\stringsToFormat.xml" Const NsCameraUsageDescription = "NsCameraUsageDescription" Const NSLocationAlwaysAndWhenInUseUsageDescription = "NSLocationAlwaysAndWhenInUseUsageDescription" Const NSLocationAlwaysUsageDescription = "NSLocationAlwaysUsageDescription" Const NSLocationWhenInUseUsageDescription = "NSLocationWhenInUseUsageDescription" Const NSPhotoLibraryAddUsageDescription = "NSPhotoLibraryAddUsageDescription" Const NSPhotoLibraryUsageDescription = "NSPhotoLibraryUsageDescription" Dim oExcel Dim oTranslations Dim objOutputFileiOS Dim objOutputFileiOSLocale Dim objFSO Dim objFSOandroid Dim objFSOios Dim myArgs Dim myParameter Dim sName Dim CompletePath Dim WorkingDir Dim WorkingDirAndroid Dim WorkingDirIos Dim LanguageColumnIndex Dim UsedRows Dim nCounter Dim xmlDoc Dim objIntro Dim objRoot Dim objHdr Dim objHdrAtt Dim theText Dim AndroidString Dim iOSString ' **************************************** ' MAKE PRETTY XML ' **************************************** Const strOutputFile = "\strings.xml" ' **************************************** Dim objInputFile, objOutputFile, strXML Dim objXML : Set objXML = WScript.CreateObject("Msxml2.DOMDocument") Dim objXSL : Set objXSL = WScript.CreateObject("Msxml2.DOMDocument") ' Create interface to Excel Set oExcel = CreateObject("Excel.application") ' Create the file interface Set objFSO=CreateObject("Scripting.FileSystemObject") ' Get the commandline parameter Set myArgs = WScript.Arguments.Unnamed If myArgs.count > 0 Then If (not objFSO.FileExists(myArgs.item(0))) Then Wscript.Echo "Error: '" & myArgs.item(0) & "' not found" WScript.Quit 255 End If Set myParameter = objFSO.GetFile(myArgs.item(0)) sName = myParameter.Name CompletePath = myParameter.Path WorkingDir = myParameter.Path WorkingDir = Left(WorkingDir, Len(WorkingDir)-Len(sName)) WorkingDirAndroid = "res\" WorkingDirIos = "ios\" If Not objFSO.FolderExists(WorkingDir & WorkingDirAndroid) Then ' Create folder if not exists' objFSO.CreateFolder(WorkingDir & WorkingDirAndroid) End If If Not objFSO.FolderExists(WorkingDir & WorkingDirIos) Then ' Create folder if not exists' objFSO.CreateFolder(WorkingDir & WorkingDirIos) End If Else Wscript.Echo "Error: A filename is needed" WScript.Quit 255 End If ' Source file Set oTranslations = oExcel.Workbooks.Open(CompletePath) ' Get the maximum number of rows in the sheet UsedRows = oTranslations.Sheets(1).UsedRange.Rows.Count ' In this column start the start the languages' LanguageColumnIndex = 6 ' stop the processing when the cell is empty --> end of languages while oTranslations.Sheets(1).Cells(3, LanguageColumnIndex) <> "" WScript.stdout.Write "Create files for: " WScript.stdout.Write oTranslations.Sheets(1).Cells(3, LanguageColumnIndex) WScript.stdout.Write " " objFSOandroid = oTranslations.Sheets(1).Cells(3, LanguageColumnIndex) If objFSOandroid = "values" Then objFSOios = "en" & ".lproj" ElseIf objFSOandroid = "values-ru" Then objFSOios = "ru-RU" & ".lproj" Else objFSOios = Right(objFSOandroid,2) & ".lproj" End If WScript.stdout.Write "; iOs folder: " WScript.stdout.Write objFSOios If Not objFSO.FolderExists(WorkingDir & WorkingDirAndroid & objFSOandroid) Then ' Create folder if not exists' objFSO.CreateFolder(WorkingDir & WorkingDirAndroid & objFSOandroid) End If If Not objFSO.FolderExists(WorkingDir & WorkingDirIos & objFSOios) Then ' Create folder if not exists' objFSO.CreateFolder(WorkingDir & WorkingDirIos & objFSOios) End If ' Create the destination files Set objOutputFileiOS = CreateObject("ADODB.Stream") objOutputFileiOS.CharSet = "utf-8" objOutputFileiOS.Open Set objOutputFileiOSLocale = CreateObject("ADODB.Stream") objOutputFileiOSLocale.CharSet = "utf-8" objOutputFileiOSLocale.Open Set xmlDoc = CreateObject("Msxml2.DOMDocument") ' NOTE: chr(34) is " ' NOTE: vbCrLf is <CR><LF> ' Create the XML header Set objIntro = xmlDoc.createProcessingInstruction("xml","version='1.0' encoding='UTF-8' standalone='yes'") xmlDoc.insertBefore objIntro,xmlDoc.childNodes(0) Set objRoot = xmlDoc.createElement("resources") xmlDoc.appendChild objRoot ' keys start in row 3!!! For nCounter = 3 To UsedRows WScript.stdout.Write "." If oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value <> "" Then ' Write to iOS file If Not oTranslations.Sheets(1).Cells(nCounter, LanguageColumnIndex).Value = "" Then objOutputFileiOS.WriteText chr(34) objOutputFileiOS.WriteText oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value objOutputFileiOS.WriteText chr(34) objOutputFileiOS.WriteText " = " objOutputFileiOS.WriteText chr(34) iOSString = Replace(oTranslations.Sheets(1).Cells(nCounter, LanguageColumnIndex).Value, "%s", "%@") iOSString = Replace(iOSString, "'", "\'") iOSString = Replace(iOSString, chr(34), "\" & chr(34)) objOutputFileiOS.WriteText iOSString objOutputFileiOS.WriteText chr(34) objOutputFileiOS.WriteText ";" & vbCrLf If ( (oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value = NsCameraUsageDescription) _ or (oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value = NSLocationAlwaysAndWhenInUseUsageDescription) _ or (oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value = NSLocationAlwaysUsageDescription) _ or (oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value = NSLocationWhenInUseUsageDescription) _ or (oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value = NSPhotoLibraryAddUsageDescription) _ or (oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value = NSPhotoLibraryUsageDescription) _ ) Then objOutputFileiOSLocale.WriteText chr(34) objOutputFileiOSLocale.WriteText oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value objOutputFileiOSLocale.WriteText chr(34) objOutputFileiOSLocale.WriteText " = " objOutputFileiOSLocale.WriteText chr(34) objOutputFileiOSLocale.WriteText iOSString objOutputFileiOSLocale.WriteText chr(34) objOutputFileiOSLocale.WriteText ";" & vbCrLf End If End If ' Write to Android file Set objHdr = xmlDoc.createElement("string") Set objHdrAtt = xmlDoc.createAttribute("name") objHdrAtt.text = oTranslations.Sheets(1).Cells(nCounter, KeyColumn).Value AndroidString =Replace (oTranslations.Sheets(1).Cells(nCounter, LanguageColumnIndex).Value, "'", "\'") AndroidString =Replace (oTranslations.Sheets(1).Cells(nCounter, LanguageColumnIndex).Value, Chr(10), "\n") If Not AndroidString = "" Then Set theText=xmlDoc.createTextNode(AndroidString) objHdr.setAttributeNode objHdrAtt objHdr.appendChild theText objRoot.appendChild objHdr End If End If Next ' Save the files xmlDoc.Save WorkingDir & WorkingDirAndroid & objFSOandroid & outFileAndroid ' **************************************** ' Put whitespace between tags. (Required for XSL transformation.) ' **************************************** Set objInputFile = objFSO.OpenTextFile(WorkingDir & WorkingDirAndroid & objFSOandroid & outFileAndroid,1,False,-2) Set objOutputFile = objFSO.CreateTextFile(WorkingDir & WorkingDirAndroid & objFSOandroid & strOutputFile,True,False) strXML = objInputFile.ReadAll strXML = Replace(strXML,"><",">" & vbCrLf & "<") objOutputFile.Write strXML objInputFile.Close objFSO.DeleteFile(WorkingDir & WorkingDirAndroid & objFSOandroid & outFileAndroid) objOutputFile.Close ' **************************************** ' Create an XSL stylesheet for transformation. ' **************************************** Dim strStylesheet : strStylesheet = _ "<xsl:stylesheet version=""1.0"" xmlns:xsl=""http://www.w3.org/1999/XSL/Transform"">" & _ "<xsl:output method=""xml"" indent=""yes""/>" & _ "<xsl:template match=""/"">" & _ "<xsl:copy-of select="".""/>" & _ "</xsl:template>" & _ "</xsl:stylesheet>" ' **************************************** ' Transform the XML. ' **************************************** objXSL.loadXML strStylesheet objXML.load WorkingDir & WorkingDirAndroid & objFSOandroid & strOutputFile objXML.transformNode objXSL objXML.save WorkingDir & WorkingDirAndroid & objFSOandroid & strOutputFile ' **************************************** ' End transformation. ' **************************************** objOutputFileiOSLocale.SaveToFile WorkingDir & WorkingDirIos & objFSOios & outFileiOSLocale, 2 objOutputFileiOS.SaveToFile WorkingDir & WorkingDirIos & objFSOios & outFileiOS, 2 LanguageColumnIndex = LanguageColumnIndex + 1 WScript.stdout.Write vbCrLf wend oTranslations.Close oExcel.Quit WScript.Echo "With success done" WScript.Quit(0) 

Jetzt ist die Zeit gekommen, die Nuancen durchzugehen.


Unsere Anwendung erfordert mehrere Benutzerberechtigungen. Unter iOS werden die Zeilen zum Anfordern dieser Berechtigungen nicht wie gewohnt in Localizable.strings, sondern in InfoPlist.strings gespeichert. Daher definieren wir ganz am Anfang unseres Skripts die Namen der Zeilen, die an InfoPlist gesendet werden:


 Const NsCameraUsageDescription = "NsCameraUsageDescription" Const NSLocationAlwaysAndWhenInUseUsageDescription = "NSLocationAlwaysAndWhenInUseUsageDescription" Const NSLocationAlwaysUsageDescription = "NSLocationAlwaysUsageDescription" Const NSLocationWhenInUseUsageDescription = "NSLocationWhenInUseUsageDescription" Const NSPhotoLibraryAddUsageDescription = "NSPhotoLibraryAddUsageDescription" Const NSPhotoLibraryUsageDescription = "NSPhotoLibraryUsageDescription" 

Das nächste bemerkenswerte Fragment sind die Namen der Ordner, in denen alle Dateien gespeichert werden. Unter iOS werden alle Ordner mit einer aus zwei Buchstaben bestehenden Sprachbezeichnung benannt, z. B. "en.lproj", "de.lproj". Alles außer Russisch, hier ist "ru-RU". In der Tabelle selbst sind die Spalten in Android-Notation. Deshalb parsim:


 If objFSOandroid = "values" Then objFSOios = "en" & ".lproj" ElseIf objFSOandroid = "values-ru" Then objFSOios = "ru-RU" & ".lproj" Else objFSOios = Right(objFSOandroid,2) & ".lproj" End If 

Und die letzte Aufgabe, Zeichen zu ersetzen und zu entkommen. Für iOS werden wir, wie gesagt, % s in % @ ändern und Anführungszeichen und Apostrophe umgehen:


 iOSString = Replace(oTranslations.Sheets(1).Cells(nCounter, LanguageColumnIndex).Value, "%s", "%@") iOSString = Replace(iOSString, "'", "\'") iOSString = Replace(iOSString, chr(34), "\" & chr(34)) 

Für Android entkommen wir auch Apostrophen und ersetzen das sogenannte Zeilenvorschubzeichen ( Chr (10) ) durch das übliche neue Zeilenzeichen \ n . Und dafür gibt es einen Grund. In einer der Zellen haben wir einen ziemlich großen Text, der vom Kunden in MS Word zusammengestellt und mit technischer Kopie in die Excel-Zelle eingefügt wurde. Und obwohl wir durch Ausprobieren nicht den richtigen Ersatz gefunden haben, wurde der Text in iOS in den erforderlichen Absätzen angezeigt und in Android zu einem Absatz zusammengeführt.


Fazit


Wie Sie wahrscheinlich bereits vermutet haben, wird das Skript in der Windows-Befehlszeile ausgeführt. Der Einfachheit halber platzieren wir das Skript und die XLSX-Datei in einem Ordner, gehen dort zur Befehlszeile und schreiben den Befehl:


cscript ConvertExcelToTXTandXML.vbs <filename>.xlsx


Drücken Sie anschließend die Eingabetaste und genießen Sie eine schöne Visualisierung des Skripts in Form von Punkten, die im Befehlsfenster für jeden Schritt des Programms angezeigt werden. Das Ergebnis der titanischen Arbeit unseres Skripts sind zwei Ordner, "ios" und "res", deren Inhalt noch in das iOS- bzw. Android-Projekt kopiert werden muss.


Das ist alles. Ich hoffe, dass dieses Skript für jemanden nützlich ist und viel Zeit spart.

Source: https://habr.com/ru/post/de446100/


All Articles