NSLocalizedString'i belirli bir dili kullanmaya zorlama


Yanıtlar:


261

NSLocalizedString()(ve bunların varyantları) NSUserDefaults, kullanıcının tercih edilen diller için ayarlarının ne olduğunu belirlemek üzere "AppleLanguages" anahtarına erişir . Bu, bir dizi dil kodu döndürür, ilki telefon tarafından kullanıcı tarafından ayarlanan koddur ve daha sonra tercih edilen dilde bir kaynak yoksa sonraki kodlar yedek olarak kullanılır. (masaüstünde, kullanıcı Sistem Tercihleri'nde özel bir siparişle birden fazla dil belirtebilir)

Kendi dil listenizi ayarlamak için setObject: forKey: yöntemini kullanarak kendi uygulamanız için genel ayarı geçersiz kılabilirsiniz. Bu, genel olarak ayarlanan değere göre önceliklidir ve uygulamanızda yerelleştirme gerçekleştiren herhangi bir koda döndürülür. Bunun kodu şuna benzer:

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:@"de", @"en", @"fr", nil] forKey:@"AppleLanguages"];
[[NSUserDefaults standardUserDefaults] synchronize]; //to make the change immediate

Bu, Almanca'yı uygulamanız için tercih edilen bir dil haline getirecek, İngilizce ve Fransızca'yı yedek olarak yapacak. Bunu, uygulamanızın başlangıcında erkenden aramak istersiniz. Dil / yerel ayar tercihleri ​​hakkında daha fazla bilgiyi buradan edinebilirsiniz: Uluslararasılaştırma Programlama Konuları: Geçerli Dili ve Yerel Ayarı Alma


4
Bu benim için işe yaramıyor, ne olursa olsun varsayılan dili kullanacak.
quano

50
Denniss; Uygulama başlatılmadan önce dil tercihini ayarlarsanız daha iyi çalışıyor gibi görünüyor . Bunu UIApplicationMain () çağrılmadan önce main () işlevinde yaparım. Bir kez gerçekten çalıştığında, kullanılan dili değiştirmez, ancak bir dahaki sefere tercihi ayarlar.
geon

3
UIKit'i başlatmadan önce dili ayarlamanız ve tam bir dil + bölge yerel ayarı belirtmeniz gerekir - tam bir örnek için buna göz atın blog.federicomestrone.com/2010/09/15/…
fedmest

18
main () 'de yapılırsa AppleLanguages ​​ayarı çalışma zamanında bir dili değiştirir - true! ancak ... uygulama yüklendikten İLK KEZ, nsuserdefaults UIApplicationMain () çağrıldıktan sonra başlatılır;
JohnPayne

3
Bu, Localizable.stringsdict içinde tanımlanan çoğul öğelerle çalışmaz. Olası bir düzeltme olup olmadığı hakkında bir fikrin var mı?
Mihai Fratu

147

Son zamanlarda aynı sorunu yaşadım ve tüm NSLocalizedString'imi başlatmak ve yama yapmak istemiyordum ya da yeni dilin çalışması için uygulamayı yeniden başlatmaya zorlamıyordum . Her şeyin olduğu gibi çalışmasını istedim.

Benim çözümüm, ana paketin sınıfını dinamik olarak değiştirmek ve uygun paketi buraya yüklemekti:

Başlık dosyası

@interface NSBundle (Language)
+(void)setLanguage:(NSString*)language;
@end

uygulama

#import <objc/runtime.h>

static const char _bundle=0;

@interface BundleEx : NSBundle
@end

@implementation BundleEx
-(NSString*)localizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    NSBundle* bundle=objc_getAssociatedObject(self, &_bundle);
    return bundle ? [bundle localizedStringForKey:key value:value table:tableName] : [super localizedStringForKey:key value:value table:tableName];
}
@end

@implementation NSBundle (Language)
+(void)setLanguage:(NSString*)language
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        object_setClass([NSBundle mainBundle],[BundleEx class]);
    });
    objc_setAssociatedObject([NSBundle mainBundle], &_bundle, language ? [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]] : nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end

Temel olarak, uygulamanız başladığında ve ilk denetleyicinizi yüklemeden önce şunları aramanız yeterlidir:

[NSBundle setLanguage:@"en"];

Kullanıcınız ayar ekranınızda tercih ettiği dili değiştirdiğinde, onu tekrar arayın:

[NSBundle setLanguage:@"fr"];

Sistem varsayılanlarına sıfırlamak için nil iletmeniz yeterlidir:

[NSBundle setLanguage:nil];

Zevk almak...

Swift sürümüne ihtiyaç duyanlar için:

var bundleKey: UInt8 = 0

class AnyLanguageBundle: Bundle {

    override func localizedString(forKey key: String,
                                  value: String?,
                                  table tableName: String?) -> String {

        guard let path = objc_getAssociatedObject(self, &bundleKey) as? String,
              let bundle = Bundle(path: path) else {

            return super.localizedString(forKey: key, value: value, table: tableName)
            }

        return bundle.localizedString(forKey: key, value: value, table: tableName)
    }
}

extension Bundle {

    class func setLanguage(_ language: String) {

        defer {

            object_setClass(Bundle.main, AnyLanguageBundle.self)
        }

