우리가 다국어 처리가 있었어..?(번역 자동화)
우리가 다국어 처리가 있었어..?(번역 자동화)
발표자료 완성!: https://gamma.app/docs/-jl63f5t028vswdx
Version1. 프로세스 개선
번역 프로세스
현재 : 한글을 작성함 → 소스 코드에 작성 → 엑셀로 옮김 → 번역요청 → 엑셀채움 → 소스코드로 옮김 (수동)
자동 : 한글을 작성함 → 소스 코드에 작성 → 엑셀로 옮김 → 번역요청 → 엑셀채움 → 소스코드 옮김 (자동화)
생각 정리!
현재 : 한글을 작성함 → 소스 코드에 작성 → 엑셀로 옮김 → 번역요청 → 번역완료 → 소스코드로 옮김 (수동)
자동 : 한글을 작성함 →(1. i18n-parser)→ 소스 코드에 작성 →(2. google-spreadsheet)→ 엑셀로 옮김 → 번역요청 → 번역완료 →(3. google-spreadsheet)→ 소스코드 옮김 (자동화)
문제 정의
문제: 다국어 귀찮다
뭐가 귀찮아?
→ 위의 과정이
반복되는 일들이 뭐가 있어?
→ 사용한 한글 문구를 json으로 만들기 ⇒ i18n-parser
→ 만든 json을 구글 시트에 옮기기 ⇒ google-spreadsheet upload
→ 구글 시트에 옮긴 후 번역 요청하기 ⇒ 업로드 시 번역가에게 알림 (⇒ 귀찮아 하실 것 같아 보류,,,)
→ 번역 완료되면 구글 시트의 값을 소스코드로 옮기기 ⇒ google-spreadsheet download
- 번역가와의 소통 비용 발생
번역으로 부터 완벽하게 벗어나려면??
→ 번역 후 배포까지 가능하도록 세팅!
개발자 : 소스코드 작성 → 커밋 시 코드 스캔(pre commit) → 소스코드 JSON업데이트 → push 시 구글 시트 업데이트(pre push)
변역가 : 구글 시트 업데이트 → 베포 버튼 클릭 → B레포 github action 실행 → dev/stg 배포
code scanner : i18next-parser
Process1 → O
- 소스코드에 t({‘한글’}) 을 입력
-
commit 시 public/locales 각각에 추가 자동화( git precommit hook
i18next-scanner
이용) - public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (
google-spreadsheet
이용해 upload 스크립트 작성) - 번역 요청 (dev 배포 전 / 후 ??)
- build 시 public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (
google-spreadsheet
이용)
User Flow
- t({‘한글’}) 이런식으로 작업 (소스코드 내에서 원래 하던대로 작업)
- 번역 요청
- 번역 완료 되면 push(stg배포)
장점
- 아름다운 DX (json 입력, 구글시트 입력, 구글시트 동기화 필요X)
- 번역과 비동기적 작업 가능 (번역 완료 여부와 상관없이 개발 가능)
단점
- 번역과 비동기적 작업 가능 (번역이 완료된 줄 알고 prd 올렸는데 번역이 안되었을 수 있음 - 휴면에러 조심!)
- 변수 처리 어떻게 할지 리서치 필요
- 라이브러리 의존도 상승 (
i18next-scanner
, )
참고
구글 스프레드 시트 자동화 : https://www.wooslog.com/blog/internalization-automation
국제화 자동화 가이드 : https://ui.toast.com/weekly-pick/ko_20210303
국제화 자동화 가이드(디테일) : https://hjleee93.github.io/frontend/javascript/autoLocalization/
자동화 작업 : https://constell847.oopy.io/f6e5a133-ef47-4017-a71b-9127953aa511
Process2 → X
- 소스코드에 t({‘한글’}) 을 입력
-
commit 시 public/locales 각각에 추가 자동화( git precommit hook
i18next-scanner
이용) - public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (
google-spreadsheet
이용해 upload 스크립트 작성) - 번역 요청 (dev 배포 전 / 후 ??)
- build 시 public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (
google-spreadsheet
이용)
User Flow
현재 : 한글을 작성함 → 소스 코드에 작성 → 엑셀로 옮김 → 요청 → 엑셀채움 → 소스코드로 옮김 (수동)
-
t({‘한글’}) 이런식으로 작업 (소스코드 내에서 원래 하던대로 작업)
⇒ push 시 스캔해서 json파일 만듬
⇒ 구글 시트에 업로드
2.
- 번역 완료 되면 push
Process3 → X
- 소스코드에 t({‘한글’}) 을 입력
-
commit 시 public/locales 각각에 추가 자동화( git precommit hook
i18next-scanner
이용) - public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (
google-spreadsheet
이용해 upload 스크립트 작성) - build 시 public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (
google-spreadsheet
이용)
구글 시트 내에 github action을 트리거하는 스크립트 작성 ⇒ 스크립트 실행 버튼 클릭 ⇒ stg 배포
(번역 요청 후 기다리고 배포 하는 과정을 번역쪽에 위임)
피드백 ⇒ PR로 올릴 수 있으면 좋을 듯 / ⇒ vpn에서 걸릴 . 수있음 github 접근 자체가 안딤
PR을 올린다? → 우리가 Merge를 해줘야함
번역쪽에서 빌드한다? → 우리 작업 시 merge가 필요하다
충돌은? →json에서만 난다 ⇒ 그럼 굳이 검사가 필요한가?
거스 승인 떨어졌다!!! pr말고 deploy하는걸로!!
아아아…안돼…
GitHub Actions 실행의 IP 주소가 허용 목록에 포함되어있어야 한다고 한다..
아아아나후아일누이아아아,,,,,,,,
어??
ㄱㄴ????????
헠헠헠헠허컿커허
내일 거스께 열어달라고 하잫ㅎㅎㅎㅎㅎ흫히ㅣ히히힣
아 잠만… 여기 ip는 구글 서버ip잖아… 동적으로 변경되는걸 대응안되지…
그러다면?
중간에 번역을 위한 레포를 하나 파서
여기는 접근 가능하게 하고
번역 레포에서 조직 레포로 트리거 보낸다면?
깃헙 액션 ip는 동적으로 변하긴하지만 그 범위가 정해져있다
그리고 일주일에 한 번 업데이트 된다
또한 이값을 자동으로 불러오는 방법이 있긴 하다
- ⇒ 스텍오버프로워의 github action ip white list 등록 방법
- ⇒ 깃헙 커뮤니티의 등록 방법
그렇다면 이론적으로는 가능하지 않음??
시트 → (ip 열어둠) → 번역레포 → (github action ip목록만 whitelist에 추가함)→ 조직레포
⇒ 근데 조직 레포 자체가 vpn 타야돼서 조직내에 만드는 것은 안돼…ㅜ
⇒ 할려면 번역레포를 개인레포로 만들고 개인 레포에서 조직 레포로 트리거 보내야 되는데… 이걸 인프라 팀이 승인 해줄까..?
⇒ 99.9% 혼날듯,,
아니면 개인레포에 서버 하나 띄워서 JWT로 인증과정 거치고 트리거 보낸다면??
보안적 이슈는?
조직레포에 접근 가능한 구멍이 생긴다
⇒ 이게 구멍이 맞나?
⇒ 트리거의 역할은 하지만 어떤 엑션이 돌게는 못한다
⇒ 그럼 괜찮지 않음??
가능한 이슈는 트리거를 겁나 많이보내는 이슈 생길 수 있음
⇒ 어케 막을까…
⇒ 중간 레포에서 타이머 같은 거 설정해서 특정 시간 동안 한번만 실행되게 하면 되지 않나?
라는 망상해봤습니다.
결론 → Process 1 채택 thank you gus!
프로세스 개선
현재 프로세스
- 개발 시 한글을 작성함
- 소스 코드에 작성
- 구글 시트로 옮김
- 번역가에게 번역요청
- 번역가가 구글 시트채움
- 개발자에게 연락
- 개발자가 소스코드로 옮김
- 개발자가 PR 작성해서 merge함
자동화 프로세스
- 개발 시 한글을 작성함
소스 코드에 작성→ Push시 소스코드 스캔해서 json 업데이트구글 시트로 옮김→ Dev PR 머지 시 구글 시트 업데이트번역가에게 번역요청- (번역가께서 번역이 필요한 시점에 알아서)구글 시트 채움
개발자에게 연락→ 시트버튼 클릭(PR 생성)개발자가 소스코드로 옮김- 개발자가 PR 작성해서 merge함 → 올라온 PR을 보고 머지함
과정
Step1. 소스코드 스캔 ⇒ 완.
TODO
- 소스코드를 스캔해서 t(‘‘)로 다국어 처리한 부분을 파싱 → 각각 public/locales/{lng}/common.json 으로 변환
기존에 있는 키에 대한 value
- 패스
기존에 없는 키에 대한 value
- 키값을 value에 추가
- 스캔 시 변수 처리 확정 지을 것 (논의) =:> 변수에 사용 가능여부
- 결론
- json ⇒
"에게 답글 달기": "에게 답글 달기",
- 사용 시 ⇒
{t('에게 답글 달기', { nickname })}
- json ⇒
- 결론
기존에 있는 키 삭제했을 경우
- common_old.json에 모아놓음
- 시트 업데이트 시 해당 키값들의 row는 제거
- 왜냐하면 스캔뜰때마다 해당 키값들은 제거되어 업로드 될 것이고, 시트에서 PR을 만들면 다시 해당 키값들이 포함되서 머지될꺼임 ⇒ 이런 문제 싱크를 맞춰주기 위해서임
- key, value의 관리 주체가 key : 개발자가 관리 (키는 우리가 만들어요) vlaue: 번역가가 관리 (번역본은 번역가님 따를게요) 로 생각을 했음
- 시트 업데이트 시 해당 키값들의 row는 제거
라이브러리 선정i18next-parser VS i18next-scanner
i18next-scanner는useTranslation
훅 탐색시 네임스페이스가 필요해서 i18next-parser 선택함
기본 : 파싱한 단어 json 추가 시 defaultValue는 key와 동일
복수형 : variables
배열에 있는 단어가 있으면 로 감싸줌
- i18next의 권장 복수형 처리 방식과 우리가 기존에 사용하던 방식이 달라서 원하는 변수 파싱해서 감싸는 방식으로 로직 작성(기존 우리 사용방법)
참고
i18next-parser결정 근거: https://velog.io/@1003gorkd/다국어-서비스-지원하기
복수형 처리 : https://www.i18next.com/translation-function/plurals
Step2. pre push 시 json 업데이트 ⇒ 완.
pre-push에 npm run scan
추가~ (Thank you Gus🫡🫡)
→ 로 만은 안된다! ^^ㅣ
npm run scan을 통해 locales/*/.json 파일을 업데이트 해줬으면 이파일들을 commit 후 합쳐서 push 해줘야 한다
npm test
npm run scan
git add public/locales/**/*.json
if git diff --cached --quiet; then
echo "No changes in locales JSON files, skipping commit."
else
git commit -m 'create locales json'
fi
음음 잘 올라감~
하지만 IDE가 create locales json 커밋까지 push한 거를 인식못함 ⇒ 흐린눈으로 넘어가기
Step3. dev 에 merge 시 구글 시트 업데이트 ⇒ 완.
TODO
- 권한 설정 env로 변경 + github 비밀에 등록
- github workflow로 테스트 성공
- upload로직 수정
준비
- 구글 시트에 접근 가능한 서비스 계정 생성(from. Google Cloud Console)
- 서비스 계정에 sheet API 권한 추가
- 서비스 계정 인증키 발급
- 해당 구글 시트에 서비스 계정 권한 추가
- 이게 무슨 의미가 있냐..?
인줄 알았는데
- 서비스 계정을 만든다는 것은 그냥 ‘가상의 구글 계정’ 하나 더 만드는 것
- 서비스 계정 token으로 인증을 ⇒ 로그인
- 구글 시트 업데이트 하기 위해서는 서비스 계정에 엑세스 권한 + 편집 권한 이 있어야 함
- 권한 인증 이후 Sheet API를 사용해서 시트 수정가능 그래서 필요함!
3-1. 구글 시트 업데이트 스크립트 작성
먼저 구글 시트 접근하기 위해서 구글 클라우드 서비스 계정을 만들고 API 접근 가능하게 열어준다(sheet, drive API)
구글 시트에 서비스계정을 편집자로 엑세스 권한을 등록한다
3-2. PR merge 시 github action으로 업데이트 스트립트 실행
PR이 머지 되었을 경우를 트리거를 잡음
on:
pull_request:
types: [closed] # PR이 닫힐 때, 즉 머지될 때 실행
이런 식으로 하고 근데 이렇게 하면 그냥 PR을 닫았을때도 작동하기 때문에 job부분에
jobs:
run-script:
runs-on: ubuntu-latest # 사용할 운영 체제
if: github.event.pull_request.merged == true # PR이 머지되었는지 확인
이렇게 조건문도 추가해준다.
- 피드백 반영 - 모든 PR merge가 아닌 dev로 merge 될때만 돌게끔 변경!
on:
pull_request:
types: [closed] # PR이 닫힐 때, 즉 머지될 때 실행
workflow_dispatch:
jobs:
run-script:
if: github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev'
...
그리고 upload 로직을 넣은 스크립트를 실행시켜준다.
steps:
- name: Checkout code
uses: actions/checkout@v2 # 코드 체크아웃
- name: Set up Node.js
uses: actions/setup-node@v2 # Node.js 환경 설정
with:
node-version: "20"
- name: Install dependencies
run: npm install # 필요한 의존성 설치
- name: Run your script
run: node translate/upload.js # 원하는 스크립트 실행
참고 : https://wise-office-worker.tistory.com/44
403에러 : https://stackoverflow.com/questions/38949318/google-sheets-api-returns-the-caller-does-not-have-permission-when-using-serve
구글 스프레드 시트 공식문서 : https://theoephraim.github.io/node-google-spreadsheet/#/guides/authentication?id=service-account
Thank you chatGPT❤️
3-2. upload 로직 만들기!
전제 : 번역의 우선순위는
- key : 소스코드 > 시트
- value : 시트 > 소스코드
- case1. 기존에 있던 value가 수정될 경우
개발 : dev merge 되며 시트 업데이트
번역가 : 기존의 key값의 value를 변경 아직 PR 날리기 전
⇒ upload 시 기존에 있던 key값의 value가 달라 충돌 발생
- 기존에 있던 key값은 업데이트 패스
- case2. 기존에 있던 key가 수정될 경우
개발 : 스캔 뜨는 순간 새로운 key값이 추가됨 + 이전 키 값 사용 안함
번역가 : 새로운 key값이 생김
⇒ 변경된 key값은 새로생긴 key와 동일하게 취급
- 새로운 row에 추가 ⇒ 변경 이전 key값은 JSON에서 사라짐 ⇒ 오래된 값을 기억 할 수는 있음 common_old.json 으로 저장됨
- 시트에 업데이트 할 때는 common_old.json에 해당하는 row를 삭제해줌
Step4. 구글 시트에서 PR 생성 버튼 구현 ⇒ 완.
TODO
- 이미 브랜치가 생성 되었을 경우 예외처리
한번에 하나의 PR만 생성 가능하게 할 것인가? ⇒ 그러면 그냥 alert에 기다리라고 띄우면 끝여러개 PR 생성 가능하면? ⇒ auto-update-branch-1, auto-update-branch-2 이런식으로 브랜치만들기하나의 PR에서 commit으로 추가되는 형식?- 브랜치을 없애고 새롭게 PR 날림
준비물
- 해당 레포에 fine-grained personal access token 받아야함(접근 권한 받기 위해서)
- 해당 기능 수행을 위해 권한 설정을 해줘야함
- 아래 엔드포인트에 접근이 가능해야함
1. `https://api.github.com/repos/${repo}/contents/${path}?ref=${baseBranch}`; 2. GET : `https://api.github.com/repos/${repo}/branches/${branch}`; 3. POST : `https://api.github.com/repos/${repo}/git/refs`; 4. POST : `https://api.github.com/repos/${repo}/pulls`;
즉, 권한이 Contents ⇒ 1번 Administration ⇒ 2, 3번 Pull requests ⇒ 4번 가 필요하다 위 권한을 위해서는 Metadata가 필수로 필요해서 결국 4개의 권한이 필요하다
- 아래 엔드포인트에 접근이 가능해야함
- 해당 기능 수행을 위해 권한 설정을 해줘야함
동작 흐름이
- ‘번역 완료’ 버튼을 누르면 스크립트가 실행됨
- 구글 시트를 json 형태로 만듬
- 현재 dev의 가장 최근 commit을기준(SHA로 가져옴)으로 새로운 branch를 생성
- 기존에 branch가 있으면 삭제 후 다시 만듬
- 생성된 브랜치에서 public/locales/{lngs}/common.json 데이터들을 가져옴
- 2번에서 만든 JSON은 인코딩해서 public/locales/{lng}/common.json 에 업데이트함
- 해당 변경사항들을 commit함
- PR을 생성함
이렇게 PR이 생성되었음
이제
- 흐뭇한 미소를지으며 해당 repo에 들어감
- 머지를 해줌
참고 : https://docs.github.com/ko/enterprise-cloud@latest/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
«주의»
- github에 시크릿 키 넣을 때 “” 빼야함
-
구글 시트의 1번째 row가 헤더가 됨… 무조건,,,
- 1번째 row 헤더
-
2번째 row title로 잡음
⇒ 그래서 upload.js / apps script 에 헤더 처리 따로 해줌
- T() 안에 삼항연산자 넣으면 인식 못함 t( check ? ‘A’ : ‘B’) ⇒ check ? t(‘A’):t(‘B’) 이렇게 해야함
PR description
전체적인 플로우는 위와 같습니다!
다국어 처리 시 키값에서 변수를 부분으로 감싸고 나머지는 동일합니다.
{
t("P 단위로 교환 가능합니다.", {
points: MINIMUM_POINTS.toLocaleString(),
});
}
최대한 예외상황들을 고려해봤는데 그래도 놓치는게 있을 것 같아서 현재 시트에 업데이트하지 않고
[MoneyBall-웹뷰] 전체 번역(Auto)
에서 운영 이후 잘 작동한다 싶으면 변경하려고 합니다!
[처리한 예외상황]
- 소스코드 스캔 시
- 기존에 있는 키값 ⇒ update 패스
- 기존에 있던 키값중 소스코드에서 삭제된 키값 ⇒ common_old.json에 저장
- 새로운 키값 추가 ⇒ 새로운 key: value로 추가
- 새로추가된 값은 key === value 입니당
- 번역 PR 후 sheet update(dev PR merge) 하는경우
- 기존에 있는 키값 ⇒ update 패스
- 기존에 있던 키값중 소스코드에서 삭제된 키값(common_old.json) ⇒ row 제거
- 새로운 키값 추가 ⇒ 새로운 row로 추가
- 새로운 키값을 추가할 경우 ko는 key ===value이지만 en, ja는 빈값으로 넣어놨습니다.
- 소스코드에는 ko, en, ja 모두 새로운 값은 key===value로 만들었지만 이렇게 업데이트하면 번역 시 빈 값을 찾기 어려울 것 같아 수정했습니다.
- 아래 사진처럼 빈값은 색깔을 다르게 줘 찾기 편해졌습니다.
- 새로운 키값을 추가할 경우 ko는 key ===value이지만 en, ja는 빈값으로 넣어놨습니다.
- 번역 PR 생성 시
- 빈 값이 있으면 생성을 못하도록 막음
변경 후 다국어 처리의 프로세스는
개발 시에는
- 개발할 때 변수는 로 키값 생성
외에는 따로 처리할건 없습니다.
번역 후 PR이 생성되면 머지하면 끝입니당.
추가 개발 사항
- 확장성 고려 할것 ⇒ 파일 위치, 파일 이름, token, key 값들 관리할 수 있게 개선
- 필수 / 옵션 값을 키 받아서 script 돌리는 식으로 변경
// web-view const webViewKey = { // 필수 값 token: "PAT토큰값", repo: "virtualcare/pasta-webview", baseBranch: "dev", sheetTitle: "[MoneyBall-웹뷰] 전체 번역(Auto)", // 옵션 값 newBranch: "auto-update-branch", prTitle: "feat: 번역 리소스 업데이트(google sheet -> repo)", prBody: "구글 시트의 번역을 업데이트했습니다.", };
- 필수 / 옵션 값을 키 받아서 script 돌리는 식으로 변경
- 다른 파트(IOS, AOS, BE)도 사용 가능한 부분 검토하기
- AOS : 처음부터 XML에 넣음 → 그리고 키값을 가져다 씀 → 나머지는 동일
- 소스코드 스캐너
- FE : i18next-parse
- IOS: bartycrouch
- AOS: 없을리가 없는데…
참고
사례1 :https://www.rldnd.net/react-i18next–
워크플로 전달 이벤트 : https://docs.github.com/ko/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event
배포에 대한 REST API 앤드포인트 : https://docs.github.com/ko/rest/deployments/deployments?apiVersion=2022-11-28
http request : https://blog.nashtechglobal.com/trigger-a-github-action-with-an-http-request/
renovate는 pr만들어줌 : https://docs.renovatebot.com/
github ip 주소 목록 : https://docs.github.com/ko/authentication/keeping-your-account-and-data-secure/about-githubs-ip-addresses
github action IP 주소 목록에 대한 토론 : https://github.com/orgs/community/discussions/26719
github actions ip 주소 : https://github.com/orgs/community/discussions/26719
github ip 주소 목록 : https://api.github.com/meta
구글 IP 주소 : https://support.google.com/a/answer/10026322?hl=en
Version2. 번역 자동화 (with Translation API)
비교
[Translation API](https://cloud.google.com/translate/docs?hl=ko) 알아보기
[AutoML Translation](https://cloud.google.com/translate/automl/docs?hl=ko) 알아보기
결론
AutoML은 성능도 확실하지 않고 투머치임, Translation API로 결정
Translation API + 용어집을 사용해서 초벌을 만들자
번역 초벌 프로세스
0. 새로운 키값 추가되면 en, ja 배경생 노랑색으로 표시
const UPDATE_ROW_BG = "#FFFF00";
function onEdit(e) {
const sheet = e.source.getActiveSheet();
const range = e.range; // 수정된 범위
// 특정 시트만 적용
if (sheet.getName() !== SHEET_TITLE) return;
// 추가된 셀의 배경생 생성
if (range.getColumn() === 2) {
const rowIndex = range.getRow();
// 추가된 키값의 영문, 일어
sheet.getRange(rowIndex, 3).setBackground(UPDATE_ROW_BG);
sheet.getRange(rowIndex, 4).setBackground(UPDATE_ROW_BG);
}
}
1. 시트에 빈값 파싱
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_TITLE);
const data = sheet.getDataRange().getValues();
// 첫 번째 행은 헤더로 처리
const headers = data[0];
// 두번째 행은 title 패스
// 데이터 순회 (첫 번째 행은 헤더이므로 1부터 시작)
for (let i = 2; i < data.length; i++) {
let row = data[i];
let koreanText = row[headers.indexOf(headers[1])]; // 'Text(한글)' 열의 값
let englishText = row[headers.indexOf(headers[2])]; // 'Text(영어)' 열의 값
let japaneseText = row[headers.indexOf(headers[3])]; // 'Text(일어)' 열의 값
if(!koreanText) return
// 빈 값은 번역 요청 후 sheet업데이트
if (!englishText) {
const enValue = translateText(koreanText, 'ko', 'en').replace(/Blood sugar/g, "Glucose Level").replace(/blood sugar/g, "glucose level")
}
if (!japaneseText){
const jaValue = translateText(koreanText, 'ko', 'ja')
}
}
}
2. 해당 값 translation API로 요청
function translateText(text, sourceLanguage, targetLanguage) {
// translation API
const url = `https://translation.googleapis.com/language/translate/v2?key=${API_KEY}`;
const payload = {
q: text,
source: sourceLanguage,
target: targetLanguage,
format: "text",
name: `projects/5${PROJECT_NUMBER}/locations/${LOCATION}/glossaries/${GLOSSARY_ID}`,
};
const options = {
method: "post",
contentType: "application/json",
payload: JSON.stringify(payload),
};
const response = UrlFetchApp.fetch(url, options);
const json = JSON.parse(response.getContentText());
return json.data.translations[0].translatedText;
}
3. 해당 시트에 업데이트
이때 auto Translation 사용했다는 것을 알리기 위해 배경색 파랑색으로 표시
sheet.getRange(i + 1, 4).setValue(jaValue);
sheet.getRange(i + 1, 4).setBackground(AUTO_UPDATE_BG_COLOR);
수정하면 배경색 제거
const UPDATE_ROW_BG = "#FFFF00";
function onEdit(e) {
const sheet = e.source.getActiveSheet();
const range = e.range; // 수정된 범위
// 특정 시트만 적용
if (sheet.getName() !== SHEET_TITLE) return;
// bg가 있는 셀의 변경이 일어나면 배경색을 제거
if (range.getBackground()) {
range.setBackground(null); // 기본 배경색으로 초기화
}
}
4. 번역 완료 되면 모든 셀 배경색 제거
function clearAllCellBackgrounds() {
const sheet =
SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_TITLE);
// 시트 전체 범위 계산
const numRows = sheet.getMaxRows(); // 시트의 총 행 수
const numCols = sheet.getMaxColumns(); // 시트의 총 열 수
console.log(numRows, numCols);
// 행과 열 크기에 맞는 2D 배열 생성 (null로 초기화)
const nullArray = Array.from({ length: numRows }, () =>
Array(numCols).fill(null)
);
// 시트 전체 범위 배경색 초기화
const range = sheet.getRange(1, 1, numRows, numCols); // A1부터 모든 셀 범위
range.setBackgrounds(nullArray);
console.log("모든 셀의 배경색이 제거되었습니다.");
}
만약 용어집을 사용한다면?
Step1. 용어집 만듬
Translation API는 API key 값만으로 요청과 응답을 받을 수 있지만
직접 제작한 파일을 사용하는 용어집은 경우는 API Key만으로는 안되고 OAuth 2.0인증 과정이 있어야 한다 (아….)
→ 그래서 Translation API 관리자 권한이 있는 서비스 계정을 만들어줘야함
Step2. 용어집으로 텍스트 번역
시트 내에서 번역 버튼을 누르면
- 영문, 일어 빈 시트 찾기
- 해당 시트 값들 clund Translation API request 요청
- response값들 해당 시트에 추가
- 추가된 cell 파랑 색깔로 표시
참고
- Gemini: 기존 번역본으로 파인튜닝 후 새로추가된 키값 번역 요청
- translation API : https://cloud.google.com/translate/docs?hl=ko
- 용어집 사용 : https://cloud.google.com/translate/docs/advanced/glossary?hl=ko
- AutoML Translation을통해 학습 후 번역 요청 : https://cloud.google.com/translate/automl/docs?hl=ko
- 두가지 비교 : https://cloud.google.com/translate/automl/docs/beginners-guide?hl=ko
- 커스텀 지원 언어 : https://cloud.google.com/translate/automl/docs/languages?hl=ko
- 한글 → 영어, 영어 → 일본어 로 해야함
- translation API : https://cloud.google.com/translate/docs?hl=ko
- 가격 산정하자
- 학습비용 얼마정도 나올지 체크
- 다른 무료 서비스 API들과 비교
AutoML : https://cloud.google.com/translate/automl/docs?hl=ko
Version3. 라이브러리 화
+ 확장
다른 팀에서도 쓰게 하려면??(IOS, AOS, BE)
크게 두가지 과정이 있다
- 소스코드 → 엑셀
- 소스코드 작성
- 다국어 파일에 추가
- 엑셀 파일에 추가
- 엑셀 → 소스코드
- 번역가 ↔ 개발자 연락
- 엑셀에 번역 추가
- 엑셀 파일로 변경 후 소스코드에 추가
2번은 가능. 1번은 각 언어마다 다름
피드백 반영
- 봇으로 바꿔서 나도 리뷰어에 추가되도록 하기 ⇒ 이거하려면 봇 계정 새로 만들어야 되는데 허가 필요
급한일만 쳐내고… 작업하자…
댓글남기기