[Android, iOS] 번역 시트 관리하기 (구글 스프레드시트)
개발을 하면서 개발적인 부분 말고 힘들었던 부분들 중에 하나는 "다국어 관리" 였다.
다국어를 처리하는 기존의 방식은 이랬다.
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'), "…");
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
끝!!!!!!!!!!!!!!!!