        objc_setAssociatedObject(Bundle.main, &bundleKey,    Bundle.main.path(forResource: language, ofType: "lproj"), .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    }
}

7
Merhaba @Wirsing, bu benim için şimdiye kadar harika çalışıyor. Hatta mağazaya bir uygulama yükledim ve Apple tarafından şikayetçi değilim.
Gilad Novik

7
Bu harika bir çözüm, buna da değiniyorum
James Tang

1
Merhaba @JamesTang, Referans ve mesajınız için teşekkürler - Orada yerelleştirme ile ilgili birçok yararlı bilgi buldum.
Gilad Novik

3
@Gilad yönteminiz dinamik dizeler (localizable.strings içinde tanımladığım dizeler) için mükemmel çalışır, ancak film şeridi düğmeleri ve etiketleri için olduğu gibi yalnızca ana yöntemle çalışır. yanıtınızı kullanıcı arayüzü denetimleri yerelleştirmesini içerecek şekilde genişletebilir misiniz? i [NSBundle setLanguage: @ "??"];
Jawad Al Shaikh

2
XIB / film şeridi için: görünümü yüklemeden ÖNCE bu yöntemi çağırdığınızdan emin olmanız gerekir. Bugüne kadar güncellenen görünümler canlı: benim durumumda sadece görünüm denetleyicisini yeniden yükledim (bir navigasyon denetleyicisine koydum ve sadece denetleyiciyi değiştirdim. Yeniden yükledikten sonra - yeni çevrilmiş dizeleri aldı). Bunun için bir cocoapod üzerinde çalışıyorum, muhtemelen bir örnek de ekleyeceğim. Bizi izlemeye devam edin ...
Gilad Novik

137

Bunu genellikle bu şekilde yaparım, ancak projenizde tüm yerelleştirme dosyalarının olması GEREKİR.

@implementation Language

static NSBundle *bundle = nil;

+(void)initialize 
{
    NSUserDefaults* defs = [NSUserDefaults standardUserDefaults];
    NSArray* languages = [defs objectForKey:@"AppleLanguages"];
    NSString *current = [[languages objectAtIndex:0] retain];
    [self setLanguage:current];
}

/*
  example calls:
    [Language setLanguage:@"it"];
    [Language setLanguage:@"de"];
*/
+(void)setLanguage:(NSString *)l
{
    NSLog(@"preferredLang: %@", l);
    NSString *path = [[ NSBundle mainBundle ] pathForResource:l ofType:@"lproj" ];
    bundle = [[NSBundle bundleWithPath:path] retain];
}

+(NSString *)get:(NSString *)key alter:(NSString *)alternate 
{
    return [bundle localizedStringForKey:key value:alternate table:nil];
}

@end

1
+1. Bu, başka hiçbir yerde görmediğim gerçekten güzel bir numara. Yerelleştirme klasörlerinden birinden bir "alt paket" oluşturarak, NSLocalizedString'i burada dolaşan bir şeyle sardığınız sürece dize öğelerinin iyi çalışmasını sağlayabilirsiniz.
Ben Zotto

4
Mükemmel Mauro. Projenizdeki dosyalar için de çalışabileceğini fark ettim. Herhangi bir nedenle (benim durumumda olduğu gibi), dizeleri dosyaları ağdan indirmeniz ve 'Belgeler' dizininizde (Belgeler / en.lproj / Localizable.strings, Belgeler / fr.lproj / Localizable.strings, ...). Bir NSBundle bile yapabilirsiniz. Bu kodu yol için kullanmanız yeterlidir: NSString * path = [NSHomeDirectory () stringByAppendingPathComponent: [NSString stringWithFormat: @ "/ Documents /% @. Lproj", l, nil]];
arnaud del.

1
Bana Alessandro'nun katkısı ile birlikte bunun en iyi yaklaşım olduğunu söylüyor. Çok müdahaleci değil ve yeniden başlatma gerektirmemelidir.
PKCLsoft

1
Neyi yanlış yapıyorum? NSObject'i devralan, bunu uygulamaya koydum, yöntem adlarını .h içine koydum, sonra [Language setLanguage: @ "es"]; Dili Değiştir Düğmemde kod çalışır (düğme yöntemi çağrılır ve Dil sınıfına gider), ancak hiçbir şey yapmaz. Ben de localizable.strings (İspanyolca) ayarladım. Ama birçok insan için çalışıyor gibi görünüyor. Lütfen birisi benim için aptal yerine koydu.
SirRupertIII

1
@KKendall şöyle deyin: [Language setLanguage: @ "es"]; NSString * stringToUse = [Dil get: @ "Metniniz" alter: nil];
Mikrasya

41

İOS 9'da kullanmayın. Bu, içinden geçen tüm dizeler için sıfır döndürür.

Uygulamayı yeniden başlatmadan ve genstrings ile uyumlu olmadan dil dizelerini güncellemenizi sağlayan başka bir çözüm buldum:

Bu makroyu Prefix.pch dosyasına koyun:

#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]

ve yerelleştirilmiş bir dize kullanımına ihtiyacınız olduğunda:

NSLocalizedStringFromTableInBundle(@"GalleryTitleKey", nil, currentLanguageBundle, @"")

Dili ayarlamak için:

[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];

Ardışık dil atlamasıyla bile çalışır:

NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"fr"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"it"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));
[[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObject:@"de"] forKey:@"AppleLanguages"];
NSLog(@"test %@", NSLocalizedStringFromTableInBundle(@"NewKey", nil, currentLanguageBundle, @""));

