Lingo.dev CLI는 설정된 로컬라이제이션 엔진을 통해 Xcode String Catalogs(.xcstrings)를 번역합니다. String Catalogs는 Xcode 15에서 도입된 Apple의 최신 로컬라이제이션 포맷으로, 모든 언어를 하나의 JSON 파일에 저장합니다. CLI는 이 파일을 직접 수정하므로 로캘별 디렉터리를 따로 둘 필요가 없습니다.
이 가이드에서는 iOS 앱 로컬라이제이션을 처음부터 끝까지 다룹니다. CLI 설정부터 로컬 번역, GitHub Actions 자동화까지 살펴보며, 푸시할 때마다 번역이 함께 배포되도록 구성할 수 있습니다.
데모 리포지토리
같이 진행하려면 lingodotdev/ios-app-localization-example를 클론하거나 포크하세요. 이 리포지토리에는 String Catalogs가 포함된 동작 가능한 Xcode 프로젝트, Lingo.dev CLI 설정, 그리고 GitHub Actions 워크플로가 들어 있습니다.
String Catalogs 작동 방식#
Xcode 15 이전에는 iOS 로컬라이제이션을 위해 [locale].lproj/ 디렉터리 전반에 걸쳐 별도의 .strings 및 .stringsdict 파일을 관리해야 했습니다. String Catalogs는 이를 Xcode가 자동으로 관리하는 하나의 Localizable.xcstrings 파일로 대체합니다.
SwiftUI나 UIKit에서 문자열을 로컬라이즈 가능하도록 표시하면, Xcode가 빌드 중 이를 감지해 String Catalog에 항목을 추가합니다. 각 항목에는 원문 문자열, 설정된 각 로캘의 번역, 그리고 번역가에게 맥락을 전달하는 선택적 주석 필드가 포함됩니다.
| 항목 | 기존 .strings | String Catalogs .xcstrings |
|---|---|---|
| 파일 수 | 테이블·로캘별 파일 1개 | 파일 1개에 모든 로캘 포함 |
| 형식 | 키-값 텍스트 | 구조화된 JSON |
| 복수형 지원 | 별도 .stringsdict 파일 | 복수 규칙 내장 |
| Xcode 연동 | 수동 내보내기/가져오기 | 자동 감지 |
| 번역가 메모 | 지원 안 함 | 항목별 주석 필드 |
CLI의 xcode-xcstrings 버킷 타입은 이 JSON 구조를 파싱하고, 각 항목을 로컬라이제이션 엔진으로 번역한 뒤, 주석·복수 규칙·메타데이터를 그대로 유지하면서 같은 파일에 다시 기록합니다.
사전 준비#
로컬라이제이션 엔진 만들기
CLI를 실행할 때마다 모든 콘텐츠는 로컬라이제이션 엔진을 거칩니다. 이 설정은 어떤 LLM 모델과 glossary, 브랜드 보이스, instructions를 적용할지 결정합니다. Lingo.dev dashboard에서 엔진을 만들고 API key를 생성하세요.
Node.js 확인
CLI를 사용하려면 Node.js 18 이상이 필요합니다:
node -vXcode에서 로컬라이제이션 활성화
Xcode 프로젝트에서 Project Settings > Info > Localizations로 이동한 뒤 대상 언어를 추가하세요. Xcode는 추가한 각 로캘에 맞는 String Catalog 항목을 생성합니다. 자세한 내용은 Apple의 localization documentation을 참고하세요.
CLI 설정#
프로젝트 루트에 i18n.json 파일을 만드세요. xcode-xcstrings 버킷은 CLI가 String Catalog 포맷을 파싱하고 파일을 직접 수정하도록 지정합니다:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de", "ja"]
},
"buckets": {
"xcode-xcstrings": {
"include": ["MyApp/Localizable.xcstrings"]
}
}
}String Catalogs는 모든 로캘을 하나의 파일에 저장하므로 include 패턴에는 [locale] 플레이스홀더가 필요하지 않습니다. CLI는 원문 언어 항목을 읽고 번역한 뒤, 모든 대상 언어를 같은 .xcstrings 파일에 다시 기록합니다.
여러 String Catalog 사용하기
프로젝트에서 String Catalog 파일을 여러 개 사용한다면(예: 프레임워크 타깃마다 하나씩), include 배열에 모두 나열하세요:
{
"buckets": {
"xcode-xcstrings": {
"include": [
"MyApp/Localizable.xcstrings",
"MyAppWidgets/Localizable.xcstrings"
]
}
}
}로컬에서 번역하기#
API key를 설정한 뒤 CLI를 실행하세요:
export LINGO_API_KEY="your-api-key"
npx lingo.dev@latest runCLI는 String Catalog를 읽고, lockfile을 기준으로 아직 번역되지 않은 항목을 찾아낸 뒤, 변경분만 로컬라이제이션 엔진으로 번역하고 결과를 같은 .xcstrings 파일에 다시 기록합니다. Xcode에서 파일을 열면 설정된 각 로캘에 번역이 채워진 것을 확인할 수 있습니다.
개발 중 특정 로캘만 대상으로 하려면 다음과 같이 실행하세요:
npx lingo.dev@latest run --target-locale es번역가 메모#
String Catalogs는 항목별 주석 필드를 지원하며, CLI는 이 주석을 번역 요청에 함께 포함합니다. 이런 주석은 로컬라이제이션 엔진에 맥락을 제공해 용어의 의미를 분명히 하고, 톤을 지정하거나, 문자열이 UI의 어디에 표시되는지 설명하는 데 도움이 됩니다.
Xcode에서 String Catalog 편집기에서 문자열을 선택한 뒤 검사기 패널에 주석을 추가하세요. 이 주석은 .xcstrings JSON에 저장됩니다:
{
"sourceLanguage": "en",
"strings": {
"Set": {
"comment": "Refers to a collection of items, not the verb",
"localizations": { }
}
}
}CLI는 이 주석을 문자열과 함께 전송해 모델이 올바르게 해석하도록 유도합니다. 예를 들어 맥락 없이 "Set"만 있으면 많은 언어에서 동사로 번역될 수 있지만, 주석이 있으면 이런 모호함을 없앨 수 있습니다. 더 많은 패턴은 Translator Notes를 참고하세요.
복수형#
String Catalogs는 CLDR plural rules를 사용해 복수형을 기본으로 처리합니다. Xcode에서 복수형 변형을 정의하면 String Catalog는 대상 언어에 필요한 각 복수 범주(zero, one, two, few, many, other)에 대한 규칙을 저장합니다.
CLI는 번역 과정에서도 이 구조를 유지하고 각 대상 로캘에 맞는 올바른 복수 범주를 생성합니다. 영어는 두 가지 범주(one 및 other)만 사용하지만, 아랍어는 여섯 가지, 폴란드어는 네 가지, 일본어는 한 가지만 필요합니다. 로컬라이제이션 엔진이 이런 차이를 자동으로 처리합니다.
GitHub Actions로 자동화하기#
푸시할 때마다 번역이 실행되도록 .github/workflows/translate.yml에 워크플로 파일을 추가하세요:
번역 결과를 main에 바로 커밋합니다. 마찰이 거의 없어 소규모 팀에 특히 적합합니다:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lingo.dev
uses: lingodotdev/lingo.dev@main
with:
api-key: ${{ secrets.LINGODOTDEV_API_KEY }}GitHub 리포지토리의 Settings > Secrets and variables > Actions에서 API key를 LINGODOTDEV_API_KEY로 저장하세요.
배포 전 검증#
번역되지 않은 문자열이 프로덕션에 배포되지 않도록 --frozen 플래그를 배포 게이트로 사용하세요. 번역이 필요한 항목이 하나라도 있으면 CLI는 0이 아닌 상태 코드로 종료합니다:
npx lingo.dev@latest run --frozen빌드 전에 별도의 CI 단계로 추가하세요:
- name: Verify translations
run: npx lingo.dev@latest run --frozen