Tüm Yazılar
KategoriiOS
Okuma Süresi
19 dk okuma
Yayın Tarihi
...
Kelime Sayısı
1.814kelime

Kahveni hazırla - bu içerikli bir makale!

String Catalogs, Localizable.xcstrings, pluralization, RTL desteği ve App Store localization. Uygulamanızı dünyaya açın.

iOS Localization ve i18n: Çok Dilli Uygulama Geliştirme

# iOS Localization ve i18n: Çok Dilli Uygulama Geliştirme

Uygulamanızı tek bir dille sınırlamak, potansiyel kullanıcılarınızın büyük bir kısmını kaybetmek demektir. App Store'daki en başarılı uygulamalar 30+ dili destekler. Xcode 15+ ile gelen String Catalogs sayesinde localization artık çok daha kolay. Bu rehberde sıfırdan profesyonel seviyeye i18n implementasyonu yapacağız.


İçindekiler


1. String Catalogs (Xcode 15+)

Xcode 15 ile gelen String Catalogs, eski .strings ve .stringsdict dosyalarını tek bir .xcstrings dosyasında birleştirir.

Geçiş Adımları

Eski Sistem
Yeni Sistem
Avantaj
Localizable.strings
Localizable.xcstrings
Tek dosya, visual editor
Localizable.stringsdict
Otomatik dahil
Pluralization görsel
InfoPlist.strings
InfoPlist.xcstrings
Ayrı catalog
Manuel key yönetimi
Otomatik extraction
Build time detection
swift
1// Xcode otomatik olarak String literal'ları yakalar
2// SwiftUI'de Text() zaten LocalizedStringKey kullanır
3 
4struct WelcomeView: View {
5 let userName: String
6 let itemCount: Int
7 
8 var body: some View {
9 VStack {
10 // Otomatik olarak String Catalog'a eklenir
11 Text("Hoş Geldiniz")
12 
13 // String interpolation da desteklenir
14 Text("Merhaba, \(userName)!")
15 
16 // Pluralization otomatik
17 Text("\(itemCount) öğe seçildi")
18 }
19 }
20}

Easter Egg

Gizli bir bilgi buldun!

Bu bölümde gizli bir bilgi var. Keşfetmek ister misin?


2. Programmatic Localization

swift
1// Eski yöntem (hâlâ çalışır)
2let greeting = NSLocalizedString("greeting", comment: "Ana ekran karşılama mesajı")
3 
4// Modern yöntem - String(localized:)
5let greeting = String(localized: "greeting", comment: "Ana ekran karşılama mesajı")
6 
7// Farklı table'dan okuma
8let settingsTitle = String(
9 localized: "settings.title",
10 table: "Settings",
11 comment: "Ayarlar ekranı başlığı"
12)
13 
14// Bundle'dan okuma (framework/SPM)
15let frameworkString = String(
16 localized: "button.save",
17 bundle: .module,
18 comment: "Kaydet butonu"
19)

LocalizedStringResource (iOS 16+)

swift
1// Daha güçlü ve type-safe localization
2struct NotificationContent {
3 let title: LocalizedStringResource
4 let body: LocalizedStringResource
5}
6 
7let content = NotificationContent(
8 title: "Yeni Mesaj",
9 body: "\(senderName) size bir mesaj gönderdi"
10)
11 
12// String'e dönüştürme
13let titleString = String(localized: content.title)

3. Pluralization

Türkçe basit olsa da, Rusça gibi diller 6 farklı plural form'a sahip. String Catalogs bunu görsel olarak yönetir.

swift
1// String Catalog'da otomatik plural desteği
2Text("\(count) dosya silindi")
3// Catalog'da:
4// zero: "Dosya silinmedi"
5// one: "1 dosya silindi"
6// other: "%lld dosya silindi"
7 
8// Custom plural fonksiyon
9func fileCountDescription(_ count: Int) -> String {
10 String(localized: "\(count) file(s) deleted",
11 comment: "Silinen dosya sayısı mesajı")
12}
Dil
Plural Rules
Kategoriler
**Türkçe**
2 form
one, other
**İngilizce**
2 form
one, other
**Arapça**
6 form
zero, one, two, few, many, other
**Rusça**
4 form
one, few, many, other
**Japonca**
1 form
other
**Lehçe**
4 form
one, few, many, other

4. SwiftUI Localization Patterns