2
@ powerj1984: hayır, yalnızca kaynak dosyalarınızdaki dizeleri değiştirir. Xib dillerini değiştirmek istiyorsanız, xib'leri seçtiğiniz dilin demetinden elle yeniden yüklemeniz gerekir.
gklka

@gklka Tudozier tarafından verilen adımları takip ettim ama XIB'leri dili değiştirmiyor, XIB'yi elle yeniden yüklemeyi söylediğiniz gibi, aslında XIB'leri yeniden yüklemek ne anlama geliyor?
Dk Kumar

@DkKumar: Buna benzer bir şey yapmalısınız: stackoverflow.com/questions/21304988/…
gklka

@gklka Cevabınız düzeltilmiş gibi görünüyor ve cevabınızla aynı adımları attım, ancak sorun, paket yolunu, tüm kaynağı (XIB'de kullanılan .png dosyası) bulacağından daha fazla değiştirirsek Aynı paket, bu yüzden en.lproj, es.lproj ve benzeri tüm paketteki görüntüler klasörünü kopyalamamız gerekiyor. IPA boyutunu artıracak, bu sorunun üstesinden gelmenin herhangi bir yolu var mı? Gönderinizde söylediğiniz gibi, bunu deneyeyim ve size daha fazla izin vereyim Aynı şey için bana yardım ettiğiniz için teşekkürler
Dk Kumar

1
Bu, iOS 9'da korkunç bir şekilde kırıldı ve tüm dizeler için null değerini döndürdü.
Alex Zavatone

32

Daha önce de belirtildiği gibi şunları yapın:

[[NSUserDefaults standardUserDefaults] setObject: [NSArray arrayWithObjects:@"el", nil] forKey:@"AppleLanguages"];

Ancak uygulamayı yeniden başlatmak zorunda kalmamak için main.m, hemen önce UIApplicationMain(...) ana yöntemine satırı koyun .


2
Çok yardımcı cevap! PS Yeni başlayanlar için bariz gelebilir, ancak bu satırı eklemeniz gerekir, NSAutoreleasePool * pool ..aksi takdirde birkaç otomatik olarak yayınlanmış nesne sızar.
pt2ph8

1
ÖNEMLİ: Daha [[NSBundle mainBundle] URLForResource:withExtension:]önce ararsanız bu çalışmaz .
Kof

3
Swift'i kullanmaya ne dersiniz, o zaman main.m yoktur?
18'de test

@turingtested hızlı ve film şeridi üzerinde denediniz mi, çalışıyor mu?
iDevAmit

Merhaba, nasıl sunucudan gelen dinamik metin yerelleştirmek için, benim uygulamada ben basitleştirilmiş çince dilinde görüntülemek zorunda her metin, Ama ingilizce gelen çince metni görüntülemek için nasıl. bana yardım et.
Mahesh Narla

31

Uygulamadan belirli bir dili kullanma hilesi NSLocalizedString, seçilen dile bağlı olarak belirli bir paketi kullanmaya zorlamaktır.

İşte ios uygulamalarında bu öğrenme ileri yerelleştirme için yazdığım yazı

ve ios uygulamalarında bir örnek uygulama ileri yerelleştirmesinin kodu


İOS7'de de çalışıyor, Brian'ın çözümünden buna geçiş yapmalıyım, çünkü iOS tekrar dil seçeneğini geçersiz kılıyor gibi görünüyor, bu yüzden ilk kez dil ayarına bağlı kaldım. Çözümünüz bir cazibe gibi çalışıyor!
haxpor

14

Swift 3 için bu çözüm hakkında ne düşünüyorsunuz?

extension String {

    func localized(forLanguage language: String = Locale.preferredLanguages.first!.components(separatedBy: "-").first!) -> String {

        guard let path = Bundle.main.path(forResource: language == "en" ? "Base" : language, ofType: "lproj") else {

            let basePath = Bundle.main.path(forResource: "Base", ofType: "lproj")!

            return Bundle(path: basePath)!.localizedString(forKey: self, value: "", table: nil)
        }

        return Bundle(path: path)!.localizedString(forKey: self, value: "", table: nil)
    }
}

Basit kullanım:

"report".localized(forLanguage: "pl") //forced language
"report".localized() //default language selected by user in settings, in case when your app doesnt support selected lanaguage, the default one is selected, here is an english.

Merhaba, nasıl sunucudan gelen dinamik metin yerelleştirmek için, benim uygulamada ben basitleştirilmiş çince dilinde görüntülemek zorunda her metin, Ama ingilizce gelen çince metni görüntülemek için nasıl. bana yardım et.
Mahesh Narla

Bu parlak bir cevaptır;)
Bartłomiej Semańczyk

great answer.helped me
Dilip Tiwari

13

Brian Webster'ın belirttiği gibi, dilin "uygulamanızın başlamasının erken bir döneminde" ayarlanması gerekir. Düşündüğümden applicationDidFinishLaunching:ait AppDelegatetüm diğer başlatma yapın nerede beri, bunu yapmak için uygun bir yer olmalı.

Ancak William Denniss'in belirttiği gibi, bunun sadece uygulama yeniden başlatıldıktan sonra bir etkisi var gibi görünüyor , bu da işe yaramaz.

