Lingo.dev CLI는 설정된 로컬라이제이션 엔진을 통해 Android strings.xml문자열 리소스()를 번역합니다. android 형식에서는 CLI가 <resources>, <string>, <string-array>, <plurals> 요소를 기본 지원하므로 XML 구조를 그대로 유지하면서 각 대상 로캘에 맞는 올바른 복수형 카테고리를 생성합니다.
이 가이드는 Android 앱을 처음부터 끝까지 로컬라이즈하는 전 과정을 안내합니다. CLI 설정부터 로컬 번역, 그리고 푸시할 때마다 번역이 반영되도록 CI에서 자동화하는 방법까지 모두 다룹니다.
데모 저장소
함께 진행하려면 lingodotdev/android-app-localization-example을 clone하거나 fork하세요. 이 저장소에는 문자열 리소스가 포함된 실행 가능한 Android 프로젝트와 Lingo.dev CLI 설정, 그리고 각 대상 로캘별 번역 커밋이 모두 들어 있습니다.
Android 로컬라이제이션 작동 방식#
Android는 각 로캘마다 전용 디렉터리를 사용하는 values-[locale]/리소스 디렉터리 규칙을 따릅니다. 시스템은 기기의 언어 설정에 따라 런타임에 올바른 strings.xml를 로드합니다.
app/src/main/res/
values/ # Default (source) strings
strings.xml
values-es/ # Spanish
strings.xml
values-fr/ # French
strings.xml
values-ja/ # Japanese
strings.xml일반적인 strings.xml에는 세 가지 요소 유형이 있습니다:
<resources>
<!-- Simple strings -->
<string name="app_name">My App</string>
<string name="welcome_message">Welcome back!</string>
<!-- String arrays -->
<string-array name="planets">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
</string-array>
<!-- Plurals -->
<plurals name="items_count">
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
</plurals>
</resources>CLI는 이 세 가지 요소 유형을 모두 파싱하고, 로컬라이제이션 엔진을 통해 내용을 번역한 다음, 로캘별 파일을 올바른 values-[locale]/ 디렉터리에 기록합니다.
사전 준비#
로컬라이제이션 엔진 만들기
CLI를 실행할 때마다 콘텐츠는 로컬라이제이션 엔진을 거칩니다. 어떤 LLM 모델, glossary, 브랜드 보이스, rules를 적용할지 정하는 설정이죠. Lingo.dev dashboard에서 새로 만들어 보세요.
Node.js 확인
CLI를 사용하려면 Node.js 22 이상이 필요합니다:
node -vCLI 설치
CLI를 전역 설치하면 lingo 명령을 사용할 수 있습니다:
npm install -g @lingo.dev/cliAndroid 프로젝트 준비
프로젝트에는 strings.xml 안에 기본 app/src/main/res/values/ 파일이 있어야 합니다. Android Studio는 새 프로젝트를 만들 때 이 파일을 자동으로 생성합니다. 리소스 디렉터리 설정은 Android의 localization guide를 참고하세요.
CLI 설정#
프로젝트 루트에서 lingo init를 실행해 소스 및 대상 로캘, 파일 패턴이 포함된 .lingo/config.json를 생성한 다음, lingo link를 실행해 조직과 엔진을 연결하세요. 결과는 다음과 같습니다:
{
"orgId": "org_...",
"engineId": "eng_...",
"sourceLocale": "en",
"targetLocales": ["es", "fr", "de", "ja"],
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
}
]
}이 패턴은 기본 리소스 디렉터리, 즉 한정자 없는 values/를 가리킵니다. 바로 Android가 소스 문자열을 기대하는 위치죠. 여기에는 로캘 코드가 없고, 있을 필요도 없습니다.
`format`을 명시적으로 설정하는 이유
CLI는 대부분의 형식을 파일 확장자로 자동 감지하지만, .xml는 모호하기 때문에 Android 리소스 파일은 files 항목에 "format": "android"를 명시적으로 지정해야 합니다.
여러 리소스 파일
프로젝트에서 문자열을 여러 파일(예: strings.xml 및 arrays.xml)로 나눠 관리한다면, 각 파일마다 files 항목을 추가하세요:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
},
{
"pattern": "app/src/main/res/values/arrays.xml",
"format": "android"
}
]
}.lingo/config.json를 저장소에 커밋하세요.
로캘 디렉터리와 한정자#
Android는 기본 언어를 한정자 없는 values/ 디렉터리에 두기 때문에 소스 경로에는 로캘 코드가 들어가지 않습니다. CLI도 이 규칙을 이해합니다. 한정자 없는 values/는 소스 로캘로 처리하고, 다른 모든 로캘에는 대상 한정자를 붙입니다.
| 로캘 | 리소스 디렉터리 |
|---|---|
en (소스) | values/ |
es | values-es/ |
pt-BR | values-pt-rBR/ |
zh-Hans | values-b+zh+Hans/ |
여기서는 지역 및 스크립트 로캘을 이해해 두는 것이 중요합니다. 리소스 한정자는 BCP 47 태그를 그대로 쓰는 방식이 아니기 때문입니다. Android는 두 가지 표기를 지원합니다. 레거시 언어-지역 형식(values-pt-rBR/)과, b+ 접두사가 붙는 BCP 47 형식(values-b+pt+BR/, API 24 이상)입니다. 디렉터리 이름을 values-pt-BR/로 지정하면 아예 무시되므로, 문자열이 있어도 절대 로드되지 않습니다.
"format": "android"를 설정해 두면 CLI가 알맞은 표기를 자동으로 생성합니다. 로캘을 표현할 수 있는 경우에는 레거시 형식을, 스크립트·세 글자 언어·숫자 지역에는 b+를 사용합니다.
이전 설정에서 업그레이드하는 경우
이전 CLI 버전에서는 소스 경로에 로캘이 포함되어야 했고, 이 가이드도 두 방식을 연결하기 위해 values-en -> values 심볼릭 링크를 권장했습니다. 하지만 @lingo.dev/cli 1.12.0부터는 더 이상 필요하지 않습니다. 패턴을 values/strings.xml로 지정하고 심볼릭 링크는 삭제하세요.
로컬에서 번역하기#
CLI를 실행하세요. 첫 실행이거나 새 대상 로캘을 추가한 경우에는 기존의 모든 문자열이 번역되도록 --backfill-missing를 사용하세요:
lingo push --backfill-missingCLI는 소스 strings.xml를 읽고 run state를 기준으로 번역되지 않은 항목을 식별한 뒤, 변경분만 로컬라이제이션 엔진으로 번역해 대상 values-[locale]/ 디렉터리에 기록합니다. 번역된 문자열을 확인하려면 대상 파일을 하나 열어보세요.
그다음부터는 lingo push가 변경된 내용만 번역합니다:
lingo push실행 범위를 특정 파일로 한정하려면 glob를 넘기면 됩니다. 패턴은 소스 경로를 기준으로 매칭되므로, 대상이 아니라 소스 파일 기준으로 범위를 지정하세요.
lingo push "app/src/main/res/values/strings.xml"다른 곳(예: CI)에서 생성된 번역을 작업 트리로 가져오려면 lingo pull를 실행하세요.
복수형#
Android는 복수형 처리를 위해 <plurals> 요소와 CLDR quantity strings(zero, one, two, few, many, other)를 사용합니다. 언어마다 필요한 복수 범주는 다릅니다. 영어는 두 개(one, other)가 필요하고, 러시아어는 네 개, 아랍어는 여섯 개가 필요합니다.
CLI는 번역 중에도 <plurals> 구조를 유지하고 각 대상 로캘에 맞는 올바른 수량 항목을 생성합니다. 예를 들어 두 개 범주를 가진 소스 항목이 있으면:
<plurals name="messages_count">
<item quantity="one">%d new message</item>
<item quantity="other">%d new messages</item>
</plurals>각 대상 언어에 맞는 올바른 범주가 생성됩니다. 로컬라이제이션 엔진은 각 로캘에 어떤 CLDR plural rules가 적용되는지 알고 있으며, 해당 언어에 필요한 범주만 생성합니다.
키 잠금#
브랜드명, API 엔드포인트, 형식 패턴처럼 모든 언어에서 동일하게 유지해야 하는 문자열 값도 있습니다. 이런 경우 키 잠금을 사용해 번역 없이 그대로 복사하세요:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android",
"lockedKeys": ["app_name", "api_base_url"]
}
]
}잠긴 키는 번역 파이프라인을 거치지 않고 소스에서 모든 대상 파일로 그대로 복사됩니다.
CI에서 자동화하기#
번역을 항상 최신 상태로 유지하는 가장 권장되는 방법은 Lingo.dev GitHub App입니다. 서버 측에서 실행되며, 커밋된 .lingo/config.json와 engineId를 읽어 번역 업데이트를 자동으로 생성합니다. 러너도, 저장된 시크릿도, 별도의 lockfile 관리도 필요 없습니다. 설치한 뒤 저장소에 연결하면 푸시할 때마다 번역이 자동으로 이루어집니다.
CLI를 자체 파이프라인 안에서 실행하고 싶다면, CLI를 설치한 뒤 lingo push를 실행하는 워크플로를 추가하세요:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install -g @lingo.dev/cli
- run: lingo push --backfill-missing
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}GitHub 저장소의 Settings > Secrets and variables > Actions에서 API 키를 LINGO_API_KEY로 저장한 다음, 후속 단계에서 업데이트된 대상 파일을 커밋하거나 pull request를 여세요.
배포 전 검증#
번역되지 않은 문자열이 프로덕션에 배포되지 않도록 lingo check를 배포 게이트로 활용하세요. 번역이 필요한 항목이 하나라도 있으면 이 명령은 0이 아닌 상태 코드로 종료됩니다:
lingo check빌드 전에 별도의 CI 단계로 추가하세요:
- name: Verify translations
run: lingo check
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}