401 — Translations - The-Balthazar/SupCom-Mod-Tutorials GitHub Wiki

Transferring strings_db.lua LOC files to Google sheets

This section assumes you have one or more pre-existing LOC documents that you wish to convert into a master translation spreadsheet.

Copy your primary LOC document into the first cell (A1) on a fresh Google Sheets sheet. You should end up with a key/value pair per cell. In B1 enter =REGEXEXTRACT(A1,"^[a-zA-Z_][a-zA-Z0-9_]*=") and in C1 enter =REGEXEXTRACT(A1,"=(.*$)"). Select B1 and C1 and double click the box in the bottom right corner of the selection to propagate the formula to all cells. You should now have all the keys down B and all the values down C, complete with = and surrounding "", which we want. If you used Split text to columns to break at the = it would have stripped those, and you'd have to re-add them yourself. From here, select columns B and C, copy, then shift-paste to convert them to values instead of formulas, and delete column A then add two header rows. In B1 put the two letter SupCom folder name for that language, such as US and in B2 but the appropriate ISO_639-1 code, such as EN.

You should now have something that looks like:

A B
US
EN
Engine0001= "Connecting to game host..."
Engine0002= "%s disconnected."
Engine0003= "Lost connection to %s."
Engine0004= "Connection to %s established."
Engine0005= "Connecting to %s..."
Engine0006= "%s: adjusting game speed to %+d"

If you have multiple existing LOC sheets for different languages, do the same for each on a different sheet within the dame document. You don't need the headers on the others, but it may help you keep track of things.

Combining multiple language LOC sheets

You can skip this step if you only had one LOC sheet to begin with.

Next we'll use VLOOKUP to merge the sheets. Starting from what should be C3, enter =VLOOKUP( then click A3, type ,, then select the sheet you're importing from and highlight columns A and B on it, and finish it off with , 2). The resulting formula should look something like =VLOOKUP(A3, RU!A:B, 2) if you also renamed your sheets or =VLOOKUP(A3, Sheet2!A:B, 2) if you didn't. Do that for each other LOC sheet in cell D3 and so on, and propagate them all down as before.

Any errors with the base sheets should be obvious at this stage, so take a moment to deal with any, then use the same copy shift-paste trick to convert everything to values and once that's done everything should be in one place. If you want to make sure you could do a VLOOKUP on the other sheets targeting the primary to see if anything was missed in the primary language, and once you're convinced it's all together, delete the other sheets.

Filling in the gaps with machine translations

For each additional language you wish to support, add column headers for them as described above. The full list of languages supported by the base game is:

English Russian German French Spanish Italian Polish Chinese Czech
Folder: US RU DE FR ES IT PL CN CZ
639-1: EN RU DE FR ES IT PL ZH CS

Then in cell J8 insert the following formula:

=IF(LEFT($B8,2)="--","--" & GoogleTranslate(right($B8,len($B8)-2),$B$2,J$2),IF($B8="","",CHAR(34)&GoogleTranslate(right(left($B8,len($B8)-1),len($B8)-2),$B$2,J$2)&CHAR(34)))

It needs to be J8 for that formula to function as expected. It takes whatever is in column B and if it starts with -- (A Lua comment) it strips that part, translates it, then re-adds the --. Otherwise it strips the first and last character (Assumed to be "") translates it, then surrounds it with "".

From here, select the cell and propagate out the function to all the empty cells. When selecting the cell, you can drag the lower right box to propagate it that way.

Unlike previous formulas we've used, we don't want to convert these machine translations into values. It'll make it easier to keep track of what is and what isn't translated by a human.

For translators: To translate an item replace the formula with your string, surrounded by "". If a machine translation is actually good, copy shift-paste it, to bake it in.

Conditional formatting for visibility

Optionally, in Format > Conditional formatting add the following rules for the whole sheet:

  • Text starts with --; and make it blue
  • Custom formula is =LEFT($A:$A,2)="--"; and make it blue
  • Cell is empty; and make it red
  • Custom formula is =ISFORMULA(A1); and make it purple
  • Custom formula is =AND(LEFT(A1,1)=CHAR(34),RIGHT(A1,1)=CHAR(34)); and make it green

The first two highlight comments, the 4th will highlight all machine translations, and the last will highlight every value starting and ending with "; that's what CHAR(34) is; writing " explicitly will cause it to try to interpret it and break.

Exporting to files

In cell A1 add the relative path you want to export to. For example /loc/ or /mods/myCoolMod/hook/loc/, and in cell A2 add --. Then, in Extensions > Apps Script paste the following function:

function generateUpdatedStringsDBFiles() {
  function replaceAll(str, find, replace) {
    return str.replace(new RegExp(find, 'g'), replace);
  }

  var routeFolder = DriveApp.getFolderById('REPLACE ME');

  var curDocument = SpreadsheetApp.getActive();
  var allSheets = curDocument.getSheets();

  for (var sheet in allSheets) {
    var curSheet = allSheets[sheet];
    var lastCol = curSheet.getLastColumn();
    var totalRows = curSheet.getLastRow();

    var translationVarList = curSheet.getRange(1, 1, totalRows).getValues();

    var directoryString = translationVarList[0][0];
    var regex = /([^/]+)/g;
    var dirName;
    var sheetFolder = null;
    while((dirName = regex.exec(directoryString)) !== null) {
      if (sheetFolder == null) {
        sheetFolder = routeFolder.createFolder(dirName[0]);
      } else {
        sheetFolder = sheetFolder.createFolder(dirName[0]);
      }
    }

    for (var curLangCol = 2; curLangCol <= lastCol; curLangCol++) {
      var outputArray = [];
      var translationResultList = curSheet.getRange(1, curLangCol, totalRows).getValues();

      //skipping the first row because it contains folder data
      for (var curRow = 1; curRow < totalRows; curRow++) {
        var locKey = translationVarList[curRow][0]
        var locValue = translationResultList[curRow][0]
        if (locValue.substring(0,1) == '#') { // #ERROR! or #REF! or whatever
          return Logger.log('Error value recieved from '+translationVarList[0][0]+' at '+locKey+' in '+translationResultList[1][0])
        } else {
          locValue = replaceAll(locValue,"\r\n","\\n")
          locValue = replaceAll(locValue,"\n","\\n")
          outputArray.push(locKey + locValue);
        }
      }
      outputArray = outputArray.join('\n');

      var targetFolder = sheetFolder.createFolder(translationResultList[0][0]);
      targetFolder.createFile("strings_db.lua", outputArray+'\n', MimeType.PLAIN_TEXT);
    }
  }
}

In line 6 replace REPLACE ME with the folder ID of the target export folder. You can get the folder ID by copying it from a folder sharing link. For example, from: https://drive.google.com/drive/folders/1_9b33c680f39c4037a0_e2693d67a1a2?usp=sharing the part of that you want would be the part between the last / and the ?: 1_9b33c680f39c4037a0_e2693d67a1a2. Which should look like this after pasting it in:

var routeFolder = DriveApp.getFolderById('1_9b33c680f39c4037a0_e2693d67a1a2');

Then run the function and download the output from the export folder. Be sure to clear the export folder before you next export.

The script supports multiple sheets of the sort described above, for if you were doing this for multiple mods or something. When the exporter creates additional folders in the Google Drive export folder, it will create independent folder trees per sheet regardless of any overlap in existing folders within the export folder. These will be condensed down when downloaded.