Ben olsa da, ana işlev kodu koymak iyi çalışıyor gibi görünüyor:

int main(int argc, char *argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    // Force language to Swedish.
    [[NSUserDefaults standardUserDefaults]
     setObject:[NSArray arrayWithObject:@"sv"]
     forKey:@"AppleLanguages"];

    int retVal = UIApplicationMain(argc, argv, nil, nil);
    [pool release];
    return retVal;
}

Bu konuda herhangi bir yorum için teşekkür ederiz.


benim uygulamada kullanıcı tarafından ayarlanabilen bir şey - bu yüzden sadece yeniden başlatmaları gerektiğini söyleyen bir iletişim kutusu açılır :)
William Denniss

Neredeyse herkes için çalışır - yerelleştirilmiş Default.png görüntüsü hariç.
Lukasz

2
Kullanıcıların bir dil ayarlamasına izin veriyor ve ardından uygulamayı yeniden başlatmalarını söylüyorsanız, NSUserDefaults'un çok hızlı bir şekilde yeniden başlatılması durumunda kaydedilmeyebileceğini unutmayın. Çoğu kullanıcı bu kadar hızlı değildir, ancak uygulamayı test ederken çok hızlı olabilir ve sonuç olarak tutarsız davranışlar görebilirsiniz. Dil anahtarımın neden bazen işe yarayıp yaramadığını anlamak birkaç saatimi aldı!
arlomedia

3
Bu bir sorun değil, sadece [[NSUserDefaults standardUserDefaults] synchronize];aradıktan sonra kullanınsetObject:forKey:
Ben Baron

11

En iyi Mauro Delrio'nun yöntemini seviyorum. Ayrıca aşağıdakileri Project_Prefix.pch dosyasına ekledim

#import "Language.h"    
#define MyLocalizedString(key, alt) [Language get:key alter:alt]

Bu nedenle, standart yöntemi (NSLocalizedString kullanan) kullanmak isterseniz, tüm dosyalarda hızlı bir sözdizimi ikamesi yapabilirsiniz.


1
Ben de onun yöntemini seviyorum ve ben png görüntüleri yüklemek için bir yöntem eklemek: + (UIImage ) imageNamed: (NSString *) imageFileName {NSString fullPath = [paket yoluForResource: imageFileName ofType: @ "png"]; UIImage * imageObj = [[UIImage ayırma] initWithContentsOfFile: fullPath]; dönüş [imageObj autorelease]; }
Jagie

11

NSLocalizedString()anahtarın değerini AppleLanguagesstandart kullanıcı varsayılanlarından ( [NSUserDefaults standardUserDefaults]) okur . Çalışma zamanında mevcut tüm yerelleştirmeler arasında uygun bir yerelleştirme seçmek için bu değeri kullanır. Apple, uygulama başlatma sırasında kullanıcı varsayılan sözlüğünü oluşturduğunda, sistem tercihlerinde tercih edilen dil (ler) anahtarını arar ve değeri oradan kopyalar. Bu aynı zamanda örneğin OS X'te dil ayarlarının değiştirilmesinin uygulamaları çalıştırmak için neden hiçbir etkisi olmadığını, yalnızca bundan sonra başlatılan uygulamalar üzerinde de açıklamaktadır. Kopyalandıktan sonra değer, ayarlar değiştiği için güncellenmez. Bu nedenle, dilden sonra değiştirirseniz iOS tüm uygulamaları yeniden başlatır.

Ancak, kullanıcı varsayılanları sözlüğünün tüm değerlerinin üzerine komut satırı bağımsız değişkenleri yazılabilir. NSUserDefaultsÜzerindeki belgelere bakın NSArgumentDomain. Bu, uygulama tercihleri ​​(.plist) dosyasından yüklenen değerleri de içerir. Test için bir değeri değiştirmek isteyip istemediğinizi bilmek gerçekten çok iyi .

Dili test etmek için değiştirmek isterseniz, muhtemelen kodunuzu değiştirmek istemezsiniz (bu kodu daha sonra kaldırmayı unutursanız ...), bunun yerine Xcode'a uygulamanızı bir komut satırı parametreleriyle başlatmasını söyleyin ( örneğin İspanyolca yerelleştirmeyi kullanın):

resim açıklamasını buraya girin

Kodunuza dokunmanıza gerek yok. Sadece farklı diller için farklı şemalar oluşturun ve sadece şemayı değiştirerek uygulamayı bir kez bir dilde ve bir başka dilde bir kez hızlı bir şekilde başlatabilirsiniz.


Sadece 1. kez çalışır, daha sonra tekrar cihaz tercihine yüklenir. dil ..
Aks

@Aks Benim için her zaman çalışır. Doğru şemayı başlattığınızdan emin olun, Xcode'dan (yeniden başlatmalar, çatallar vb.) Argümanı alamayacağınızdan emin olun ve OptionsApple'ın sunduğu daha yeni Xcode sürümlerinde olduğu gibi dili geçersiz kılmadığınızdan emin olun . de.
Mecki

Cevabınız için teşekkürler @Mecki .. Benim için onun xcode çalışmıyor ama kod bahsettiğimde, işe yarıyor .. Ama yine de cihazımı diğer bazı tercih edilen dillerle ayarladıysam, tercih ettiğime yüklemek için uygulamayı yeniden başlatması gerekiyor tartıştığım dil ....
Aks

