Seize the day

POST : Android Dev Study

안드로이드 다국어 번역툴 #2

  집단 지성을 이용한 안드로이드 다국어 지원 방법 #0에 이어서 안드로이드의 언어 파일에서 엑셀 파일을 생성하는 툴을 제작했다. 이 툴은 처음 한 번만 사용되지만 이게 없다면 개별 언어파일에서 해당 스트링 리소스를 일일이 복사하여 붙여넣기로 해야 하므로 필요한 툴이다. 


  처음에는 엑셀 OLE오토메이션을 이용하는 윈도즈 프로그램(Win32)을 구현하려고 했으나 기술 조사를 해보니 자바스크립트로 엑셀 파일을 다루는 라이브러리(xlsx)가 있어서 그거를 이용했다. 


  소스 편집 도구는 전에는 ATOM을 이용했으나 이번에는 비주얼 스튜디오 커뮤니티 버전을 이용했다. 노드 프로젝트를 생성할 수 있고, F5로 변수 디버깅도 가능했다. 좋은 도구다. 


  필요한 라이브러리 설치한다. xlsx-workbook 라이브러리는 xlsx를 좀 더 쉽게 사용하도록 랩핑한 라이브러리이고 예제 샘플만으로도 충분히 사용하기 편했다.


   npm install xml2js

   npm install hashmap

   npm install xlsx-workbook


android_base 서브 모듈의 리소스 폴더와 app 리소스 폴더에서 언어 파일을 각각 읽어와 하나의 엑셀 파일을 생성하는 소스코드이다. 

'use strict';

const xml2js = require('xml2js')
const hashmap = require('hashmap')
const fs = require('fs')

const Workbook = require('xlsx-workbook').Workbook;
const workbook = new Workbook()
const sheet = workbook.add("sheet1")

const replaceMap = new hashmap.HashMap()
replaceMap.set("%d", "${num}")
replaceMap.set("%s", "${str}")
replaceMap.set("%1$d", "${num1}")
replaceMap.set("%2$d", "${num2}")
replaceMap.set("%3$d", "${num3}")
replaceMap.set("%4$d", "${num4}")
replaceMap.set("%1$s", "${str1}")
replaceMap.set("%2$s", "${str2}")
replaceMap.set("%3$s", "${str3}")
replaceMap.set("%4$s", "${str4}")

const replaceKeys = replaceMap.keys()

const langColumnIndexMap = new hashmap.HashMap()
langColumnIndexMap.set("en", 4)
langColumnIndexMap.set("ko", 5)
langColumnIndexMap.set("ru", 6)
langColumnIndexMap.set("de", 7)

function read_resouce_dir(res_dir) {
    console.log("\n" + res_dir)
    fs.readdirSync(res_dir).forEach(filename => {
        if (filename == "values" || filename.startsWith("values-")) {
            const langCode = filename == "values" ? "en" : filename.substr(7)
            if (langCode.length == 2) {
                console.log(filename + " -> " + langCode)

                const langColIndex = langColumnIndexMap.get(langCode)
                sheet[2][langColIndex] = langCode
                const xmlPath = res_dir + filename + "/strings.xml"
                write_language(langCode, langColIndex, xmlPath)
            }
        }
    })
}


const stringId2RowIndexMap = new hashmap.HashMap()
let nextStringIdRowIndex = 4

function write_language(langCode, langColIndex, xmlPath) {
    const xmlString = fs.readFileSync(xmlPath)
    const parser = new xml2js.Parser()

    parser.parseString(xmlString, function (err, result) {
        const len = result.resources.string.length
        for (let i = 0; i < len; i++) {
            const item = result.resources.string[i]
            const id = item.$.name
            let row
            if (stringId2RowIndexMap.has(id)) {
                row = stringId2RowIndexMap.get(id)
            } else {
                row = nextStringIdRowIndex++
                stringId2RowIndexMap.set(id, row)
                sheet[row][0] = id
            }

            write_string(langCode, row, langColIndex, item._)            
        }
    })
}


const mustHaveColIndex = 3

function write_string(langCode, row, col, value) {
    let mustHave = ""
    
    for (let i = 0; i < replaceKeys.length; i++) {
        const str0 = replaceKeys[i]
        const index = value.indexOf(str0)
        if (index == 0 || (index > 0 && value[index - 1] != '%')) {            
            const str1 = replaceMap.get(str0)
            mustHave += " " + str1
            value = value.replace(str0, str1)
        }
    }

    if (langCode == "en" && mustHave.length > 0) {
        sheet[row][mustHaveColIndex] = mustHave.substr(1)
    }

    sheet[row][col] = value
}


const android_base_res_dir = "c:\\Project\\screenshot\\android_base\\res\\"
const app_res_dir = "c:\\Project\\screenshot\\app\\src\\main\\res\\"

sheet[0][0] = "Screenshot touch translation"
sheet[3][0] = "[common]"
read_resouce_dir(android_base_res_dir)

nextStringIdRowIndex++
sheet[nextStringIdRowIndex++][0] = "[app]"
read_resouce_dir(app_res_dir)

workbook.save("Screenshot_touch")


안드로이드 언어 파일에는 %1$d와 같은 특수한 기호가 있는데, 이것은 번역자가 이해하기 어렵고 오타가 많기 때문에 ${num1} 처럼 사용하기 쉬운 키워드로 변경했다. 그리고 이것을 Must have 컬럼에 기록해서 나중에 번역이 제대로 되었는지 점검할 때 사용한다.


최종 생성된 엑셀 파일은 다음과 같다.



Screenshot_touch.xlsx


이 파일에 설명을 추가하고 구글독스에 올리면 1단계는 완료된다. 다음 번에는 번역자가 실제로 번역을 테스트할 수 있는 도구를 구현하겠다. 




top

posted at

2018. 6. 5. 01:39


CONTENTS

Seize the day
BLOG main image
김대정의 앱 개발 노트와 사는 이야기
RSS 2.0Tattertools
공지
아카이브
최근 글 최근 댓글
카테고리 태그 구름사이트 링크