NSLocalizedString kullanarak en iyi uygulama


140

NSLocalizedStringUygulamamı yerelleştirmek için (diğerleri gibi) kullanıyorum .

Ne yazık ki, birkaç "dezavantaj" vardır (NSLocalizedString'in kendisinin hatası olmak zorunda değildir),

  • Xcode'daki dizeler için otomatik tamamlama yok. Bu, çalışmayı sadece hataya yatkın değil aynı zamanda yorucu hale getirir.
  • Bir dizeyi daha önce var olan eşdeğer bir dizeyi bilmediğiniz için yeniden tanımlayabilirsiniz (örneğin, "Lütfen şifreyi girin" ve "Önce şifreyi girin")
  • Otomatik tamamlama sorununa benzer şekilde, yorum dizelerini "hatırlamanız" / kopyalamanız gerekir, aksi genstringtakdirde bir dize için birden fazla yorum elde edersiniz
  • genstringBazı dizeleri yerelleştirdikten sonra kullanmak istiyorsanız, eski yerelleştirmelerinizi kaybetmemeye dikkat etmelisiniz.
  • Tüm projeniz boyunca aynı dizeler dağılmıştır. Örneğin, NSLocalizedString(@"Abort", @"Cancel action")her yerde kullandınız ve Kod İncelemesi NSLocalizedString(@"Cancel", @"Cancel action"), kodu daha tutarlı hale getirmek için dizeyi yeniden adlandırmanızı ister .

Ne yaptığımı (ve bazı aramalar sonra ben birçok kişi bunu düşündüm) strings.hburada #definetüm yerelleştirme kodu ayrı bir dosyaya sahip olmaktır . Örneğin

// In strings.h
#define NSLS_COMMON_CANCEL NSLocalizedString(@"Cancel", nil)
// Somewhere else
NSLog(@"%@", NSLS_COMMON_CANCEL);

Bu aslında kod tamamlama, değişken adlarını değiştirmek için tek bir yer (artık genstring'e gerek yok) ve otomatik refactor için benzersiz bir anahtar kelime sağlar. Bununla birlikte, bu, #definedoğası gereği yapılandırılmamış bir dizi ifadeyle sonuçlanmak pahasına gelir (örneğin, LocString.Common.Cancel veya bunun gibi bir şey gibi).

Yani, bu biraz iyi çalışıyor olsa da, bunu projelerinizde nasıl yaptığınızı merak ediyordum. NSLocalizedString kullanımını basitleştirmek için başka yaklaşımlar var mı? Onu çevreleyen bir çerçeve bile var mı?


Sadece senin gibi yapıyorum. Ama NSLocalizedStringWithDefaultValue makro farklı yerelleştirme sorunları (denetleyiciler, modeller, vb. Gibi) için farklı dizeleri dosyaları oluşturmak ve bir başlangıç ​​varsayılan değer oluşturmak için kullanıyorum.
anka

Görünüşe göre xcode6'nın Yerelleştirmeye Aktar, bir başlık dosyasında makrolar olarak tanımlanan dizeleri yakalamıyor. Neler eksik olabileceğimi kimse onaylayabilir veya söyleyebilir mi? Teşekkürler...!
Juddster

@Juddster, yeni fonla bile teyit edebilir Editör-> Yerelleştirme için Dışa Aktar başlık dosyasında alınmaz
Kırmızı

Yanıtlar:


100

NSLocalizedStringbazı sınırlamaları vardır, ancak kakao için o kadar merkezi ki, yerelleştirmeyi işlemek için özel kod yazmak mantıksızdır, yani kullanmak zorunda kalacaksınız. Bununla birlikte, küçük bir takım yardımcı olabilir, işte şöyle devam ediyorum:

Dizeler dosyasını güncelleme

genstringsönceki tüm çevirilerinizi atarak dize dosyalarınızın üzerine yazar. Eski dizeler dosyasını ayrıştırmak, güncellemeleri manuel olarak geri yüklemek zorunda kalmamak için boşlukları doldurup doldurmak için update_strings.py yazdım genstrings. Komut dosyası, güncelleştirilirken çok büyük farklardan kaçınmak için varolan dize dosyalarını mümkün olduğunca eşleştirmeye çalışır.

Dizelerinizi adlandırma

NSLocalizedStringReklamı yapılan olarak kullanıyorsanız :

NSLocalizedString(@"Cancel or continue?", @"Cancel notice message when a download takes too long to proceed");

Aynı İngilizce terimin farklı bağlamlarda farklı anlamları olabileceği ( OKve Cancelaklınıza geldiği) için kodunuzun başka bir bölümünde aynı dizeyi tanımlayabilirsiniz . Bu yüzden her zaman modüle özgü bir önek ve çok kesin bir açıklama ile anlamsız bir all-caps dizesi kullanın:

NSLocalizedString(@"DOWNLOAD_CANCEL_OR_CONTINUE", @"Cancel notice window title when a download takes too long to proceed");

Aynı dizeyi farklı yerlerde kullanma

Aynı dizeyi birden çok kez kullanırsanız, bir makroyu yaptığınız gibi kullanabilir veya görünüm denetleyicinizde veya veri kaynağınızda örnek değişken olarak önbelleğe alabilirsiniz. Bu şekilde, her zaman kafa karıştırıcı olan aynı yerelleştirmenin örnekleri arasında bayat ve tutarsız olabilecek açıklamayı tekrarlamanız gerekmez. Örnek değişkenler sembol olduğundan, bu en yaygın çevirilerde otomatik tamamlamayı kullanabileceksiniz ve belirli olanlar için "el ile" dizeleri kullanabileceksiniz.

Umarım bu ipuçlarıyla Kakao yerelleştirmesinde daha üretken olursunuz!


Cevabınız için teşekkür ederim, python dosyanıza kesinlikle bir göz atacağım. Adlandırma sözleşmelerinize katılıyorum. Son zamanlarda diğer bazı iOS geliştiricileriyle konuştum ve makrolar yerine statik dizelerin kullanılmasını önerdiler, bu da mantıklı. Cevabınızı iptal ettim, ancak kabul etmeden önce biraz bekleyeceğim, çünkü çözüm hala biraz sakar. Belki daha iyi bir şey gelir. Tekrar teşekkürler!
JiaYow

Çok rica ederim. Yerelleştirme sıkıcı bir süreçtir, doğru araçlara ve iş akışına sahip olmak fark yaratır.
ndfred

17
Gettext tarzı yerelleştirme işlevlerinin neden çevirilerden birini anahtar olarak kullandığını hiç anlamadım. Orijinal metniniz değişirse ne olur? Anahtarınız değişir ve tüm yerelleştirilmiş dosyalarınız anahtarları için eski metni kullanır. Bana hiç mantıklı gelmedi. Her zaman "home_button_text" gibi anahtarlar kullandım, böylece benzersiz ve asla değişmezler. Ayrıca tüm Localizable.strings dosyaları ayrıştırmak ve uygun dize yükleyecek statik yöntemlerle bir sınıf dosyası oluşturmak için bir bash komut dosyası yazdım. Bu bana kod tamamlama verir. Bir gün bunu açık kaynak yapabilirim.
Mike Weller

2
Bence demek genstringsistemiyorsun gestring.
hiroshi

1
@ndfred compile time dizeyi yanlış yazıp yazmadığınızı kontrol eder. Yine de eklemek için marjinal olarak daha fazla kod. Ayrıca yeniden düzenleme durumunda, statik analiz, bir sembolün olması işleri daha kolay hale getirecektir.
Allen Zeng


24

Ndfred ile katılıyorum, ama bunu eklemek istiyorum:

İkinci parametre ... varsayılan değer olarak kullanılabilir!

(NSLocalizedStringWithDefaultValue, genstring ile düzgün çalışmıyor, bu yüzden bu çözümü önerdim)

İşte varsayılan değer olarak açıklama kullanan NSLocalizedString kullanan benim Özel uygulama:

1. Önceden derlenmiş başlığınızda (.pch dosyası), 'NSLocalizedString' makrosunu yeniden tanımlayın:

// cutom NSLocalizedString that use macro comment as default value
#import "LocalizationHandlerUtil.h"

#undef NSLocalizedString
#define NSLocalizedString(key,_comment) [[LocalizationHandlerUtil singleton] localizedString:key  comment:_comment]

2. yerelleştirme işleyicisini uygulamak için bir sınıf oluşturun

#import "LocalizationHandlerUtil.h"

@implementation LocalizationHandlerUtil

static LocalizationHandlerUtil * singleton = nil;

+ (LocalizationHandlerUtil *)singleton
{
    return singleton;
}

__attribute__((constructor))
static void staticInit_singleton()
{
    singleton = [[LocalizationHandlerUtil alloc] init];
}

- (NSString *)localizedString:(NSString *)key comment:(NSString *)comment
{
    // default localized string loading
    NSString * localizedString = [[NSBundle mainBundle] localizedStringForKey:key value:key table:nil];

    // if (value == key) and comment is not nil -> returns comment
    if([localizedString isEqualToString:key] && comment !=nil)
        return comment;

    return localizedString;
}

@end

3. Kullanın!

Her derlemede Localizable.strings dosyanızın güncellenmesi için Uygulama Derleme Aşamalarınıza bir Çalıştır komut dosyası eklediğinizden emin olun, yani Localized.strings dosyanıza yeni yerelleştirilmiş dize eklenir:

Benim derleme aşaması komut dosyası bir kabuk komut dosyasıdır:

Shell: /bin/sh
Shell script content: find . -name \*.m | xargs genstrings -o MyClassesFolder

Bu yeni satırı kodunuza eklediğinizde:

self.title = NSLocalizedString(@"view_settings_title", @"Settings");

Ardından bir yapı oluşturun, ./Localizable.scripts dosyanız şu yeni satırı içerecektir:

/* Settings */
"view_settings_title" = "view_settings_title";

Ve 'view_settings_title' için anahtar == değeri olduğundan, özel LocalizedStringHandler yorumu döndürür, yani 'Ayarlar "

Voilà :-)


ARC hataları
alıyorum,

Sanırım bunun nedeni LocalizationHandlerUtil.h eksik. Kodu geri bulamıyorum ... Sadece LocalizationHandlerUtil.h başlık dosyasını oluşturmaya çalışın ve sorun olmalı
Pascal

Dosyaları ben yarattım. Klasör yolu sorunu nedeniyle düşünüyorum.
Mangesh

3

Swift'te aşağıdakileri kullanıyorum, örneğin bu durumda "Evet" düğmesi için:

NSLocalizedString("btn_yes", value: "Yes", comment: "Yes button")

value:Varsayılan metin değeri için kullanımını not alın . İlk parametre çeviri kimliği olarak işlev görür. value:Parametreyi kullanmanın avantajı , varsayılan metnin daha sonra değiştirilebilmesidir, ancak çeviri kimliğinin aynı kalmasıdır. Localizable.strings dosyası"btn_yes" = "Yes";

Eğer value:parametre daha sonra kullanılmamıştır ilk parametre her ikisi için kullanılacaktır: çeviri kimliği için ve ayrıca varsayılan metin değeri için. Localizable.strings dosyası içerir "Yes" = "Yes";. Bu tür yerelleştirme dosyalarını yönetmek garip görünüyor. Özellikle çevrilmiş metin uzunsa kimlik de uzundur. Varsayılan metin değerinin herhangi bir karakteri değiştirildiğinde, çeviri kimliği de değişir. Bu, harici çeviri sistemleri kullanıldığında sorunlara yol açar. Çeviri kimliğinin değiştirilmesi, her zaman istenmeyebilecek yeni çeviri metni eklenmesi olarak anlaşılmaktadır.


2

Birden çok dilde Localizable.strings korunmasına yardımcı olacak bir komut dosyası yazdım. Otomatik tamamlamada yardımcı olmasa da, komutu kullanarak .strings dosyalarının birleştirilmesine yardımcı olur:

merge_strings.rb ja.lproj/Localizable.strings en.lproj/Localizable.strings

Daha fazla bilgi için bkz. Https://github.com/hiroshi/merge_strings

Bazılarınız bunu yararlı buluyor.


2

Swift çözümü arayan biri varsa. Burada bir araya getirdiğim çözümü kontrol etmek isteyebilirsiniz: SwiftyLocalization

Kurulum için birkaç adımda, Google E-Tablo'da çok esnek bir yerelleştirmeye sahip olursunuz (yorum, özel renk, vurgu, yazı tipi, birden çok sayfa ve daha fazlası).

Kısacası, adımlar şunlardır: Google E-Tablo -> CSV dosyaları -> Localizable.strings

Dahası, aynı zamanda sizin için bir anahtar alma ve kod çözme için arayüzler gibi davranan bir yapı olan Localizables.swift üretir (Dizeyi anahtardan deşifre etmenin bir yolunu manuel olarak belirtmeniz gerekir).

Bu neden harika?

  1. Artık her yerde düz bir dize olarak bir anahtara ihtiyacınız yok.
  2. Derleme zamanında yanlış anahtarlar algılanıyor.
  3. Xcode otomatik tamamlama yapabilir.

Yerelleştirilebilir anahtarınızı otomatik olarak tamamlayabilen araçlar varken. Gerçek bir değişkene başvurmak, her zaman geçerli bir anahtar olmasını sağlar, aksi takdirde derlenmez.

// It's defined as computed static var, so it's up-to-date every time you call. 
// You can also have your custom retrieval method there.

button.setTitle(Localizables.login.button_title_login, forState: .Normal)

Proje, E-Tablolar'ı dönüştürmek için Google App Script'i ve CSV dosyalarını dönüştürmek için Python betiğini kullanıyor -> Localizable.strings Nelerin mümkün olduğunu öğrenmek için bu örnek sayfaya hızlıca göz atabilirsiniz.


1

iOS 7 ve Xcode 5 ile, 'Localization.strings' yöntemini kullanmaktan kaçınmalı ve yeni 'temel yerelleştirme' yöntemini kullanmalısınız. Google'da 'temel yerelleştirme' için bazı öğreticiler var

Apple doc: Temel yerelleştirme


evet Steve bu doğru. Ayrıca, dinamik olarak oluşturulan herhangi bir dize için .strings dosya yöntemine hala ihtiyacınız vardır. Ancak sadece bunlar için Apple'ın tercih ettiği yöntem temel yerelleştirmedir.
Ronny Webers

Yeni yönteme bağlantı?
Abartma

1
Imo temel Yerelleştirme yöntemi değersizdir. Dinamik dizeler için diğer konum dosyalarını kullanmaya devam etmelisiniz ve dizelerinizin birçok dosyaya yayılmasını sağlar. Nibs içindeki Strings / Film şeritleri gibi bazı Libs ile Localizable.strings içinde tuşlara otomatik olarak lokalize edilebilir github.com/AliSoftware/OHAutoNIBi18n
Rafael Nobre

0
#define PBLocalizedString(key, val) \

[[NSBundle mainBundle] localizedStringForKey:(key) value:(val) table:nil]

0

Kendim, genellikle .strings dosyalarına girişleri unutmayı unutup kodlama ile uğraşıyorum. Böylece .strings dosyalarına geri koymak ve çevirmek için ne borçluyum bulmak için yardımcı komut dosyaları var.

Ben NSLocalizedString üzerinde kendi makro kullanmak üzere, gözden geçirmek ve kullanmadan önce komut dosyasını güncelleyin O basitlik için varsayıldığı gibi nil NSLocalizedString için ikinci param olarak kullanılır. Değiştirmek istediğiniz bölüm

NSLocalizedString\(@(".*?")\s*,\s*nil\) 

Sadece makro ve NSLocalizedString kullanımınızla eşleşen bir şeyle değiştirin.

İşte senaryo geliyor, sadece Bölüm 3'e ihtiyacınız var. Geri kalan her şeyin nereden geldiğini daha kolay görmektir:

// Part 1. Get keys from one of the Localizable.strings
perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings

// Part 2. Get keys from the source code
grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/'

// Part 3. Get Part 1 and 2 together.

comm -2 -3 <(grep -n -h -Eo -r  'NSLocalizedString\(@(".*?")\s*,\s*nil\)' ./ | perl -ne 'print "$1\n" if /NSLocalizedString\(@(".+")\s*,\s*nil\)/' | sort | uniq) <(perl -ne 'print "$1\n" if /^\s*(".+")\s*=/' myapp/fr.lproj/Localizable.strings | sort) | uniq >> fr-localization-delta.txt

Çıktı dosyası, kodda bulunan ancak Localizable.strings dosyasında bulunmayan anahtarlar içerir. İşte bir örnek:

"MPH"
"Map Direction"
"Max duration of a detailed recording, hours"
"Moving ..."
"My Track"
"New Trip"

Kesinlikle daha cilalanabilir, ama paylaşacağımı düşündüm.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.