@Aks Bunu bir cihazda kullanırken, yalnızca doğrudan Xcode'dan başlatıldığında çalışır, bazı cihazlarda simgesine dokunarak uygulamayı yeniden başlattığınızda çalışmaz ve uygulama öldürüldüğünde de çalışmaz (ör. çünkü arka plana gitti) ve sistem tarafından yeniden başlatıldığından (bu yeniden başlatma Xcode tarafından yapılan bir yeniden başlatma olmadığından) - bu nedenle, iOS uygulamanızı arada öldürmek zorunda kalırsa farklı bir uygulamaya ve geri geçiş çalışmayabilir (ör. bellek gerekiyor).
Mecki

10

Kullanmanıza izin veren bir çözüm buldum NSLocalizedString. Bir NSBundlearama kategorisi oluşturuyorum NSBundle+RunTimeLanguage. Arayüz böyle.

// NSBundle+RunTimeLanguage.h
#import <Foundation/Foundation.h>
@interface NSBundle (RunTimeLanguage)
#define NSLocalizedString(key, comment) [[NSBundle mainBundle] runTimeLocalizedStringForKey:(key) value:@"" table:nil]
- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName;
@end

Uygulama böyle.

// NSBundle+RunTimeLanguage.m
#import "NSBundle+RunTimeLanguage.h"
#import "AppDelegate.h"

@implementation NSBundle (RunTimeLanguage)

- (NSString *)runTimeLocalizedStringForKey:(NSString *)key value:(NSString *)value table:(NSString *)tableName
{
    AppDelegate *appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    NSString *path= [[NSBundle mainBundle] pathForResource:[appDelegate languageCode] ofType:@"lproj"];
    NSBundle *languageBundle = [NSBundle bundleWithPath:path];
    NSString *localizedString=[languageBundle localizedStringForKey:key value:key table:nil];
    return localizedString;
}
@end

Daha NSBundle+RunTimeLanguage.hsonra, kullanılan dosyalara içe aktarma ekleyin NSLocalizedString.

Gördüğünüz gibi languageCode'umu bir özellikte saklıyorum AppDelegate. Bu istediğiniz bir yerde saklanabilir.

Bu konuda sevmediğim tek şey NSLocalizedStringmarco'nun yeniden tanımladığı bir Uyarı . Belki birisi bu parçayı düzeltmeme yardımcı olabilir.


1
Uyarıyı devre dışı bırakmak için #undef NSLocalizedStringhemen ekleyin#define
berilyum

Bu xib dosyası için yerelleştirme üzerinde çalışıyor mu? Kullanıcı arabirimi adını belirli bir dilde çevirmek için .xib dosyası ve .strings var. Denedim ve XIB ile çalışmıyor ama işleri doğru bir şekilde yaptım mı emin değilim
Kong Hantrakool

Kong geciken cevap için özür dilerim. Bu NSLocalizedString kullandığınız her yerde çalışır. Dolayısıyla doğrudan XIB'de çalışmaz. XIB içindeki dizelere IBOutlet'lere ihtiyacınız olacak ve daha sonra kod içinde dize değerlerini programlı olarak ayarlamanız gerekecektir.
qman64

Bu yaklaşım benim için işe yaradı ve anında dilleri değiştirebildim. "Es", fr "ve" en "gibi dil kodlarının iyi çalıştığını unutmayın. Ancak" zh "(Basitleştirilmiş Çince için) başarısız oldu ve bana boş dizeler verdi. Sistemimde" es.lproj "için global bir arama yaptım eriştiğim dosyaların nerede olduğunu görün ve orada "zh.lproj" aslında "zh-Hans.lproj" olduğunu keşfettim.
Gallymon

9

Hızlı Sürüm:

