우리가 다국어 처리가 있었어..?(번역 자동화)

발표자료 완성!: 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

  1. 소스코드에 t({‘한글’}) 을 입력
  2. commit 시 public/locales 각각에 추가 자동화(git precommit hook   i18next-scanner 이용)
  3. public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (google-spreadsheet 이용해 upload 스크립트 작성)
  4. 번역 요청 (dev 배포 전 / 후 ??)
  5. build 시 public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (google-spreadsheet 이용)

User Flow

  1. t({‘한글’}) 이런식으로 작업 (소스코드 내에서 원래 하던대로 작업)
  2. 번역 요청
  3. 번역 완료 되면 push(stg배포)

장점

  1. 아름다운 DX (json 입력, 구글시트 입력, 구글시트 동기화 필요X)
  2. 번역과 비동기적 작업 가능 (번역 완료 여부와 상관없이 개발 가능)

단점

  1. 번역과 비동기적 작업 가능 (번역이 완료된 줄 알고 prd 올렸는데 번역이 안되었을 수 있음 - 휴면에러 조심!)
  2. 변수 처리 어떻게 할지 리서치 필요
  3. 라이브러리 의존도 상승 (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

  1. 소스코드에 t({‘한글’}) 을 입력
  2. commit 시 public/locales 각각에 추가 자동화(git precommit hook   i18next-scanner 이용)
  3. public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (google-spreadsheet 이용해 upload 스크립트 작성)
  4. 번역 요청 (dev 배포 전 / 후 ??)
  5. build 시 public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (google-spreadsheet 이용)

User Flow

현재 : 한글을 작성함 → 소스 코드에 작성 → 엑셀로 옮김 → 요청 → 엑셀채움 → 소스코드로 옮김 (수동)

  1. t({‘한글’}) 이런식으로 작업 (소스코드 내에서 원래 하던대로 작업)

    ⇒ push 시 스캔해서 json파일 만듬

    ⇒ 구글 시트에 업로드

2.

  1. 번역 완료 되면 push

Process3 → X

  1. 소스코드에 t({‘한글’}) 을 입력
  2. commit 시 public/locales 각각에 추가 자동화(git precommit hook   i18next-scanner 이용)
  3. public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (google-spreadsheet 이용해 upload 스크립트 작성)
  4. build 시 public/locales의 키값을 구글 스프레드 시트에 업로드 자동화 (google-spreadsheet 이용)

구글 시트 내에 github action을 트리거하는 스크립트 작성 ⇒ 스크립트 실행 버튼 클릭 ⇒ stg 배포

(번역 요청 후 기다리고 배포 하는 과정을 번역쪽에 위임)

피드백 ⇒ PR로 올릴 수 있으면 좋을 듯 / ⇒ vpn에서 걸릴 . 수있음 github 접근 자체가 안딤

PR을 올린다? → 우리가 Merge를 해줘야함

번역쪽에서 빌드한다? → 우리 작업 시 merge가 필요하다

충돌은? →json에서만 난다 ⇒ 그럼 굳이 검사가 필요한가?

거스 승인 떨어졌다!!! pr말고 deploy하는걸로!!

아아아…안돼…

Untitled

GitHub Actions 실행의 IP 주소가 허용 목록에 포함되어있어야 한다고 한다..

아아아나후아일누이아아아,,,,,,,,

어??

Untitled

ㄱㄴ????????

헠헠헠헠허컿커허

Untitled

내일 거스께 열어달라고 하잫ㅎㅎㅎㅎㅎ흫히ㅣ히히힣

아 잠만… 여기 ip는 구글 서버ip잖아… 동적으로 변경되는걸 대응안되지…

그러다면?

중간에 번역을 위한 레포를 하나 파서

여기는 접근 가능하게 하고

번역 레포에서 조직 레포로 트리거 보낸다면?

깃헙 액션 ip는 동적으로 변하긴하지만 그 범위가 정해져있다

Untitled

그리고 일주일에 한 번 업데이트 된다

또한 이값을 자동으로 불러오는 방법이 있긴 하다

⇒ 스텍오버프로워의 github action ip white list 등록 방법

https://stackoverflow.com/questions/68011051/how-do-i-whitelist-github-actions-ip-addresses-in-azure-web-app-using-githubs-a

⇒ 깃헙 커뮤니티의 등록 방법

https://github.com/orgs/community/discussions/26884

그렇다면 이론적으로는 가능하지 않음??

시트 → (ip 열어둠) → 번역레포 → (github action ip목록만 whitelist에 추가함)→ 조직레포

⇒ 근데 조직 레포 자체가 vpn 타야돼서 조직내에 만드는 것은 안돼…ㅜ

⇒ 할려면 번역레포를 개인레포로 만들고 개인 레포에서 조직 레포로 트리거 보내야 되는데… 이걸 인프라 팀이 승인 해줄까..?

99.9% 혼날듯,,

아니면 개인레포에 서버 하나 띄워서 JWT로 인증과정 거치고 트리거 보낸다면??

보안적 이슈는?

조직레포에 접근 가능한 구멍이 생긴다

⇒ 이게 구멍이 맞나?

⇒ 트리거의 역할은 하지만 어떤 엑션이 돌게는 못한다

⇒ 그럼 괜찮지 않음??

가능한 이슈는 트리거를 겁나 많이보내는 이슈 생길 수 있음

⇒ 어케 막을까…

⇒ 중간 레포에서 타이머 같은 거 설정해서 특정 시간 동안 한번만 실행되게 하면 되지 않나?

라는 망상해봤습니다.


결론 → Process 1 채택 thank you gus!

프로세스 개선

현재 프로세스

  1. 개발 시 한글을 작성함
  2. 소스 코드에 작성
  3. 구글 시트로 옮김
  4. 번역가에게 번역요청
  5. 번역가가 구글 시트채움
  6. 개발자에게 연락
  7. 개발자가 소스코드로 옮김
  8. 개발자가 PR 작성해서 merge함

자동화 프로세스

  1. 개발 시 한글을 작성함
  2. 소스 코드에 작성 → Push시 소스코드 스캔해서 json 업데이트
  3. 구글 시트로 옮김 → Dev PR 머지 시 구글 시트 업데이트
  4. 번역가에게 번역요청
  5. (번역가께서 번역이 필요한 시점에 알아서)구글 시트 채움
  6. 개발자에게 연락 → 시트버튼 클릭(PR 생성)
  7. 개발자가 소스코드로 옮김
  8. 개발자가 PR 작성해서 merge함 → 올라온 PR을 보고 머지함

과정

Step1. 소스코드 스캔 ⇒ 완.

TODO

  • 소스코드를 스캔해서 t(‘‘)로 다국어 처리한 부분을 파싱 → 각각 public/locales/{lng}/common.json 으로 변환

기존에 있는 키에 대한 value

  • 패스

기존에 없는 키에 대한 value

  • 키값을 value에 추가
  • 스캔 시 변수 처리 확정 지을 것 (논의) =:> 변수에 사용 가능여부
    • 결론
      • json ⇒ "에게 답글 달기": "에게 답글 달기",
      • 사용 시 ⇒ {t('에게 답글 달기', { nickname })}

기존에 있는 키 삭제했을 경우

  • common_old.json에 모아놓음
    • 시트 업데이트 시 해당 키값들의 row는 제거
      • 왜냐하면 스캔뜰때마다 해당 키값들은 제거되어 업로드 될 것이고, 시트에서 PR을 만들면 다시 해당 키값들이 포함되서 머지될꺼임 ⇒ 이런 문제 싱크를 맞춰주기 위해서임
    • key, value의 관리 주체가 key : 개발자가 관리 (키는 우리가 만들어요) vlaue: 번역가가 관리 (번역본은 번역가님 따를게요) 로 생각을 했음

라이브러리 선정i18next-parser VS i18next-scanner

image.png

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로직 수정

준비

  1. 구글 시트에 접근 가능한 서비스 계정 생성(from. Google Cloud Console)
  2. 서비스 계정에 sheet API 권한 추가
  3. 서비스 계정 인증키 발급
  4. 해당 구글 시트에 서비스 계정 권한 추가
  • 이게 무슨 의미가 있냐..? 인줄 알았는데
    1. 서비스 계정을 만든다는 것은 그냥 ‘가상의 구글 계정’ 하나 더 만드는 것
    2. 서비스 계정 token으로 인증을 ⇒ 로그인
    3. 구글 시트 업데이트 하기 위해서는 서비스 계정에 엑세스 권한 + 편집 권한 이 있어야 함
    4. 권한 인증 이후 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

  • 이미 브랜치가 생성 되었을 경우 예외처리
    1. 한번에 하나의 PR만 생성 가능하게 할 것인가? ⇒ 그러면 그냥 alert에 기다리라고 띄우면 끝
    2. 여러개 PR 생성 가능하면? ⇒ auto-update-branch-1, auto-update-branch-2 이런식으로 브랜치만들기
    3. 하나의 PR에서 commit으로 추가되는 형식?
    4. 브랜치을 없애고 새롭게 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개의 권한이 필요하다 image.png

동작 흐름이

  1. ‘번역 완료’ 버튼을 누르면 스크립트가 실행됨
  2. 구글 시트를 json 형태로 만듬
  3. 현재 dev의 가장 최근 commit을기준(SHA로 가져옴)으로 새로운 branch를 생성
    1. 기존에 branch가 있으면 삭제 후 다시 만듬
  4. 생성된 브랜치에서 public/locales/{lngs}/common.json 데이터들을 가져옴
  5. 2번에서 만든 JSON은 인코딩해서 public/locales/{lng}/common.json 에 업데이트함
  6. 해당 변경사항들을 commit함
  7. PR을 생성함

이렇게 PR이 생성되었음

이제

  1. 흐뭇한 미소를지으며 해당 repo에 들어감
  2. 머지를 해줌

참고 : https://docs.github.com/ko/enterprise-cloud@latest/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens

image.png

«주의»

  1. github에 시크릿 키 넣을 때 “” 빼야함
  2. 구글 시트의 1번째 row가 헤더가 됨… 무조건,,,

    1. 1번째 row 헤더
    2. 2번째 row title로 잡음

      ⇒ 그래서 upload.js / apps script 에 헤더 처리 따로 해줌

  3. T() 안에 삼항연산자 넣으면 인식 못함 t( check ? ‘A’ : ‘B’) ⇒ check ? t(‘A’):t(‘B’) 이렇게 해야함

PR description

image.png

전체적인 플로우는 위와 같습니다!

다국어 처리 시 키값에서 변수를 부분으로 감싸고 나머지는 동일합니다.

{
  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로 만들었지만 이렇게 업데이트하면 번역 시 빈 값을 찾기 어려울 것 같아 수정했습니다.
        • 아래 사진처럼 빈값은 색깔을 다르게 줘 찾기 편해졌습니다. image.png
  • 번역 PR 생성 시
    • 빈 값이 있으면 생성을 못하도록 막음

변경 후 다국어 처리의 프로세스는

개발 시에는

  1. 개발할 때 변수는 로 키값 생성

외에는 따로 처리할건 없습니다.

번역 후 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: "구글 시트의 번역을 업데이트했습니다.",
      };
      
  • 다른 파트(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/

조직에 허용되는 IP 주소 관리 : https://docs.github.com/ko/enterprise-cloud@latest/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/managing-allowed-ip-addresses-for-your-organization

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. 용어집으로 텍스트 번역

시트 내에서 번역 버튼을 누르면

  1. 영문, 일어 빈 시트 찾기
  2. 해당 시트 값들 clund Translation API request 요청
  3. response값들 해당 시트에 추가
  4. 추가된 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
    • 한글 → 영어, 영어 → 일본어 로 해야함
  • 가격 산정하자
    • 학습비용 얼마정도 나올지 체크
    • 다른 무료 서비스 API들과 비교

AutoML : https://cloud.google.com/translate/automl/docs?hl=ko

Version3. 라이브러리 화

+ 확장

다른 팀에서도 쓰게 하려면??(IOS, AOS, BE)

크게 두가지 과정이 있다

  1. 소스코드 → 엑셀
    • 소스코드 작성
    • 다국어 파일에 추가
    • 엑셀 파일에 추가
  2. 엑셀 → 소스코드
    • 번역가 ↔ 개발자 연락
    • 엑셀에 번역 추가
    • 엑셀 파일로 변경 후 소스코드에 추가

2번은 가능. 1번은 각 언어마다 다름

피드백 반영

  • 봇으로 바꿔서 나도 리뷰어에 추가되도록 하기 ⇒ 이거하려면 봇 계정 새로 만들어야 되는데 허가 필요

급한일만 쳐내고… 작업하자…


번역 개선 공유 자료(개발자)

번역 개선 공유 자료(번역가)

댓글남기기