철스토리

[Android, iOS] 번역 시트 관리하기 (구글 스프레드시트) 본문

안드로이드/프로그래밍

[Android, iOS] 번역 시트 관리하기 (구글 스프레드시트)

HyunChol 2018. 9. 8. 23:20
반응형

개발을 하면서 개발적인 부분 말고 힘들었던 부분들 중에 하나는 "다국어 관리" 였다.


다국어를 처리하는 기존의 방식은 이랬다.

1. 기획자가 기획문서를 작성하면서 문구를 정한다.

2. 안드로이드, 아이폰 개발자 중 먼저 개발하는 부분에 대해 키값과 문구를 구글시트에 등록한다.

3. 기획자가 문구를 정리해서 번역가에게 전송한다. 총 5가지의 언어를 지원한다. - 한국어, 영어, 중국어, 대만어, 일본어 (번역을 외주로 했음)

4. 기획자가 번역이 도착하면 도착한 순서대로 시트에 업데이트 한다.

5. 개발자가 업데이트 된 번역에 대해 개발자가 키값을 찾아 적용한다.

이러한 과정으로 번역을 적용하는건 그렇게 어렵거나 많이 불편하진 않았다.

하지만 문제는 문구가 수정될 때 발생했다.


구글시트에 모든 문구에 대한 번역이 들어가 있다보니 1000라인(1000개의 단어 또는 문장) 이상 되는데

이중에서 문구가 중간중간 수정이 되고, 번역이 수정되면

그것을 찾아서 개발자가 또 적용해야하고....

이런게 반복되면 기획자가 복사붙여넣기 할 때도 실수할 수 있고, 개발자가 복사붙여넣기 할 때도 실수할 수 있는 상황이 발생했다.


그래서 여러가지를 찾아보게되었다.

그중에서 찾게된 방법을 정리해놓고 앞으로 사용해 보려고 한다. 참고한 사이트는 아래의 사이트들이다.


https://tech.wanted.co.kr/android/2018/03/30/android-strings-1.html

https://github.com/aurelhubert/android-ios-drive-export


구글드라이브에 구글시트 생성


시트 작성하기

아래처럼 구글시트에 글을 작성한다.

여기서 중요한 포인트

  • Description :  주석부분
  • en, fr, ko 등 : values-en, values-ko 등으로 파일이 생성됨
  • %1$s, %2$s, %3$d, %4$d : 이건 안드로이에서 필요한 내용인데 아이폰은 자동으로 %@로 매핑되게끔 소스를 짰음.
  • 언어추가 : 언어가 추가될때는 Tawiwanese (zh-rtw) 오른쪽으로 계속해서 언어를 추가하면 됨


메뉴 구성하기

도구 - 스크립트 편집기 를 눌러서 스크립트를 작성한다. 아래 그림 참조.


코드.gs

var appName = "AppName";


function onOpen() {

  var sheet = SpreadsheetApp.getActiveSpreadsheet();

  var entries = [

    {

      name : "리소스 생성",

      functionName : "exportResources"

    }

  ];

  sheet.addMenu(appName, entries);

};


// Export resources function

function exportResources() {

  

  // Folders

  var appFolder = createOrGetFolder(appName);

  var androidFolder = createOrGetFolder("Android", appFolder);

  var iOSFolder = createOrGetFolder("iOS", appFolder);

  

  // Data

  var sheet = SpreadsheetApp.getActiveSheet();

  var data = sheet.getDataRange().getValues();

  

  var i = 2;

  while (data[1][i] != null && data[1][i].length > 0) {

  

    //var results = data[1][i].match(/\((\w\w)\)/g);

    var results = data[1][i].match(/\(([a-zA-Z-]*)\)/g);

    if (results.length > 0) {

      var language = results[0].replace("(", "").replace(")", "");

      createAndroidResources(language, data, androidFolder, i);

      createIOSResources(language, data, iOSFolder, i);

    }

    

    i++;

  }

  

}