NSUserDefaults.standardUserDefaults().setObject(["fr"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()

8

Kısaca :

Uygulamanızı yerelleştirin

Yapmanız gereken ilk şey, uygulamanızı en az iki dilde yerelleştirmek (bu örnekte İngilizce ve Fransızca).

NSLocalizedString'i geçersiz kıl

Kodunuzda, kullanmak yerine şu şekilde tanımlanmış NSLocalizedString(key, comment)bir makro kullanın MYLocalizedString(key, comment): #define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];

Bu MYLocalizationSystemsingleton:

  • Doğru yerelleştirilmiş NSBundle kullanıcısının istediği şekilde ayarlayarak dili ayarlayın
  • Önceden ayarlanan bu dile göre yerelleştirilmiş NSString'i döndürür

Kullanıcı dilini ayarla

Kullanıcı uygulama dilini Fransızca olarak değiştirdiğinde, [[MYLocalizationSystem sharedInstance] setLanguage:@"fr"];

- (void)setLanguage:(NSString *)lang
{
    NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj"];
    if (!path)
    {
        _bundle = [NSBundle mainBundle];
        NSLog(@"Warning: No lproj for %@, system default set instead !", lang);
        return;
    }

    _bundle = [NSBundle bundleWithPath:path];
}

Bu örnekte bu yöntem, yerelleştirilmiş paketi fr.lproj olarak ayarlar

Yerelleştirilmiş dize döndür

Yerelleştirilmiş paketi ayarladıktan sonra, bu yöntemle ondan doğru yerelleştirilmiş dizeyi alabilirsiniz:

- (NSString *)localizedStringForKey:(NSString *)key value:(NSString *)value
{
    // bundle was initialized with [NSBundle mainBundle] as default and modified in setLanguage method
    return [self.bundle localizedStringForKey:key value:value table:nil];
}

Umarım bu size yardımcı olacaktır.

Bu makalede NSWinery.io'dan daha fazla ayrıntı bulacaksınız.


Sadece cevabınızdaki bir çözüme bağlantı vermenizi istemiyoruz; bağlantı bir gün çalışmayı durdurabilir. Bağlantıyı cevabınızdan kaldırmak zorunda olmasanız da, cevabınızı bağlantılı makalenin ilgili bölümünün bir özetini içerecek şekilde düzenlemenizi rica ediyoruz.
Kayıtsız Adaçayı

7

Swift 3 uzantıları:

extension Locale {
    static var preferredLanguage: String {
        get {
            return self.preferredLanguages.first ?? "en"
        }
        set {
            UserDefaults.standard.set([newValue], forKey: "AppleLanguages")
            UserDefaults.standard.synchronize()
        }
    }
}

extension String {
    var localized: String {

    var result: String

    let languageCode = Locale.preferredLanguage //en-US

    var path = Bundle.main.path(forResource: languageCode, ofType: "lproj")

    if path == nil, let hyphenRange = languageCode.range(of: "-") {
        let languageCodeShort = languageCode.substring(to: hyphenRange.lowerBound) // en
        path = Bundle.main.path(forResource: languageCodeShort, ofType: "lproj")
    }

    if let path = path, let locBundle = Bundle(path: path) {
        result = locBundle.localizedString(forKey: self, value: nil, table: nil)
    } else {
        result = NSLocalizedString(self, comment: "")
    }
        return result
    }
}

Kullanımı:

Locale.preferredLanguage = "uk"

label.text = "localizedKey".localized

Teşekkürler. İyi çalışıyor.
Krunal Nagvadia

5

Tanımlamak için .pch dosyasında :

#define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]


#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")

'Ovverride ...' uyarısından nasıl kurtulurum?
Idan Moshe

1
Basit çözüm ihtiyacım olan her şeyi yapar. Bu sorunu çözmek için bir rehber olarak kullanabildi. Bir yerelleştirme dosyası olmadığından pathForResource nil döndürürse, ben denedim başka hiçbir şey temel yerelleştirme dizeleri çeker beri pathForResource: @ "Base" kullanın. Teşekkür ederim.
GRW

Bu hacky (diğer tüm cevaplar da öyle) ve yazdığım birim testinde uygulamak en kolaydı.
Maksimum

4

Belki de bunu tamamlamanız gerekir (#import'tan sonra .pch dosyasında):

extern NSBundle* bundle; // Declared on Language.m

#ifdef NSLocalizedString
    #undef NSLocalizedString
    // Delete this line to avoid warning
    #warning "Undefining NSLocalizedString"
#endif

#define NSLocalizedString(key, comment) \
    [bundle localizedStringForKey:(key) value:@"" table:nil]

/Users/pwang/Desktop/Myshinesvn/Myshine/viewController/OrientationReadyPagesView.m:193:31: Bildirilmemiş tanımlayıcı 'paket' kullanımı
pengwang

4

Swift 3 çözümü:

let languages = ["bs", "zh-Hant", "en", "fi", "ko", "lv", "ms", "pl", "pt-BR", "ru", "sr-Latn", "sk", "es", "tr"]
UserDefaults.standard.set([languages[0]], forKey: "AppleLanguages")

Kullanılabilecek bazı dil kodlarına örnekler verin. Bu yardımcı olur umarım


3

Bunu yapmak istediğiniz yerelleştirilmiş dizeler kümesiyle bir alt paket oluşturabilir ve sonra NSLocalizedStringFromTableInBundle()bunları yüklemek için kullanabilirsiniz . (Bunun, uygulamada yapabileceğiniz normal kullanıcı arayüzü yerelleştirmesinden ayrı bir içerik olduğunu varsayıyorum.)


3

benim durumum için iki yerel dosya var, ja ve tr

ve sistemde tercih edilen dil ne en ne de ja ise bunu en

main.m dosyasını düzenleyeceğim

ilk tercih edilen en veya ja olup olmadığını kontrol edeceğim, eğer değilse ikinci tercih edilen dili en olarak değiştireceğim.

int main(int argc, char *argv[])
{

    [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"AppleLanguages"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    NSString *lang = [[NSLocale preferredLanguages] objectAtIndex:0];

    if (![lang isEqualToString:@"en"]  &&  ![lang isEqualToString:@"ja"]){

        NSMutableArray *array = [[NSMutableArray alloc] initWithArray:[NSLocale preferredLanguages]];
        [array replaceObjectAtIndex:1 withObject:@"en"];

        [[NSUserDefaults standardUserDefaults] setObject:array forKey:@"AppleLanguages"];
        [[NSUserDefaults standardUserDefaults] synchronize];


    }

    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));


    }


}

Teşekkürler @ chings228 benim için yararlı, ama bu uygulama için varsayılan başlatma görüntüsünü (sıçrama) değişmez Ben her dil için farklı sıçramalar var. Bunun için nasıl başvuracağınızı biliyor musunuz?
JERC

Ben sıçrama ana program çalışmaya başlamadan önce çalışır düşünüyorum, bu yüzden nasıl geçersiz kılmayı bilmiyorum, plist yardımcı olabilir ama uygulama bir dahaki sefere çalışabilir
chings228

2

Bunun gibi bir şey yapabilirsiniz:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];


NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];

NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):

2

Dayanarak Tudorizer en olmaksızın değişiklik diline cevap bırakarak veya yeniden başlatarak uygulamayı.

Makro yerine, belirli bir dil kodunun bulunup bulunmadığını kontrol etmek için tercih edilen dile erişmek için bir sınıf kullanın.

Aşağıda, iOS 9 için çalışan geçerli dil paketini elde etmek için kullanılan bir sınıf bulunmaktadır:

@implementation OSLocalization

+ (NSBundle *)currentLanguageBundle
{
    // Default language incase an unsupported language is found
    NSString *language = @"en";

    if ([NSLocale preferredLanguages].count) {
        // Check first object to be of type "en","es" etc
        // Codes seen by my eyes: "en-US","en","es-US","es" etc

        NSString *letterCode = [[NSLocale preferredLanguages] objectAtIndex:0];

        if ([letterCode rangeOfString:@"en"].location != NSNotFound) {
            // English
            language = @"en";
        } else if ([letterCode rangeOfString:@"es"].location != NSNotFound) {
            // Spanish
            language = @"es";
        } else if ([letterCode rangeOfString:@"fr"].location != NSNotFound) {
            // French
            language = @"fr";
        } // Add more if needed
    }

    return [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:language ofType:@"lproj"]];
}

/// Check if preferred language is English
+ (BOOL)isCurrentLanguageEnglish
{
    if (![NSLocale preferredLanguages].count) {
        // Just incase check for no items in array
        return YES;
    }

    if ([[[NSLocale preferredLanguages] objectAtIndex:0] rangeOfString:@"en"].location == NSNotFound) {
        // No letter code for english found
        return NO;
    } else {
        // Tis English
        return YES;
    }
}

/*  Swap language between English & Spanish
 *  Could send a string argument to directly pass the new language
 */
