
Android 앱 현지화 완벽 가이드
strings.xml부터 Play Store 메타데이터까지, Kotlin, Jetpack Compose, Fastlane, AI 자동 번역으로 Android 앱을 현지화하는 방법을 알아보세요.
현지화를 위한 Android 프로젝트 설정
Android는 폴더 기반 규칙으로 현지화를 처리해요. 기본 문자열은 res/values/strings.xml에 두고, 번역된 문자열은 res/values-de/, res/values-ja/ 같은 로케일별 폴더에 넣어요.
// Android project structure for localization:
// res/
// ├── values/ ← Default (fallback) locale
// │ └── strings.xml
// ├── values-de/ ← German
// │ └── strings.xml
// ├── values-ja/ ← Japanese
// │ └── strings.xml
// └── values-es/ ← Spanish
// └── strings.xml
//
// Folder naming: values-{language} or values-{language}-r{Region}
// Examples: values-pt-rBR, values-zh-rCN, values-zh-rTWstrings.xml 생성
Android 문자열 리소스는 '<resources>' 루트 안에 '<string>' 요소를 넣은 XML을 사용해요. 문자열 플레이스홀더에는 %s, 정수에는 %d, 번역가가 순서를 바꿀 수 있는 위치 인수에는 %1$s/%2$s를 사용하세요.
<!-- res/values/strings.xml -->
<resources>
<string name="welcome_title">Welcome to MyApp</string>
<string name="login_button">Sign In</string>
<string name="settings_label">Settings</string>
<string name="greeting">Hello, %s!</string> <!-- %s = string -->
<string name="item_count">%d items</string> <!-- %d = integer -->
<string name="app_name" translatable="false">MyApp</string>
</resources><!-- ❌ Common mistakes in strings.xml: -->
<!-- Unescaped apostrophe — crashes XML parser silently -->
<string name="message">It's a great day</string>
<!-- Missing from default values/strings.xml — app crashes -->
<!-- (only exists in values-de/strings.xml) -->
<!-- ✅ Correct versions: -->
<string name="message">It\'s a great day</string>
<!-- Or wrap in double quotes: -->
<string name="message">"It's a great day"</string>복수형 처리
Android는 zero, one, two, few, many, other quantity 속성이 있는 '<plurals>' 요소를 사용해요. 필요한 범주는 대상 언어마다 달라요. 아랍어는 6가지를 모두 사용하고, 러시아어에는 few/many가 필요하며, 일본어는 other만 사용해요.
<!-- res/values/strings.xml -->
<resources>
<plurals name="items_count">
<item quantity="zero">No items</item>
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
</plurals>
</resources>
<!-- Usage in Kotlin: -->
<!-- val text = resources.getQuantityString(
R.plurals.items_count,
count, // selects plural form
count // format argument
) -->코드에서 사용: Kotlin 및 Jetpack Compose
기존 Android에서는 getString(R.string.key)과 resources.getQuantityString()을 사용해요. Jetpack Compose에서는 stringResource(R.string.key)와 pluralStringResource()를 사용해요. 둘 다 런타임에 기기 로케일을 기준으로 올바른 번역을 가져와요.
// Traditional Android (Activity/Fragment)
val title = getString(R.string.welcome_title)
val greeting = getString(R.string.greeting, userName)
val items = resources.getQuantityString(
R.plurals.items_count, count, count
)
// Jetpack Compose
@Composable
fun WelcomeScreen(userName: String, itemCount: Int) {
// ✅ stringResource — Compose-aware, triggers recomposition
Text(text = stringResource(R.string.welcome_title))
// ✅ With format arguments
Text(text = stringResource(R.string.greeting, userName))
// ✅ Plurals — count passed TWICE
Text(text = pluralStringResource(
R.plurals.items_count,
itemCount, // selects plural form
itemCount // format argument
))
}문자열 배열 및 형식 지정 문자열
드롭다운 옵션, 온보딩 단계 같은 순서가 있는 목록에는 '<string-array>'를 사용하세요. 번역가가 문장 구조를 깨뜨리지 않고 단어 순서를 바꿀 수 있도록 형식 지정 문자열에는 위치 형식 인수(%1$s, %2$d)를 사용하세요.
<!-- res/values/strings.xml -->
<resources>
<!-- String array for dropdown/list -->
<string-array name="sort_options">
<item>Most Recent</item>
<item>Most Popular</item>
<item>Price: Low to High</item>
<item>Price: High to Low</item>
</string-array>
<!-- Positional format args for reordering -->
<string name="welcome_message">
Hello %1$s, you have %2$d new messages
</string>
<!-- Translators can reorder: -->
<!-- %2$d neue Nachrichten für %1$s -->
</resources>Fastlane으로 Google Play 메타데이터 현지화
Fastlane의 supply 명령을 사용하면 제목, 간단한 설명, 자세한 설명, 변경 로그 같은 Play Store 메타데이터를 저장소에서 로케일별 일반 텍스트 파일로 관리할 수 있어요.
# Install Fastlane
$ gem install fastlane
# Initialize supply for Play Store metadata
$ fastlane supply init
# Directory structure created:
# fastlane/metadata/android/
# ├── en-US/
# │ ├── title.txt # App name (50 chars)
# │ ├── short_description.txt # Short desc (80 chars)
# │ ├── full_description.txt # Full desc (4000 chars)
# │ └── changelogs/
# │ └── default.txt # What's New
# ├── de-DE/
# │ └── ...
# └── ja-JP/
# └── ...
# Push metadata to Play Store:
$ fastlane supplyPlay Store 등록 정보 현지화 자동화
수동으로 복사해 붙여 넣을 필요가 없어요. 글자 수 제한을 고려해 Play Store 제목, 설명, 출시 노트를 175개 이상의 로케일로 번역해요.
Google Play 연동 살펴보기현지화 테스트
에뮬레이터의 로케일 전환, 맞춤 LocaleList를 적용한 Compose 미리 보기, 개발자 옵션의 의사 로케일로 테스트하세요. Gradle의 resConfigs를 사용해 타사 라이브러리에서 불필요한 로케일 리소스를 제거하세요.
// 1. Emulator: Settings > System > Language > Add language
// 2. Compose Preview with locale:
@Preview
@Composable
fun WelcomePreview() {
val config = Configuration(resources.configuration).apply {
setLocale(Locale("de"))
}
val localContext = LocalContext.current
val localizedContext = localContext.createConfigurationContext(config)
CompositionLocalProvider(
LocalContext provides localizedContext
) {
WelcomeScreen()
}
}
// 3. Restrict library locales in build.gradle.kts:
android {
defaultConfig {
// Only include locales you actually translate
resourceConfigurations += listOf("en", "de", "ja", "es", "fr")
}
}
// 4. Enable pseudolocales in Developer Options:
// en-XA (accented) — detects hardcoded strings
// ar-XB (RTL) — tests layout mirroring번역 품질 검사 자동화
번역 자동화
AI로 strings.xml, 복수형, 문자열 배열, Fastlane Supply 메타데이터를 번역하세요. 앱 내 문자열과 Play Store 메타데이터 번역을 모두 자동화해 완전히 현지화된 앱을 제공할 수 있어요.
# Translate strings.xml files
> Translate res/values/strings.xml
to Japanese, German, and Spanish
# Translate Play Store metadata too
> Translate fastlane/metadata/android/en-US/
to de-DE, ja-JP, es-ES
✓ 6 files translated in 3.2sAndroid Studio 플러그인 제공
IntelliJ 및 Android Studio용 i18n Agent 플러그인으로 IDE에서 Android XML 리소스를 직접 번역하세요.
추가 기능: LocaleChain을 활용한 스마트 로케일 폴백
Android의 리소스 폴백은 OS가 제어해요. pt-BR 번역이 없으면 Android는 pt-PT를 완전히 건너뛰고 영어를 표시해요. LocaleChain은 문자열 조회를 가로채 구성 가능한 폴백 체인을 차례로 확인하므로 지역 사용자가 가장 가까운 번역을 볼 수 있어요.
Android용 LocaleChain은 오픈 소스 Kotlin 라이브러리예요. GitHub에서 보기
// build.gradle.kts (app module)
dependencies {
implementation("com.i18nagent:locale-chain-android:0.1.0")
}// 1. Application.onCreate() — configure chains once
class MyApp : Application() {
override fun onCreate() {
super.onCreate()
LocaleChain.configure()
}
}
// 2. BaseActivity — wrap context per Activity
open class BaseActivity : AppCompatActivity() {
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleChain.wrap(newBase))
}
}
// pt-BR user with only pt-PT translations?
// → Shows Portuguese instead of falling back to English
// Custom overrides for your specific locales:
LocaleChain.configure(
overrides = mapOf("es-MX" to listOf("es-419", "es"))
)흔한 실수
기본 문자열 누락으로 인한 앱 비정상 종료
App Bundle 언어 분할로 인한 앱 내 전환 오류
RTL 레이아웃 깨짐
라이브러리 리소스로 인한 지원 언어 혼입
권장 파일 구조
MyApp/
├── app/
│ └── src/main/
│ ├── res/
│ │ ├── values/
│ │ │ ├── strings.xml # Default (source) strings
│ │ │ └── plurals.xml # Plural rules
│ │ ├── values-de/
│ │ │ └── strings.xml
│ │ ├── values-ja/
│ │ │ └── strings.xml
│ │ └── values-es/
│ │ └── strings.xml
│ ├── java/com/example/myapp/
│ └── AndroidManifest.xml
├── fastlane/
│ └── metadata/android/
│ ├── en-US/
│ │ ├── title.txt
│ │ ├── short_description.txt
│ │ ├── full_description.txt
│ │ └── changelogs/default.txt
│ ├── de-DE/
│ └── ja-JP/
├── build.gradle.kts
└── settings.gradle.kts지금 i18n Agent 사용해 보기
번역 파일을 여기에 드롭
JSON, YAML, PO, XML, CSV, Markdown, Properties
또는 클릭하여 파일 선택
대상 언어
locale-chain-android를 활용한 로케일 폴백
pt-BR 같은 지역 로케일에 번역 키가 없으면 Android는 상위 로케일 pt를 먼저 확인하지 않고 기본 리소스 폴더로 바로 폴백해요.
implementation("com.i18nagent:locale-chain-android:0.1.0")import com.i18nagent.localechain.LocaleChain
LocaleChain.configure(
overrides = mapOf(
"pt-BR" to listOf("pt", "en"),
"zh-Hant-HK" to listOf("zh-Hant", "zh", "en"),
)
)지원 프레임워크와 75개 내장 체인의 전체 목록은 로케일 폴백 가이드에서 확인하세요. Learn more →