iOS & Android Integration
LangCTL exports platform-specific formats for iOS (Localizable.strings) and Android (strings.xml) with automatic parameter conversion.
iOS Integration
Export for iOS
langctl export my-app -l en -f ios-strings -o ./Resources/en.lproj/Localizable.strings
langctl export my-app -l es -f ios-strings -o ./Resources/es.lproj/Localizable.strings
langctl export my-app -l fr -f ios-strings -o ./Resources/fr.lproj/Localizable.strings File Structure
MyApp/
Resources/
en.lproj/
Localizable.strings
es.lproj/
Localizable.strings
fr.lproj/
Localizable.strings
Using Translations in Swift
// Basic usage
let welcome = NSLocalizedString("home.welcome", comment: "Welcome message")
// With parameters
let greeting = String(
format: NSLocalizedString("home.greeting", comment: ""),
username
)
// SwiftUI
import SwiftUI
struct ContentView: View {
var body: some View {
VStack {
Text(LocalizedStringKey("home.welcome"))
Text(LocalizedStringKey("home.subtitle"))
}
}
} LangCTL converts {{param}} to iOS format:
| LangCTL | iOS Output |
|---|---|
{{username}} | %@ |
{{count}} | %@ |
{{username}}, {{count}} | %1$@, %2$@ |
langctl export my-app -l en -f android-xml -o ./app/src/main/res/values/strings.xml
langctl export my-app -l es -f android-xml -o ./app/src/main/res/values-es/strings.xml
langctl export my-app -l fr -f android-xml -o ./app/src/main/res/values-fr/strings.xml File Structure
app/
src/
main/
res/
values/
strings.xml (English - default)
values-es/
strings.xml (Spanish)
values-fr/
strings.xml (French)
Using Translations in Kotlin
// Basic usage
val welcome = getString(R.string.home_welcome)
// Set in TextView
binding.textView.text = getString(R.string.home_welcome)
// With parameters
val greeting = getString(R.string.home_greeting, username)
binding.textView.text = getString(R.string.home_greeting, username, count)
// In Compose
@Composable
fun HomeScreen() {
Column {
Text(stringResource(R.string.home_welcome))
Text(stringResource(R.string.home_subtitle))
}
} LangCTL converts {{param}} to Android format:
| LangCTL | Android Output |
|---|---|
{{username}} | %1$s |
{{count}} | %1$d |
{{username}}, {{count}} | %1$s, %2$d |
ℹ️
Note
Android uses positional parameters (%1$s, %2$s) for proper pluralization and RTL support.
name: iOS Build
on: [push]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Install LangCTL
run: npm install -g @langctl/cli
- name: Export Translations
env:
LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
run: |
langctl export my-app -l en -f ios-strings -o ./Resources/en.lproj/Localizable.strings
langctl export my-app -l es -f ios-strings -o ./Resources/es.lproj/Localizable.strings
- name: Build iOS App
run: xcodebuild -scheme MyApp -configuration Release name: Android Build
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up JDK
uses: actions/setup-java@v3
with:
java-version: '17'
- name: Install LangCTL
run: npm install -g @langctl/cli
- name: Export Translations
env:
LANGCTL_API_KEY: ${{ secrets.LANGCTL_API_KEY }}
run: |
langctl export my-app -l en -f android-xml -o ./app/src/main/res/values/strings.xml
langctl export my-app -l es -f android-xml -o ./app/src/main/res/values-es/strings.xml
- name: Build Android App
run: ./gradlew assembleRelease lane :fetch_translations do
sh("npm install -g @langctl/cli")
["en", "es", "fr"].each do |lang|
sh("langctl export my-app -l #{lang} -f ios-strings -o ../Resources/#{lang}.lproj/Localizable.strings")
end
end
lane :release do
fetch_translations
build_app(scheme: "MyApp")
upload_to_app_store
end lane :fetch_translations do
sh("npm install -g @langctl/cli")
{
"en" => "values",
"es" => "values-es",
"fr" => "values-fr"
}.each do |lang, dir|
sh("langctl export my-app -l #{lang} -f android-xml -o ../app/src/main/res/#{dir}/strings.xml")
end
end
lane :release do
fetch_translations
gradle(task: "assembleRelease")
upload_to_play_store
end Best Practices
iOS Best Practices
-
Use String Catalogs (iOS 15+):
- Export as Localizable.strings
- Import into Xcode String Catalog
- Benefit from Xcode’s translation editor
-
Localized String Keys:
- Use descriptive keys:
home.welcomenotstring_001 - Group by feature:
auth.login.title - Add comments for context
- Use descriptive keys:
-
Test RTL Languages:
- Export Arabic/Hebrew
- Test layout in Xcode
- Use Auto Layout constraints
Android Best Practices
-
Resource Qualifiers:
- Use correct directory names:
values-es,values-ar - Follow Android conventions
- Test with different configurations
- Use correct directory names:
-
Pluralization:
- Export plural forms separately
- Use Android plural resources
- Test all quantity cases
-
String Formatting:
- Avoid hardcoded strings
- Use string resources everywhere
- Format numbers/dates properly
💡
Tip
Always test translations on actual devices in different languages to catch layout and formatting issues.
Troubleshooting
iOS Issues
Strings not appearing:
- Clean build folder (Cmd+Shift+K)
- Check .lproj folder names match language codes
- Verify Localizable.strings is in Copy Bundle Resources
Parameters not working:
- Check String.format() syntax
- Verify parameter order matches export
- Use String(format:) correctly
Android Issues
Resources not found:
- Check values-XX folder naming
- Ensure strings.xml is valid XML
- Clean and rebuild project
Parameters not formatting:
- Verify correct parameter type (%s vs %d)
- Check positional indicators (%1$s, %2$s)
- Escape special characters properly
Next Steps
- Cross-Platform - Flutter & React Native
- CI/CD Integration - Automate workflows
- Export Formats - Format specifications
- CLI Export - Command-line tools