+ (void)changeCurrentLanguage
{
    if ([self isCurrentLanguageEnglish]) {
        [[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];
    } else {
        [[NSUserDefaults standardUserDefaults] setObject:@[@"en"] forKey:@"AppleLanguages"];
    }
}
@end

Bir dize dosyasına / image / video / etc'ye başvurmak için yukarıdaki sınıfı kullanın:

// Access a localized image
[[OSLocalization currentLanguageBundle] pathForResource:@"my_image_name.png" ofType:nil]
// Access  a localized string from Localizable.strings file
NSLocalizedStringFromTableInBundle(@"StringKey", nil, [OSLocalization currentLanguageBundle], @"comment")

Aşağıdaki gibi satır içi dili değiştirin veya yeni dile başvuruda bulunan bir dize parametresi almak için yukarıdaki sınıftaki "changeCurrentLanguage" yöntemini güncelleyin.

[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];

2

Hızlı 4'te, kütüphaneleri yeniden başlatmaya veya kullanmaya gerek kalmadan çözdüm.

Birçok seçeneği denedikten sonra, çevirmek istediğiniz stringToLocalize (Localizable.String, dizeler dosyası) ilettiğiniz bu işlevi buldum ve çevirmek istediğiniz dil ve döndürdüğü değer Dizeler dosyasında bulunan Dize:

    func localizeString (stringToLocalize: String, language: String) -> String
    {
        let path = Bundle.main.path (forResource: language, ofType: "lproj")
        let languageBundle = Bundle (path: path!)
        return languageBundle! .localizedString (forKey: stringToLocalize, value: "", table: nil)
    }

Bu işlevi göz önünde bulundurarak, bir Swift dosyasında bu işlevi oluşturdum:

struct CustomLanguage {

    func createBundlePath () -> Bundle {
        let selectedLanguage = //recover the language chosen by the user (in my case, from UserDefaults)
        let path = Bundle.main.path(forResource: selectedLanguage, ofType: "lproj")
        return Bundle(path: path!)!
    }
}

Tüm uygulamadan ve ViewControllers'ın geri kalanının her bir dizesine koymak yerine erişmek için:

NSLocalizedString ("StringToLocalize", comment: ")

Onunla değiştirdim

let customLang = CustomLanguage() //declare at top
let bundleLanguage = customLang.createBundle()

NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String

En iyi yol olup olmadığını bilmiyorum, ama çok basit buldum ve benim için çalışıyor, umarım size yardımcı olur!


1

Bu işlev geçerli dil için yerelleştirilmiş dize almaya çalışır ve bulunmazsa ingilizce dili kullanarak alır.

- (NSString*)L:(NSString*)key
{
    static NSString* valueNotFound = @"VALUE_NOT_FOUND";
    static NSBundle* enBundle = nil;

    NSString* pl = [NSLocale preferredLanguages][0];
    NSString* bp = [[NSBundle mainBundle] pathForResource:pl ofType:@"lproj"];
    NSBundle* b = [NSBundle bundleWithPath:bp];

    NSString* s = [b localizedStringForKey:key value:valueNotFound table:nil];
    if ( [s isEqualToString:valueNotFound] ) {
        if ( !enBundle ) {
            bp = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
            enBundle = [NSBundle bundleWithPath:bp];
        }
        s = [enBundle localizedStringForKey:key value:key table:nil];
    }

    return s;
}

1

Resmi olarak iOS tarafından desteklenmeyen bir dile destek eklemek istedim (sistem ayarları altındaki Dil bölümünde listelenmiyor). Takip ederek Apple'ın Uluslararasılaşma Eğitimi Brian Webster ve geonların tarafından burada ve birkaç ipucu, kod (main.m koymak) bu parça ile geldi:

int main(int argc, char * argv[]) {
    @autoreleasepool {
        // Grab regional settings locale, for Slovenian this is either sl_SI or en_SI
        NSLocale *locale = [NSLocale currentLocale];
        NSString *ll = [locale localeIdentifier]; // sl_SI

        // Grab the first part of language identifier
        NSArray *comp = [ll componentsSeparatedByString:@"_"];
        NSString *ll1 = @"en";
        if (comp.count > 0) {
            ll1 = comp[0]; // sl, en, ...
        }
        // Check if we already saved language (user can manually change it inside app for example)
        if (![[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"]) {
            //   Slovenian (Slovenia),            Slovenia
            if ([ll isEqualToString:@"sl_SI"] || [ll isEqualToString:@"en_SI"]) {
                ll1 = @"sl-SI"; // This is the part of localized path for Slovenian language that Xcode generates
            }
            // Add more unsupported languages here...

            [[NSUserDefaults standardUserDefaults] setObject:ll1 forKey:@"SelectedLanguage"]; // Save language
        }
        else {
            // Restore language as we have previously saved it
            ll1 = [[NSUserDefaults standardUserDefaults] objectForKey:@"SelectedLanguage"];
        }
        // Overwrite NSLocalizedString and StoryBoard language preference
        [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:ll1, @"en", @"fr", nil] forKey:@"AppleLanguages"];
        // Make sure settings are stored to disk
        [[NSUserDefaults standardUserDefaults] synchronize];

        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

Bu hem Storyboard hem de NSLocalizedString kodu için iyi çalışır. Kod, kullanıcının uygulama içindeki dili daha sonra manuel olarak değiştirme seçeneğine sahip olacağını varsayar.

Tabii ki, uygun Storyboard çevirilerini ve Localizable.strings çevirilerini eklemeyi unutmayın (bunun nasıl yapılacağı için yukarıdaki Apple sayfasına bağlantıya bakın).


Sloven diliyle ilgili sorunlarla da karşılaştığınızı görüyorum :) iOS tarafından desteklenmeyen diller için bu yanıtı geliştirmek için, uygulamadaki sistem kontrolleri için kullanılacak özel yerelleştirilebilir dizeler ayarlayıp ayarlayamayacağımızı anladınız mı (Düzenle, Bitti, Daha fazla, ...)?
miham

1

İşte bu sorun için iyi bir çözüm ve uygulamanın yeniden başlatılmasını gerektirmez.

https://github.com/cmaftuleac/BundleLocalization

Bu uygulama NSBundle içinde ince ayar yaparak çalışır. Buradaki fikir, NSBundle nesnesi örneğinde localizedStringForKey yöntemini geçersiz kılmanız ve daha sonra bu yöntemi farklı bir dil içeren farklı bir pakette çağırmanızdır. Basit ve zarif, her türlü kaynakla tamamen uyumludur.


Projedeki bu kod bana çok yardımcı oldu. Belirli bir dil kodu için bir paket nasıl bulunurNSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
Eonil

Bu sınıf iyi çalışıyor, ancak dili başka birine değiştirdikten sonra etkilemiyor.
anilkumar iOS ReactNative

0

ne yaparsanız yapın, en iyi yol belirtilen dil için kısa_adı almaktır, yani: fr, en, nl, de, it, vb ... ve aynısını global bir değere atamaktır.

aşağı açılır bir menü (seçicinin aşağıdan bir dil görünümü ile birlikte göründüğü bir düğmenin kombinasyonu) açılır bir pencere gibi görünmesi için bir seçici görünüm yapın ve istediğiniz dili seçin. kısa adın dahili olarak saklanmasına izin verin. LocalisedString adlı bir .h + .m dosyası oluşturun.

Short_name öğesinin genel değerini LocalisedString.m dosyasında elde edilen değere eşit olacak şekilde ayarlayın. Gerekli dil seçildiğinde NSBundlePath'i gerekli dil için proje alt dizinleri oluşturmak üzere atayın. örneğin, nl.proj, en.proj.

Belirli bir proje klasörü seçildiğinde, ilgili dil için yerelleştirilmiş dizeyi arayın ve dili dinamik olarak değiştirin.

kurallar çiğnenmez.


0

Swift için, main.swiftuygulamayı çalıştırmadan önce dosyayı geçersiz kılabilir ve UserDefaults dizesini ayarlayabilirsiniz. Bu şekilde, istenen efekti görmek için Uygulamayı yeniden başlatmanız gerekmez.

import Foundation
import UIKit

// Your initialisation code here
let langCultureCode: String = "LANGUAGE_CODE"

UserDefaults.standard.set([langCultureCode], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()

UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(AppDelegate.self))

kaldırılması ile birlikte eşleştirilmiş @UIApplicationMainsizin de AppDelegate.swiftdosyaya.

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.