우리 회사도 글로벌인데 영어 버전도 지원해야지!
언제부턴가 다국어 지원이 흔한 기능이 되었다.
전에 사이드프로젝트 할때 i18n 써서 했던거라 대수롭지 않게 생각했는데 현업해서 해보니 생각보다 협업하기 어려웠고 절차가 번거로웠다. 우리는 i18n을 json 파일로 영문 전환 버튼으로 ko.json / en.json 바꿔서 적용했는데
자동화하기 전에 절차가 어땠냐면,
1. 개발하다가 ko.json 에 key value 를 추가한다
2. 검수하시는 직원께 메신저로 검수 요청을 보낸다
3. 확인 및 검수 후 답장을 보낸다
4. 검수 받은 영문을 en.json 에 key value 를 추가한다
위 절차가 번역물이 업데이트가 종종 일어날때마다 진행되니 번거로운건 둘째치고 업무 효율이 매우 낮아졌다.
(검수하시는 분도 본인 업무도 많은데 자꾸 요청드려서 미안했다..)
그렇게 몇번의 업데이트 후 다른거 개발하기도 바쁜데 번역에 업무시간을 자꾸 빼앗기기 싫어서 자동화하기로 했다.
구글 스프레드시트를 통한 다국어 번역 자동화하기
타 블로그에 자세히 정리도 되어있고 방법도 상세한데 나는 좀 과하게 자동화한 느낌도 나서.. 나름 간소화 버전으로 만들었는데 다른 분들 입맛에 맞을지는 모르겠다.
(완성본 프리 뷰)
위의 방식이다. 결국 컨셉은 1. ko.json 파일을 npm 명령어로 구글 스프레드시트에 업로드 2. 검수자는 구글 스프레드시트 화면만 바라보면 되고 3. 검수 됐다는 답장오면 한번씩 npm run download en.json 을 업데이트 해주면 된다.
절차 단계가 줄어든건 아니지만 업데이트 된 번역물만 뽑아서 검수자에게 전달하고 검수된 내용을 json 파일로 복붙하던 DX 개선과 특히, 같은 스프레드시트 화면을 바라보는 검수자와의 커뮤니케이션 비용은 확실하게 개선되었다.
아래부터는 구글 스프레드 시트와 연동하여 다국어 번역 절차를 간소화하는 방법을 서술하겠습니다.
1. 구글 스프레드시트 서비스 계정 만들기
구글 클라우드 대시보드 요 링크 타고 들어가서 아래 <서비스 계정> 클릭
2. 계정 이름 정도만 입력하고 완료 누르면 된다.
3. 만들어진 서비스 계정 옆에 편집 버튼을 눌러 키를 추가한다 (키 유형 JSON)
※ 만들어진 json 파일은 api 사용할때 인증해야되니 저장해두자
4. api로 컨트롤할 스프레드시트 만들기
링크 타고 빈 스프레드시트 하나 만들어준다.
아래 밑줄 친게 5번에서 사용할 process.env.SPREAD_SHEET_DOC_ID 부분이다.
공유 버튼 눌러서 만들어 두었던 사용자 계정 이메일을 등록!
참고로)
자동번역 열에 등록해 놓은 함수는 =IF(B2<>"",GOOGLETRANSLATE(B2, "ko", "en"),"")
다운로드 열에 등록해 놓은 함수는 =IF(D2<>"", D2,C2)
5. upload.js 만들기
npm i google-spreadsheet
npm i google-auth-library
npm i dotenv // (option!)
import dotenv from "dotenv";
dotenv.config();
import { GoogleSpreadsheet } from "google-spreadsheet";
import { JWT } from "google-auth-library";
import creds from "./translation/.credentials/august-sandbox-378002-e13c063fc08e.json" assert { type: "json" };
// 위에 import 는 3번에서 만든 json key 에서 불러온것임!
import fs from "fs";
const serviceAccountAuth = new JWT({
email: creds.client_email,
key: creds.private_key,
scopes: [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive.file",
],
});
const doc = new GoogleSpreadsheet(
process.env.SPREAD_SHEET_DOC_ID,
// SPREAD_SHEET_DOC_ID 는 4번에서 밑줄친 부분!
serviceAccountAuth
);
await doc.loadInfo();
console.log(doc.title);
const sheet = doc.sheetsByIndex[0]; // 난 첫번째 시트가 번역 시트여서 [0] 설정한 것
await sheet.setHeaderRow([ // 첫번째 행 header 설정 해주고
"key",
"한글",
"자동번역",
"검수",
"비고",
"다운로드",
]);
const rows = await sheet.getRows();
let existedKeys = []; // 이미 시트에 등록된 key는 제외해주려고 배열에 담음
for (const row of rows) {
existedKeys.push(row._rawData[0]);
}
const filePath = process.env.KO_JSON_PATH; // 사용하실 분들은 이 경로 설정만 하시면 됩니다
const jsonFile = fs.readFileSync(filePath);
const jsonData = JSON.parse(jsonFile);
// json key의 depth를 .으로 평탄화하는 재귀함수
function flattenObject(obj, parentKey = "", result = []) {
for (const [key, value] of Object.entries(obj)) {
const newKey = parentKey ? `${parentKey}.${key}` : key;
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
flattenObject(value, newKey, result);
} else {
const newObject = { key: newKey, 한글: value };
result.push(newObject);
}
}
return result;
}
const flattenedKoJson = flattenObject(jsonData);
// 이미 있는건 업데이트 해주지 않습니다. (있던 내용을 바꾸려면 그냥 시트에서 바꾸세요!)
const newFlattenedKoJson = flattenedKoJson.filter(
(obj) => !existedKeys.includes(obj.key)
);
console.log("새롭게 업데이트 될 Array: ", newFlattenedKoJson);
if (newFlattenedKoJson.length > 0) {
await sheet.addRows(newFlattenedKoJson);
}
console.log("Uploaded successfully");
6. download.js 만들기
import dotenv from "dotenv";
dotenv.config();
import { GoogleSpreadsheet } from "google-spreadsheet";
import { JWT } from "google-auth-library";
import creds from "./translation/.credentials/august-sandbox-378002-e13c063fc08e.json" assert { type: "json" };
import fs from "fs";
import { dirname } from "path";
const serviceAccountAuth = new JWT({
email: creds.client_email,
key: creds.private_key,
scopes: [
"https://www.googleapis.com/auth/spreadsheets",
"https://www.googleapis.com/auth/drive.file",
],
});
const doc = new GoogleSpreadsheet(
process.env.SPREAD_SHEET_DOC_ID,
serviceAccountAuth
);
await doc.loadInfo();
const sheet = doc.sheetsByIndex[0];
const rows = await sheet.getRows();
const fetchedRows = rows.map((row) => {
return row._rawData;
});
function arrayToNestedObject(arr) {
const result = {};
arr.forEach(([path, , , , , value]) => {
const keys = path.split(".");
let current = result;
keys.forEach((key, index) => {
if (index === keys.length - 1) {
current[key] = value;
} else {
if (!current[key]) {
current[key] = {};
}
current = current[key];
}
});
});
return result;
}
const nestedObject = arrayToNestedObject(fetchedRows);
const filePath = process.env.EN_JSON_PATH; // 마찬가지로 사용하실 분들은 요 경로를 설정해주시면 됩니다!
// 중간 폴더 없으면 생성
fs.mkdirSync(dirname(filePath), { recursive: true });
// 파일 생성
fs.writeFileSync(filePath, JSON.stringify(nestedObject, null, 2));
console.log("Downloaded successfully");
담백하게 적어서 금방 끝나버렸는데 내용이나 컨셉 설명은 타 블로그에 정리 잘된게 많으니 아래 링크를 보시는걸 추천드립니다.
https://velog.io/@calvinsnax/getting-i18n-with-google-spreadsheet
구글스프레드시트를 200% 활용한 국제화(i18n) 자동화 사례
비개발자와의 협업이 유독 중요했던 국제화 프로젝트. 구글스프레드시트를 활용하여 비개발자와의 협업을 멋지게 완성해낸 국제화(i18n) 자동화 사례를 소개합니다.
velog.io
https://www.wooslog.com/blog/internalization-automation
구글 스프레드시트를 통한 국제화 자동화
뤼튼에서는 글로벌한 유저들에 대비하기 위해 국제화를 진행하였습니다. 국제화는 한국어로 된 문구들을 다른 나라 언어로도 제공하는 기능을 말합니다.
www.wooslog.com
2탄은 react 에 적용하는 부분입니다:)
여기까지만 봐도 핵심 내용은 끝이긴하지만..
'OpenAPI' 카테고리의 다른 글
구글 스프레드시트를 통한 다국어 번역 자동화하기 -2 (2) | 2024.08.07 |
---|