// Create an XML file for Android

// language: Current language

// data:     Spreadsheet data array

// folder:   Folder where create the file

// column:   Index of the column

function createAndroidResources(language, data, folder, column) {

  

  var folderName = "values";

  

  if (language != "en") {

    folderName += "-" + language;

  }

  

  var languageFolder = createOrGetFolder(folderName, folder);

  

  var content = "<resources>";

  content += "\n\n";

  content += "\t<!-- App name -->";

  content += '\n\t<string name="app_name">' + appName + '</string>';

  

  for (var i = 3; i < data.length; i++) {

    

    if (data[i][1].length == 0) {

      continue;

    }

    

    if (data[i][0].length > 0) {

      content += "\n\n\t<!-- " + data[i][0] + " -->";

    }

    

    var formatted = "";

    if (data[i][2].indexOf("%s") > -1 || data[i][2].indexOf("%d") > -1) {

        formatted = ' formatted="false"';

    }

    

    var escapedContent = data[i][column]

    .replace(new RegExp("\'", 'g'), "\\'")

    .replace(new RegExp("\\.\\.\\.", 'g'), "&#8230;");

    

    content += '\n\t<string name="' + data[i][1] + '"' + formatted + '>' + escapedContent + '</string>';

  }

  

  content += "\n\n</resources>";

  

  var file = createOrGetFile("strings.xml", languageFolder);

  file.setContent(content);

}


// Create a localizable file for iOS

// language: Current language

// data:     Spreadsheet data array

// folder:   Folder where create the file

// column:   Index of the column

function createIOSResources(language, data, folder, column) {

    

  var content = "// App";

  content += "\n";

  content += '"APP_NAME" = "' + appName + '";';

  

  for (var i = 3; i < data.length; i++) {

    

    if (data[i][1].length == 0) {

      continue;

    }

    

    if (data[i][0].length > 0) {

      content += "\n\n// " + data[i][0] + "";

    }


    var value = data[i][column];

    value = value.replace(/%[0-9]\$[sdf]/g, "%@");

    //value = value.replace(/%s/g, "%@");

    value = value.replace(/"/g, '\\"');

    value = value.replace(/(?:\r\n|\r|\n)/g, '\\n');

    

    content += '\n"' + data[i][1] + '" = "' + value + '";';

  }

  

  var fileName = "Localizable_" + language.toUpperCase() + ".strings";

  var file = createOrGetFile(fileName, folder);

  file.setContent(content);

}




////////////

// HELPER //

////////////


// Check folder

function createOrGetFolder(name, folder) {

  var folders;

  if (folder == undefined) {

    folders = DriveApp.getFoldersByName(name)

  } else {

    folders = folder.getFoldersByName(name)

  }

  

  var mainFolder;

  if (folders.hasNext()) {

    mainFolder = folders.next();

  } else {

     if (folder == undefined) {

       mainFolder = DriveApp.createFolder(name);

     } else {

       mainFolder = folder.createFolder(name);

     }

  } 

  

  return mainFolder;

}



// Check file

function createOrGetFile(name, folder) {

  var files;

  if (folder == undefined) {

    files = DriveApp.getFilesByName(name)

  } else {

    files = folder.getFilesByName(name)

  }

  

  var file;

  if (files.hasNext()) {

    file = files.next();

  } else {

     if (folder == undefined) {

       file = DriveApp.createFile(name, "");

     } else {

       file = folder.createFile(name, "");

     }

  } 

  

  return file;

}


위의 소스를 저장한 후에 구글시트로 돌아가면 "AppName"이라는 메뉴가 생성이 되었다.


번역 생성하기

AppName - 리소스 생성을 누른다.


그러면 완료 될 때까지 진행중 메시지가 뜬다.


생성된 파일 확인하기


Android


iOS



끝!!!!!!!!!!!!!!!!

반응형
Comments