swift
1// 1. Text otomatik localize eder
2Text("Kaydet") // ✅ LocalizedStringKey
3 
4// 2. String parametreler localize ETMEZ
5let dynamicString = "Kaydet"
6Text(dynamicString) // ❌ String olarak kalır
7Text(LocalizedStringKey(dynamicString)) // ✅ Explicit conversion
8 
9// 3. Label ve Button
10Button("Sil") { deleteItem() } // ✅ Otomatik
11Label("Ayarlar", systemImage: "gear") // ✅ Otomatik
12 
13// 4. TextField placeholder
14TextField("E-posta adresiniz", text: $email) // ✅ Otomatik
15 
16// 5. Accessibility
17Image("hero")
18 .accessibilityLabel("Ana sayfa görseli") // ✅ Otomatik
19 
20// 6. Environment ile dil değiştirme (preview'da kullanışlı)
21struct ContentView_Previews: PreviewProvider {
22 static var previews: some View {
23 ContentView()
24 .environment(\.locale, Locale(identifier: "tr"))
25 ContentView()
26 .environment(\.locale, Locale(identifier: "en"))
27 ContentView()
28 .environment(\.locale, Locale(identifier: "ar"))
29 .environment(\.layoutDirection, .rightToLeft)
30 }
31}

5. Date, Number & Currency Formatting

swift
1// Tarih - her zaman Formatter kullanın, manuel format YASAK!
2let date = Date()
3 
4// SwiftUI otomatik locale-aware
5Text(date, style: .date) // "9 Şubat 2025"
6Text(date, style: .time) // "14:30"
7Text(date, style: .relative) // "2 saat önce"
8 
9// Programmatic
10let formatted = date.formatted(
11 .dateTime.day().month(.wide).year()
12 .locale(Locale(identifier: "tr_TR"))
13) // "9 Şubat 2025"
14 
15// Sayı formatlama
16let number = 1234567.89
17Text(number, format: .number) // "1.234.567,89" (TR)
18 
19// Para birimi
20let price = Decimal(29.99)
21Text(price, format: .currency(code: "TRY")) // "₺29,99"
22Text(price, format: .currency(code: "USD")) // "$29.99"
23 
24// Ölçü birimleri
25let distance = Measurement(value: 5.2, unit: UnitLength.kilometers)
26Text(distance, format: .measurement(width: .wide)) // "5,2 kilometre"

6. RTL (Sağdan Sola) Desteği

swift
1// SwiftUI otomatik RTL desteği sağlar
2// Ama dikkat edilmesi gerekenler:
3 
4// ✅ leading/trailing kullanın (left/right DEĞİL)
5HStack {
6 Text("İsim")
7 Spacer()
8 Text("Değer")
9}
10.padding(.leading, 16) // ✅ RTL'de otomatik sağa döner
11// .padding(.left, 16) // ❌ RTL'de yanlış tarafta kalır
12 
13// ✅ Flipped image'lar
14Image(systemName: "arrow.right")
15 .flipsForRightToLeftLayoutDirection(true)
16 
17// ✅ TextAlignment
18Text("مرحبا")
19 .multilineTextAlignment(.leading) // RTL'de sağa hizalanır

7. Asset Localization

swift
1// Asset catalog'da localized images
2// 1. Asset'e sağ tık → Localize
3// 2. Her dil için farklı görsel ekle
4 
5// Localized asset kullanımı
6Image("onboarding_hero") // Otomatik doğru dili seçer
7 
8// App Icon localization (Info.plist)
9// CFBundleIcons → CFBundleAlternateIcons ile dil bazlı ikon

8. Localization Testing

swift
1// Unit test
2func testLocalization() {
3 let bundle = Bundle(for: type(of: self))
4 let languages = ["tr", "en", "de", "ar", "ja"]
5 
6 for lang in languages {
7 guard let path = bundle.path(forResource: lang, ofType: "lproj"),
8 let langBundle = Bundle(path: path) else {
9 XCTFail("Missing localization: \(lang)")
10 continue
11 }
12 
13 let greeting = langBundle.localizedString(
14 forKey: "greeting", value: nil, table: nil
15 )
16 XCTAssertNotEqual(greeting, "greeting",
17 "Untranslated key 'greeting' in \(lang)")
18 }
19}
20 
21// Scheme'de pseudo-localization
22// Edit Scheme → Run → Arguments → -NSDoubleLocalizedStrings YES
23// Bu tüm string'leri 2x uzatır → layout sorunlarını yakalar
24 
25// -AppleLanguages "(ar)" ile Arapça test
26// -NSForceRightToLeftWritingDirection YES ile RTL test

9. App Store Localization

Öğe
Max Karakter
Dikkat
**App Name**
30
Her dilde farklı olabilir
**Subtitle**
30
Anahtar kelime fırsatı
**Keywords**
100
Dile özel SEO
**Description**
4000
İlk 3 satır kritik
**Promotional Text**
170
Review olmadan güncellenebilir
**Screenshots**
10 adet
Localized text overlay

