최근 스레드를 통해 정말 많은 자극을 받고 있는 딜라이트룸 iOS 개발자 리디님. 다양한 개발 스토리를 들으면서 나도 나중에 내실 있는 나만의 앱을 만들고 싶다는 꿈이 점점 커지고 있다. 이 글에서는 리디님이 연사로서 SwiftRise 컨퍼런스에서도 소개해주셨고 내 프로젝트에도 적용해 볼 만한 것이어서 공부해 보면서 구현했던 부분을 공유해보려 한다.
사실 컨퍼런스에서는 도입한 도구나 구체적 구현 방법을 자세히 설명해 주셨다기보다 왜 이런 자동화 시스템을 구축했었어야 했는지에 대해 사고의 변화와 점진적인 디벨롭 과정에 대해 충분히 납득할 수 있게 설명해 주셔서 더 기억에 남았던 듯싶다! 결과적으로 우리는 iOS 개발자이기 이전에 product developer이기에 이런 자동화 도구나 AI를 잘 활용해서 제품을 만들어내자는 게 요점이었지만 간만에 적용해보고 싶어서 설레는 파트였어서 리디님의 미디엄 게시글을 읽으면서 구현해 보았다.
다국어 작업은 개발자의 노동이 들어갈 수밖에 없지 않나라고 생각했던 생각했던나였지만, 역시 다년의 경력이 있으신 현업자의 인사이트는 다르다고 느꼈다.
https://medium.com/delightroom/이번-작업은-다국어로-하겠습니다-5d8a42fa0746
97개국 32개 언어를 손쉽게 배포하는 방법
이번 작업은 ‘다국어’로 하겠습니다. 근데 이제 ‘귀찮음’ 을 덜어낸..
medium.com
📍String Catalog
내가 기존에 사용하고 있었던 다국어 관리 방법은 iOS16 버전부터 사용할 수 있는 String Catalog였다.
그래도 Apple 이 호기롭게 내놓은 다국어 리소스 관리 방법이기 때문에 .strings 파일을 사용하여 각 언어별로 키-값 쌍으로 관리했을 때 보다는 확실히 직관적이고 관리도 용이하다는 장점이 있긴 했다.
- 다만, 낮은 iOS 버전에서는 사용할 수 없다는 한계가 있고,
- value에 잘못 문자열을 넣을 때나 key를 사용할 때 여전히 휴먼 에러의 발생 가능성이 높으며,
- 그리고 회사라면 더더욱 개발자가 아닌 기획자 또는 별도 팀에서 다국어 관리를 할 가능성이 높은데 단어 하나를 추가/수정한다고 해도 어떤 언어인지/어떤 키값을 가지는지 등을 별도로 소통해야 하기 때문에 아주 비효율적인 방법일 수 있다.
휴먼에러의 발생 가능성을 줄이고 효율적으로 다국어 자원을 관리할 수 있는 도구부터 살펴보자.
📍Lokalise
이번 기회를 통해 Lokalise라는 서비스를 처음 알게 되었는데, 클라우드 기반 Localization 플랫폼이고 다국어 리소스를 생성하고 관리할 수 있다.
A Localization and Translation Software Tool | Lokalise
Find out how Lokalise can help you automate your workflow and make the localization process easier!
lokalise.com
나는 기존에 string catalog로 다국어 key-value를 관리하고 있었기 때문에 이 데이터를 Lokalise에 마이그레이션 해줄 필요가 있었다. Lokalise에서는 .strings 등 다양한 파일 형식으로 기존의 데이터들을 업데이트할 수 있는데, 나는 .strings 파일 형식으로 작업하지도 않았기 때문에 chat gpt에 string catalog의 소스코드를 넣어서 .strings 파일의 코드 형태로 변환해 달라고 요청한 다음 수동으로 데이터 넣어주었다. 역시 다 해주는 나의 비서 chat gpt ;)
이렇게 직접 넣어주지 않아도 회사에서 일하는 경우 엑셀 파일 같은 걸로 관리되고 있을 수 있으니 그런 걸 넣을 수도 있다.
등록을 완료하면 여러 개의 key들에 대한 다국어 등록이 완료될 것이고 특정 프로젝트나 특정 언어의 다국어 처리 완료율 확인할 수 있다.
이렇게 다국어를 관리했다면 실제 프로젝트에 반영해야 한다. Lokalise에서는 나의 GitHub 레포지토리를 등록해서 소스를 가져올 수 있는데, Apps 탭에서 프로젝트의 GitHub 레포지토리에 대해 등록하고, Download 탭에서 리소스를 다운로드할 레포지토리 선택하고 다운받으면 내가 작업한 다국어 리소스들이 .strings 파일로 예쁘게 변환되어 해당 레포지토리에 PR을 만들어준다.
근데! 이렇게 관리해 준다면 어떤 문제가 있을까?
실제로 진행 중인 프로젝트 레포에 PR이 올라가고 이 코드가 develop 브랜치나 특정 브랜치에 업데이트가 된다면 이 다국어 리소스 업데이트를 반영하고 싶은 각 개발자들이 본인이 작업하고 있는 각 브랜치에 반영하기 위해서는 rebase를 하는 등 동기화하는 작업에 대한 리소스가 많이 들어간다. (( 리디님의 블로그로 보고 간접체험.. ㅎㅎ)) 나는 개인 프로젝트에 적용하는 것이기 때문에 그리 큰 리소스는 아니겠지만 협업이나 회사 환경이라고 생각해 보니 개선의 필요성이 충분하다는 것을 느꼈다.
이럴 때 GitHub Submodule라는 개념을 결합해 볼 수가 있다.
📍Git Submodule
Git의 Submodule은 하나의 Git 리포지토리 안에 다른 Git 리포지토리를 포함할 수 있도록 하는 기능이다. 현재 프로젝트 내부에서 다른 독립적인 Git 레포지토리를 서브디렉토리로 추가할 수 있는 것이다. 즉, localization에 대한 레포지토리를 프로젝트의 submodule로 따로 관리할 수 있는 것!
Submodule을 사용하면서 느낀 점은 다국어 관리하는 레포지토리와 실제 프로젝트 레포지토리를 따로 관리할 수 있어서 다국어 리소스의 버전 관리가 명확하다는 점이다. 그리고 나는 개인 프로젝트에 적용했지만 협업을 가정했을 경우에도 각 feature 브랜치에서 최신 localization을 반영하기 위한 리소스가 훨씬 적게 들 수 있겠다는 생각을 했다.
나는 프로젝트 메인 레포지토리에서 develop branch는 언제나 다국어를 관리하는 레포지토리의 최신 commit address를 바라보게 하였고 특정 피쳐 브랜치들은 필요에 따라 서브모듈의 특정 커밋 주소를 바라볼 수 있게 하였다.
▶️ Submodule 추가
github에서 다국어를 관리해 줄 submodule git repository 만들고 → 터미널로 프로젝트에 서브모듈을 추가해 줄 수 있다.
git submodule add https://github.com/yyeonjju/KoCo-Localize.git LocalizationSubmodule
그럼 이런 식으로 서브모듈이 생긴다
그리고 나서 push 해보면, main repository에서는 이렇게 서브모율의 특정 커밋해시를 바라보고 있는 것을 확인할 수 있다.
▶️ Lokalise에 App 등록
Lokalise의 App 탭에서 서브모듈 깃헙 레포지토리를 등록! → 레포의 특정 브랜치에 대한 정보를 Lokalise에서 pull 해주면 Lokalise에서 작업한 리소스들 다운로드 받을 준비 끝!
▶️ 리소스 다운로드
다운로드 탭에서 → build and download → 깃헙에 PR 올라옴
다운로드 탭에서도 File structure / Content to export 등을 어떻게 할 건지에 대한 항목이 있고 등록해 놓은 각 key 별로 파일 이름, tag 등을 어떻게 설정해 놓았느냐에 따라 다운받을 리소스들을 다양하게 조절할 수 있으므로 이것저것 만져보며 익숙해지는 것을 추천!
Lokalise에서 다국어 리소스를 다운로드 하면 서브모듈 레포지토리에 PR이 생기게 된다.
이렇게 다국어를 submodule을 사용하는 방향으로 바꾸었으니 SwiftGen과 같은 도구를 사용해서 type-safe한 코드로 변환하려면 이런 실행코드들도 메인 프로젝트 레포지토리가 아닌 서브모듈 레포지토리에서 관리해줘야 할 것이다.
→ 그래서 하게 된 게 Git Actions로 이 과정을 자동화하는 것!
→ PR 생성된걸 트리거로해서 SwiftGen를 사용한 변환 과정을 자동화해보도록 하자!
📍 GitHub Actions
위에서 말한 대로 Lokalise를 통해 PR이 만들어졌을 때, 이것을 트리거로 SwiftGen이라는 도구를 사용해서 다국어 코드를 보다 선언적으로 사용할 수 있도록 만드는 과정을 Actions로 자동화시키고자 했다.
SwiftGen에 대한 사용기는 이전에 썼던 글이 있으므로 참고!
https://heidi-dev.tistory.com/38
▶️ Workflow 스크립트
서브모듈 레포지토리의 워크플로우 .yml 파일은 이런 식으로 작성했다.
간단하게만 설명하자면 Lokalise에서 리소스 다운로드하는 과정에서 서브모듈에 PR이 생성되었을 때 1️⃣ PR 이 오픈된걸 트리거로 하여 워크플로우를 실행하게 되고 -> 2️⃣ Lokalise에서 만든 브랜치로부터 만들어진 PR일 경우(브랜치 이름이 'lokalise'로 시작할 경우) SwiftGen을 설치하고 -> 3️⃣ 내가 서브모듈 내 작성해놓은 swiftGen 관련 .yml 파일을 실행해서 다국어 리소스 (.strings 파일)을 사용하기 편리하게 코드로 변환시킨다. -> 4️⃣ 그리고 이 작업에 대해 커밋을 남긴다
on:
pull_request_target:
types:
- opened
permissions: write-all
jobs:
localization:
if: startsWith(github.head_ref, 'lokalise')
runs-on: macos-latest
steps:
- name: Check out lokalise branch
uses: actions/checkout@v3
with:
ref: ${{ github.head_ref }}
# 현재 체크아웃된 브랜치 출력
- name: Print current branch
run: git branch --show-current
# git pull origin을 실행하여 최신 코드를 가져옴
- name: Pull
run: |
git pull origin
# homebrew 설치되어 있는지 확인하고 설치
- name: Install Homebrew
run: |
echo "Checking Homebrew..."
if ! command -v brew &> /dev/null; then
echo "Installing Homebrew..."
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
else
echo "Homebrew already installed."
fi
# swiftgen 설치
- name: Install SwiftGen
run: |
brew install swiftgen
# yml 파일 실행
- name: Run SwiftGen
run: |
swiftgen config run --config swiftgen.yml
#변경 사항을 자동으로 커밋하고 푸시
- name: commit and push
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: "[Success] complete localization build"
▶️ Workflow 실행 완료
그럼 이제 Lokalise로부터 PR이 생성되면 Workflow가 실행되는 것을 확인할 수 있고, Actions 탭에서 성공적으로 스크립트 실행이 완료되는 것도 확인할 수 있다.
이렇게 까지 하고 나서는?
서브모듈 레포지토리에서는 이렇게 작업된 걸 머지해서 PR을 닫고 → 메인 레포지토리에서는 develop 브랜치에서 서브모듈을 최신화시켜주면 된다. 근데, 이것 또한 사람 손이 닿는 귀찮은 작업.. 서브모듈 레포지토리에서 자동으로 PR의 base branch에 머지하고, 메인 레포지토리에서는 서브모듈이 최신화되는 작업도 모두 자동화할 순 없을까??
있다. ;)
특정 검증 이후 머지해서 PR을 닫고, 메인 레포지토리에서 서브모듈을 최신화하하는 건 다음 글에서 이어서 작성하겠습니닷
'iOS' 카테고리의 다른 글
Github Actions를 통한 다국어 자동화 (2) | Submodule 최신화, Slack Webhook (2) | 2025.02.24 |
---|---|
ETag 기반 이미지 캐싱 & instruments로 로딩 속도 분석 |OSLog, os_signpost (0) | 2025.01.13 |
[iOS] App Thinning 앱 씨닝과 Slicing, On-Demand Resource, Bitcode (4) | 2024.06.08 |
[iOS] image asset의 크기 1x ,2x, 3x 사용하는 이유 | scale factor, 해상도(Resolution), pixel, point (0) | 2024.05.22 |
[iOS] 앱의 시작지점 @main (1) | 2024.02.11 |