10. Export/Import Workflow ve Çeviri Entegrasyonu

Büyük projelerde localization yönetimi manuel yapılamaz. Xcode'un XLIFF export/import sistemi ve third-party entegrasyonlar bu süreci otomatize eder.

XLIFF Export/Import

bash
1# Tüm localize edilebilir string'leri XLIFF formatında export et
2xcodebuild -exportLocalizations -project MyApp.xcodeproj \
3 -localizationPath ./Localizations \
4 -exportLanguage tr -exportLanguage en -exportLanguage de -exportLanguage ar
5 
6# Çeviri tamamlandıktan sonra import et
7xcodebuild -importLocalizations -project MyApp.xcodeproj \
8 -localizationPath ./Localizations/de.xcloc

Çeviri Servisleri Entegrasyonu

Servis
Avantaj
Dezavantaj
Fiyat Modeli
**Lokalise**
Xcode entegrasyonu, OTA update
Pahalı
Per-word
**Phrase**
GitHub/GitLab CI entegrasyonu
Kurulumu karmaşık
Per-user
**POEditor**
Basit UI, hızlı başlangıç
Sınırlı CI
Freemium
**Crowdin**
Açık kaynak desteği, geniş API
UI karmaşık
Per-word
**Transifex**
Güçlü API, webhook desteği
Eski arayüz
Per-word

CI/CD Localization Pipeline

swift
1// Fastlane ile localization otomasyonu
2// Fastfile
3 
4lane :sync_translations do
5 // 1. Export edilebilir string'leri çıkar
6 sh("xcodebuild -exportLocalizations -project ../MyApp.xcodeproj -localizationPath ../Translations")
7 
8 // 2. Çeviri servisine gönder (Lokalise örneği)
9 sh("lokalise2 file upload --project-id PROJECT_ID --file ../Translations/en.xcloc --lang-iso en")
10 
11 // 3. Çevirileri indir
12 sh("lokalise2 file download --project-id PROJECT_ID --format xliff --dest ../Translations/")
13 
14 // 4. Xcode'a import et
15 sh("xcodebuild -importLocalizations -project ../MyApp.xcodeproj -localizationPath ../Translations/tr.xcloc")
16end

String Catalog Doğrulama Script'i

swift
1// Eksik çevirileri bulan bir script
2import Foundation
3 
4func findMissingTranslations(in xcstringsPath: String, for language: String) {
5 guard let data = FileManager.default.contents(atPath: xcstringsPath),
6 let catalog = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
7 let strings = catalog["strings"] as? [String: Any] else {
8 print("Catalog okunamadı")
9 return
10 }
11 
12 var missingCount = 0
13 for (key, value) in strings {
14 guard let entry = value as? [String: Any],
15 let localizations = entry["localizations"] as? [String: Any] else {
16 print("EKSIK: \(key) — hiç çeviri yok")
17 missingCount += 1
18 continue
19 }
20 
21 if localizations[language] == nil {
22 print("EKSIK [\(language)]: \(key)")
23 missingCount += 1
24 }
25 }
26 print("Toplam eksik: \(missingCount) string")
27}

11. Best Practices Checklist

  • String Catalogs kullan (Xcode 15+)
  • Hardcoded string YASAK — tümü localize
  • Pluralization tüm diller için doğru
  • Date/Number/Currency → Formatter kullan
  • RTL layout test edilmiş
  • Pseudo-localization ile layout test
  • Minimum 10 dil desteği hedefle
  • Professional çeviri (makine çevirisi → human review)
  • App Store metadata her dil için optimize
  • Accessibility label'ları localize

ALTIN İPUCU

Bu yazının en değerli bilgisi

Bu ipucu, yazının en önemli çıkarımını içeriyor.

Okuyucu Ödülü

Tebrikler! Bu yazıyı sonuna kadar okuduğun için sana özel bir hediyem var:

Etiketler

#Localization#i18n#String Catalog#RTL#Accessibility#iOS
Muhittin Çamdalı

Muhittin Çamdalı

Senior iOS Developer

12+ yıllık deneyime sahip iOS Developer. Swift, SwiftUI ve modern iOS mimarileri konusunda uzman. Apple platformlarında performanslı ve kullanıcı dostu uygulamalar geliştiriyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Gizliliğinize saygı duyuyoruz. İstediğiniz zaman abonelikten çıkabilirsiniz.

Paylaş

Bunu da begenebilirsiniz