Cara memaksa NSLocalizedString untuk menggunakan bahasa tertentu

Jawaban:

261

NSLocalizedString()(dan variasinya) mengakses kunci "AppleLanguages" NSUserDefaultsuntuk menentukan pengaturan pengguna untuk bahasa yang diinginkan. Ini mengembalikan array kode bahasa, dengan yang pertama ditetapkan oleh pengguna untuk telepon mereka, dan yang berikutnya digunakan sebagai cadangan jika sumber daya tidak tersedia dalam bahasa yang disukai. (pada desktop, pengguna dapat menentukan beberapa bahasa dengan pemesanan khusus di System Preferences)

Anda dapat mengganti pengaturan global untuk aplikasi Anda sendiri jika ingin menggunakan metode setObject: forKey: untuk mengatur daftar bahasa Anda sendiri. Ini akan diutamakan daripada nilai yang ditetapkan secara global dan dikembalikan ke kode apa pun dalam aplikasi Anda yang melakukan pelokalan. Kode untuk ini akan terlihat seperti:

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

Ini akan menjadikan Jerman bahasa pilihan untuk aplikasi Anda, dengan bahasa Inggris dan Prancis sebagai mundur. Anda ingin memanggil ini di awal startup aplikasi Anda. Anda dapat membaca lebih lanjut tentang preferensi bahasa / lokal di sini: Topik Pemrograman Internasionalisasi: Mendapatkan Bahasa dan Lokal Saat Ini

Brian Webster
sumber
4
Ini tidak berfungsi untuk saya, itu akan menggunakan bahasa default tidak peduli apa.
quano
50
Denniss; Tampaknya berfungsi lebih baik jika Anda mengatur preferensi bahasa sebelum aplikasi diluncurkan. Saya melakukannya di fungsi main (), sebelum UIApplicationMain () dipanggil. Setelah benar-benar berjalan, itu tidak akan mengubah bahasa yang digunakan, tetapi hanya mengatur preferensi untuk waktu berikutnya.
geon
3
Anda harus mengatur bahasa sebelum menginisialisasi UIKit dan Anda harus menentukan bahasa lengkap + wilayah lokal - lihat ini untuk contoh lengkap blog.federicomestrone.com/2010/09/15/…
fedmest
18
pengaturan AppleLanguages ​​akan mengubah bahasa saat runtime jika dilakukan di main () - true! tapi ... WAKTU PERTAMA aplikasi terinstal, kesalahan nsuserdisialisasi diinisialisasi SETELAH UIAplikasiMain () dipanggil, yang akan mengabaikan AppleLanguages ​​yang sebelumnya ditetapkan dan akan membutuhkan restart paksa jelek dari aplikasi untuk melihat bahasa yang diinginkan.
JohnPayne
3
Ini tidak berfungsi dengan item jamak yang didefinisikan dalam Localizable.stringsdict. Adakah yang tahu jika ada kemungkinan perbaikan?
Mihai Fratu
147

Saya memiliki masalah yang sama baru-baru ini dan saya tidak ingin memulai dan menambal seluruh NSLocalizedString atau memaksa aplikasi untuk memulai kembali agar bahasa baru berfungsi. Saya ingin semuanya berjalan apa adanya.

Solusi saya adalah mengubah kelas bundel utama secara dinamis dan memuat bundel yang sesuai di sana:

File tajuk

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

Penerapan

#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

Jadi pada dasarnya, ketika aplikasi Anda mulai dan sebelum Anda memuat controller pertama Anda, cukup hubungi:

[NSBundle setLanguage:@"en"];

Ketika pengguna Anda mengubah bahasa pilihannya di layar pengaturan Anda, cukup panggil lagi:

[NSBundle setLanguage:@"fr"];

Untuk mengatur ulang ke default sistem, cukup lewati nol:

[NSBundle setLanguage:nil];

Nikmati...

Bagi mereka yang membutuhkan versi Swift:

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)
    }
}
Gilad Novik
sumber
7
Hai @ Berputar-putar, ini bagus untuk saya sejauh ini. Saya bahkan telah mengunggah satu aplikasi ke toko dan tidak ada keluhan dari Apple.
Gilad Novik
7
Ini adalah solusi yang bagus, saya juga merujuk ini di sini: medium.com/ios-apprentice/905e4052b9de
James Tang
1
Hai @JamesTang, Terima kasih atas referensi dan kiriman Anda - Saya menemukan banyak informasi berguna mengenai pelokalan.
Gilad Novik
3
@Gilad metode Anda berfungsi sempurna untuk string dinamis (string yang saya definisikan di localizable.strings) tetapi untuk tombol storyboard dan labelnya hanya berfungsi pada metode utama saja. jadi bisakah Anda memperluas jawaban untuk menyertakan pelokalan kontrol UI? maksud saya bagaimana me-refresh storyboard (tanpa menutup) setelah saya memohon [NSBundle setLanguage: @ "??"] ;?
Jawad Al Shaikh
2
Adapun XIB / storyboard: Anda harus memastikan Anda memanggil metode ini SEBELUM Anda memuat tampilan. Sejauh memperbarui pandangan hidup: dalam kasus saya, saya hanya memuat kembali pengontrol tampilan (saya memasukkannya ke dalam pengontrol navigasi dan hanya mengganti pengontrol. Setelah memuat ulang - itu mendapat string yang diterjemahkan baru). Saya sedang mengerjakan cocoapod untuk itu, saya mungkin akan menyertakan contoh di sana juga. Tetap disini ...
Gilad Novik
137

Saya biasanya melakukan ini dengan cara ini, tetapi Anda HARUS memiliki semua file pelokalan dalam proyek Anda.

@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
Mauro Delrio
sumber
1
+1. Ini adalah trik yang sangat bagus yang belum pernah saya lihat di tempat lain. Dengan membuat "sub bundel" dari salah satu folder pelokalan, Anda bisa membuat hal-hal string berfungsi dengan baik selama Anda membungkus NSLocalizedString dengan sesuatu yang berbelok di sini.
Ben Zotto
4
Mauro yang luar biasa. Saya perhatikan bahwa itu juga dapat berfungsi untuk file dari proyek Anda. Jika karena alasan tertentu (seperti dalam kasus saya), Anda perlu mengunduh file string dari jaringan, dan menyimpannya di direktori 'Dokumen' (dengan struktur folder Dokumen / id.lproj / Localizable.strings, Dokumen / fr.lproj / Localizable.strings, ...). Anda bahkan dapat membuat NSBundle. Cukup gunakan kode ini untuk path: NSString * path = [NSHomeDirectory () stringByAppendingPathComponent: [NSString stringWithFormat: @ "/ Documents /% @. Lproj", l, nil]];
arnaud del.
1
Menurut saya ini adalah pendekatan terbaik, bersama dengan kontribusi dari Alessandro di bawah ini. Itu tidak begitu mengganggu dan tidak perlu di-restart.
PKCLsoft
1
Apa yang saya lakukan salah? Saya membuat kelas Bahasa, mewarisi NSObject, memasukkan ini ke dalam implementasi, memasukkan nama metode ke dalam .h, lalu memasukkan [Bahasa setLanguage: @ "es"]; di Ubah Bahasa Tombol saya, kode berjalan (metode tombol dipanggil, dan pergi ke kelas Bahasa), tetapi tidak melakukan apa-apa. Saya telah mengatur localizable.strings (Spanyol) saya juga. Tetapi tampaknya itu bekerja untuk banyak orang lain. Tolong, seseorang membodohi saya.
SirRupertIII
1
@KKemungkinkah Anda menyebutnya seperti ini: [Language setLanguage: @ "es"]; NSString * stringToUse = [Bahasa dapatkan: @ "Teks Anda" ubah: nil];
Mikrasya
41

Jangan gunakan di iOS 9. Ini mengembalikan nol untuk semua string melewatinya.

Saya telah menemukan solusi lain yang memungkinkan Anda untuk memperbarui string bahasa, tanpa memulai ulang aplikasi dan kompatibel dengan genstrings:

Letakkan makro ini di Prefix.pch:

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

dan di mana pun Anda membutuhkan penggunaan string lokal:

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

Untuk mengatur penggunaan bahasa:

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

Bekerja bahkan dengan hopping bahasa berurutan seperti:

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, @""));
Tudor
sumber
2
@ powerj1984: tidak, itu hanya akan mengubah string dalam file sumber Anda. Jika Anda ingin mengubah bahasa xib, Anda harus memuat ulang xibs dengan tangan, dari bundel bahasa yang Anda pilih.
gklka
@gklka Saya telah mengikuti langkah-langkah yang diberikan oleh Tudozier tetapi XIB saya tidak mengubah bahasa, seperti yang Anda katakan memuat ulang XIB dengan tangan, apa artinya sebenarnya untuk memuat ulang XIB?
Dk Kumar
@DkKumar: Anda harus melakukan sesuatu yang mirip dengan ini: stackoverflow.com/questions/21304988/…
gklka
@gklka Jawaban Anda tampaknya benar dan saya telah melakukan langkah-langkah yang sama seperti yang Anda uraikan dalam jawaban Anda, tetapi apa masalahnya adalah jika kita mengubah jalur bundel daripada akan menemukan semua sumber daya (yaitu file .png yang digunakan dalam XIB) di bundel yang sama, jadi kita harus menyalin folder gambar secara berlebihan di semua bundel seperti en.lproj, es.lproj dan seterusnya .. jadi akan berpengaruh pada peningkatan ukuran IPA, jadi apakah ada cara untuk mengatasi masalah ini? seperti yang Anda katakan di posting Anda, izinkan saya mencoba ini dan izinkan Anda lebih lanjut tentang ini. Terima kasih telah membantu saya untuk hal yang sama
Dk Kumar
1
Ini rusak parah di iOS 9, mengembalikan nol untuk semua string.
Alex Zavatone
32

Seperti yang dikatakan sebelumnya, lakukan saja:

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

Tetapi untuk menghindari keharusan me-restart aplikasi, letakkan baris pada metode utama main.m, sesaat sebelum UIApplicationMain(...).

Frédéric Feytons
sumber
2
Jawaban yang sangat membantu! PS Mungkin terdengar jelas bagi yang bukan pemula, tetapi Anda harus memasukkan garis itu setelah NSAutoreleasePool * pool ..atau beberapa objek autoreleased akan bocor.
pt2ph8
1
PENTING: Ini tidak akan berfungsi jika Anda menelepon [[NSBundle mainBundle] URLForResource:withExtension:]sebelumnya.
Kof
3
Bagaimana jika menggunakan Swift, maka tidak ada main.m?
turingtested
@turingtested, apakah Anda sudah mencoba swift dan storyboard, apakah ini berfungsi?
iDevAmit
Hai, Bagaimana cara melokalkan teks dinamis yang berasal dari server, dalam aplikasi saya setiap teks harus saya tampilkan dalam bahasa Cina yang disederhanakan, Tetapi bagaimana cara menampilkan teks dalam bahasa Cina yang berasal dari bahasa Inggris. tolong aku.
Mahesh Narla
31

Trik untuk menggunakan bahasa tertentu dengan memilihnya dari aplikasi adalah memaksa NSLocalizedStringuntuk menggunakan bundel tertentu tergantung pada bahasa yang dipilih,

di sini adalah posting yang telah saya tulis untuk lokalisasi muka pembelajaran ini di aplikasi ios

dan di sini adalah kode satu contoh lokalisasi muka aplikasi di aplikasi ios

object2.0
sumber
Ini berfungsi di iOS7 juga, saya harus beralih dari solusi Brian untuk ini karena sepertinya iOS mengabaikan opsi bahasa lagi sehingga saya terjebak dengan pengaturan bahasa pertama kali. Solusi Anda bekerja seperti pesona!
haxpor
14

Apa pendapat Anda tentang solusi ini untuk Swift 3?

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)
    }
}

Penggunaan sederhana:

"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.
Bartłomiej Semańczyk
sumber
Hai, Bagaimana cara melokalkan teks dinamis yang berasal dari server, dalam aplikasi saya setiap teks harus saya tampilkan dalam bahasa Cina yang disederhanakan, Tetapi bagaimana cara menampilkan teks dalam bahasa Cina yang berasal dari bahasa Inggris. tolong aku.
Mahesh Narla
Ini adalah jawaban yang brilian;)
Bartłomiej Semańczyk
jawaban yang bagus. Membantu saya
Dilip Tiwari
13

Seperti yang disebutkan Brian Webster, bahasa perlu diatur "kapan saja lebih awal dalam startup aplikasi Anda". Saya pikir applicationDidFinishLaunching:dari AppDelegateseharusnya menjadi tempat yang cocok untuk melakukannya, karena itu di mana aku melakukan semua inisialisasi lainnya.

Tetapi seperti yang disebutkan oleh William Denniss, itu tampaknya memiliki efek hanya setelah aplikasi di-restart, yang agak tidak berguna.

Tampaknya berfungsi dengan baik jika saya meletakkan kode di fungsi utama, meskipun:

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;
}

Saya menghargai komentar ini.

geon
sumber
dalam implementasi saya ini adalah hal yang dapat diatur pengguna - jadi saya hanya memunculkan dialog yang memberi tahu mereka bahwa mereka harus memulai ulang :)
William Denniss
Ini berfungsi, hampir untuk semua - kecuali untuk gambar Default.png lokal.
Lukasz
2
Jika Anda membiarkan pengguna mengatur bahasa dan kemudian memberi tahu mereka untuk memulai ulang aplikasi, ingatlah bahwa NSUserDefaults mungkin tidak disimpan jika mereka memulai ulang terlalu cepat. Sebagian besar pengguna tidak secepat ini, tetapi ketika Anda menguji aplikasi Anda mungkin terlalu cepat dan melihat perilaku yang tidak konsisten sebagai hasilnya. Saya butuh beberapa jam untuk menyadari mengapa pergantian bahasa saya kadang-kadang berhasil dan kadang tidak!
arlomedia
3
Itu bukan masalah, gunakan saja [[NSUserDefaults standardUserDefaults] synchronize];setelah meneleponsetObject:forKey:
Ben Baron
11

Saya suka metode terbaik Mauro Delrio. Saya juga telah menambahkan yang berikut ini di Project_Prefix.pch saya

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

Jadi jika Anda ingin menggunakan metode standar (yang menggunakan NSLocalizedString), Anda dapat membuat substitusi sintaksis cepat di semua file.

dnaxxx
sumber
1
Saya juga menyukai metodenya dan saya menambahkan metode untuk memuat gambar png: + (UIImage ) imageNamed: (NSString *) imageFileName {NSString fullPath = [bundle pathForResource: imageFileName ofType: @ "png"]; UIImage * imageObj = [[alokasi UIImage] initWithContentsOfFile: fullPath]; return [imageObj autorelease]; }
Jagie
11

NSLocalizedString()membaca nilai untuk kunci AppleLanguagesdari standar pengguna standar ( [NSUserDefaults standardUserDefaults]). Ini menggunakan nilai itu untuk memilih lokalisasi yang tepat di antara semua lokalisasi yang ada saat runtime. Ketika Apple membuat kamus default pengguna saat peluncuran aplikasi, mereka mencari kunci bahasa yang disukai dalam preferensi sistem dan menyalin nilainya dari sana. Ini juga menjelaskan misalnya mengapa mengubah pengaturan bahasa di OS X tidak berpengaruh pada menjalankan aplikasi, hanya pada aplikasi yang dimulai setelahnya. Setelah disalin, nilainya tidak diperbarui hanya karena pengaturannya berubah. Itu sebabnya iOS memulai ulang semua aplikasi jika Anda mengubah bahasa.

Namun, semua nilai kamus default pengguna dapat ditimpa oleh argumen baris perintah. Lihat NSUserDefaultsdokumentasi di NSArgumentDomain. Ini bahkan termasuk nilai-nilai yang diambil dari file preferensi aplikasi (.plist). Ini sangat bagus untuk diketahui jika Anda ingin mengubah nilai hanya sekali untuk pengujian .

Jadi jika Anda ingin mengubah bahasa hanya untuk pengujian, Anda mungkin tidak ingin mengubah kode Anda (jika Anda lupa untuk menghapus kode ini nanti ...), alih-alih minta Xcode untuk memulai aplikasi Anda dengan parameter baris perintah ( mis. gunakan lokalisasi bahasa Spanyol):

masukkan deskripsi gambar di sini

Tidak perlu menyentuh kode Anda sama sekali. Cukup buat skema yang berbeda untuk bahasa yang berbeda dan Anda dapat dengan cepat memulai aplikasi sekali dalam satu bahasa dan sekali dalam yang lain hanya dengan mengganti skema.

Mecki
sumber
Ini hanya berfungsi untuk pertama kalinya setelah itu lagi dimuat ke dalam perangkat. bahasa ..
Aks
@Aks Bekerja setiap saat untuk saya. Pastikan Anda memulai skema yang benar, pastikan Anda mulai dari dalam Xcode (relaunches, forks, dll. Tidak akan mendapatkan argumen) dan pastikan Anda tidak mengganti bahasa Optionsseperti halnya dengan versi Xcode yang lebih baru yang ditawarkan Apple yang demikian juga.
Mecki
Terima kasih atas balasan Anda @Mecki .. Bagi saya ini tidak berfungsi dalam xcode tetapi ketika saya menyebutkan dalam kode, itu berfungsi .. Tapi tetap saja jika saya telah mengatur perangkat saya dengan beberapa bahasa pilihan lain, ia perlu me-restart aplikasi untuk memuat ke dalam pilihan saya bahasa yang saya sampaikan dalam argumen ....
Aks
@Aks Saat menggunakannya pada perangkat, itu hanya akan bekerja ketika dimulai langsung dari Xcode, itu tidak akan berfungsi ketika Anda memulai aplikasi lagi dengan mengetuk ikonnya pada beberapa perangkat dan itu juga tidak akan berfungsi ketika aplikasi terbunuh (mis. karena ia beralih ke latar belakang) dan dihidupkan ulang oleh sistem (karena restart ini bukan restart yang dilakukan oleh Xcode) - jadi beralih ke aplikasi yang berbeda dan kembali mungkin tidak berfungsi jika iOS harus mematikan aplikasi Anda di antara (misalnya karena itu membutuhkan memori).
Mecki
10

Saya datang dengan solusi yang memungkinkan Anda untuk menggunakannya NSLocalizedString. Saya membuat kategori NSBundlepanggilan NSBundle+RunTimeLanguage. Antarmuka seperti ini.

// 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

Implementasinya seperti ini.

// 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

Daripada hanya menambahkan impor NSBundle+RunTimeLanguage.hke file yang digunakan NSLocalizedString.

Seperti yang Anda lihat, saya menyimpan kode bahasa saya di properti AppDelegate. Ini dapat disimpan di mana saja yang Anda inginkan.

Satu-satunya hal yang saya tidak suka tentang ini adalah Peringatan yang NSLocalizedStringdidefinisikan ulang marco. Mungkin seseorang dapat membantu saya memperbaiki bagian ini.

qman64
sumber
1
Tambahkan #undef NSLocalizedStringsesaat sebelum #definemenonaktifkan peringatan
berilium
Apakah ini berfungsi pada lokalisasi untuk file xib? Saya memiliki file .xib dan .strings untuk menerjemahkan nama UI dalam bahasa tertentu. Saya mencoba dan itu tidak bekerja dengan XIB tetapi saya tidak yakin apakah saya telah melakukan sesuatu dengan benar
Kong Hantrakool
Kong minta maaf atas tanggapan yang tertunda. Ini berfungsi di mana pun Anda menggunakan NSLocalizedString. Jadi itu tidak akan bekerja secara langsung di XIB. Anda perlu IBOutlets ke string di XIB dan kemudian harus secara terprogram mengatur nilai string dalam kode.
qman64
Pendekatan ini berhasil bagi saya dan saya dapat mengubah bahasa saat itu juga. Perhatikan bahwa kode bahasa seperti "es", fr "dan" en "bekerja dengan baik. Tetapi" zh "(untuk Bahasa Cina Sederhana) gagal dan memberi saya string nol kembali. Saya melakukan pencarian global pada sistem saya untuk" es.lproj "untuk lihat di mana file-file yang saya akses berada dan saya menemukan di sana bahwa "zh.lproj" sebenarnya "zh-Hans.lproj"
Gallymon
9

Versi Swift:

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

Singkatnya:

Lokalkan aplikasi Anda

Ini hal pertama yang harus Anda lakukan adalah melokalkan aplikasi Anda dengan setidaknya dua bahasa (Inggris dan Perancis dalam contoh ini).

Ganti NSLocalizedString

Dalam kode Anda, alih-alih menggunakan NSLocalizedString(key, comment), gunakan makro yang MYLocalizedString(key, comment)ditentukan seperti ini: #define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];

MYLocalizationSystemSingleton ini akan:

  • Set Bahasamu dengan menetapkan hak lokal NSBundle pengguna meminta
  • Mengembalikan NSString yang dilokalkan sesuai dengan bahasa yang ditetapkan sebelumnya

Tetapkan bahasa pengguna

Saat pengguna mengubah bahasa aplikasi dalam bahasa Prancis, hubungi [[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];
}

Dalam contoh ini metode ini mengatur bundel lokal ke fr.lproj

Kembalikan string yang dilokalkan

Setelah Anda menyetel bundel yang dilokalkan, Anda akan bisa mendapatkan string yang dilokalisasikan darinya dengan metode ini:

- (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];
}

Semoga ini bisa membantu Anda.

Anda akan menemukan rincian lebih lanjut dalam artikel ini dari NSWinery.io

pengguna3465357
sumber
Kami meminta Anda tidak hanya menautkan ke solusi dalam jawaban Anda; tautan mungkin berhenti bekerja suatu hari. Meskipun Anda tidak harus menghapus tautan dari jawaban Anda, kami meminta Anda mengedit jawaban Anda untuk menyertakan ringkasan bagian yang relevan dari artikel yang ditautkan.
Obivious Sage
7

Ekstensi Swift 3:

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
    }
}

Pemakaian:

Locale.preferredLanguage = "uk"

label.text = "localizedKey".localized
ChikabuZ
sumber
Terima kasih. Bekerja dengan baik.
Krunal Nagvadia
5

Dalam file .pch untuk mendefinisikan:

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


#define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
Mr.Piffiffo
sumber
Bagaimana cara saya menyingkirkan peringatan 'ovverride ...'?
Idan Moshe
1
Solusi sederhana melakukan semua yang saya butuhkan. Mampu menggunakan ini sebagai panduan untuk menyelesaikan masalah saya. Jika pathForResource mengembalikan nil karena saya tidak memiliki file lokalisasi maka saya menggunakan pathForResource: @ "Base" karena tidak ada yang lain saya telah mencoba menarik string dari lokalisasi basis. Terima kasih.
GRW
Ini adalah hacky (demikian juga semua jawaban lainnya), dan itu paling mudah diterapkan dalam unit test yang saya tulis.
Maks
4

Mungkin Anda harus melengkapi ini (pada file .pch setelah #import):

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]
D33pN16h7
sumber
/Users/pwang/Desktop/Myshinesvn/Myshine/viewController/OrientationReadyPagesView.m:193:31: Penggunaan 'bundle' pengidentifikasi yang tidak dideklarasikan
pengwang
4

Solusi Swift 3:

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")

Memberi beberapa contoh kode bahasa yang dapat digunakan. Semoga ini membantu

Jeremy Bader
sumber
3

Anda bisa membangun sub-bundel dengan set string terlokalisasi yang ingin Anda lakukan dengan ini, dan kemudian gunakan NSLocalizedStringFromTableInBundle()untuk memuatnya. (Saya berasumsi bahwa ini adalah konten yang terpisah dari lokalisasi UI normal yang mungkin Anda lakukan di aplikasi.)

Sixten Otto
sumber
3

untuk kasus saya, saya punya dua file terlokalisasi, ja dan en

dan saya ingin memaksanya untuk en jika bahasa pilihan dalam sistem tidak en atau ja

saya akan mengedit file main.m

Saya akan memeriksa apakah pilihan pertama adalah en atau ja, jika tidak maka saya akan mengubah bahasa pilihan kedua menjadi en.

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]));


    }


}
chings228
sumber
Terima kasih @ chings228 ini berguna bagi saya, tetapi ini tidak mengubah gambar peluncuran default (splash) untuk aplikasi yang saya punya splash yang berbeda untuk setiap bahasa. Anda tahu cara mendaftar untuk ini ??
JERC
saya pikir splash berjalan sebelum program utama mulai berjalan, jadi saya tidak tahu bagaimana menimpanya, mungkin plist dapat membantu tetapi mungkin berfungsi untuk waktu berikutnya aplikasi terbuka
chings228
2

Anda dapat melakukan sesuatu seperti ini:

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


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

NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
JERC
sumber
2

Berdasarkan jawaban Tudorizer untuk mengubah bahasa tanpa meninggalkan atau memulai ulang aplikasi.

Alih-alih makro, gunakan kelas untuk mengakses bahasa pilihan untuk memeriksa apakah ada kode bahasa tertentu.

Di bawah ini adalah kelas yang digunakan untuk mendapatkan bundel bahasa saat ini yang berfungsi untuk iOS 9:

@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

Gunakan kelas di atas untuk referensi file string / gambar / video / dll:

// 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")

Ubah bahasa in-line seperti di bawah ini atau perbarui metode "changeCurrentLanguage" di kelas di atas untuk mengambil parameter string yang mereferensikan bahasa baru.

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

Di swift 4, saya telah menyelesaikannya tanpa perlu me-restart atau menggunakan perpustakaan.

Setelah mencoba banyak opsi, saya menemukan fungsi ini, tempat Anda meneruskan stringToLocalize (dari Localizable.String, file string) yang ingin Anda terjemahkan, dan bahasa tempat Anda ingin menerjemahkannya, dan apa yang dikembalikan adalah nilai untuk String yang Anda miliki di file Strings:

    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)
    }

Dengan mempertimbangkan fungsi ini, saya membuat fungsi ini dalam file Swift:

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!)!
    }
}

Untuk mengakses dari seluruh aplikasi, dan di setiap string dari ViewControllers lainnya, alih-alih menempatkan:

NSLocalizedString ("StringToLocalize", comment: ")

Saya telah menggantinya dengan

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

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

Saya tidak tahu apakah itu cara terbaik, tetapi saya menemukannya sangat sederhana, dan itu bekerja untuk saya, saya harap ini membantu Anda!

ainareta685
sumber
1

Fungsi ini akan mencoba untuk mendapatkan string terlokalisasi untuk bahasa saat ini dan jika tidak ditemukan itu akan mendapatkannya menggunakan bahasa inggris.

- (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;
}
Cherpak Evgeny
sumber
1

Saya ingin menambahkan dukungan untuk bahasa yang tidak secara resmi didukung oleh iOS (tidak tercantum di bagian Bahasa di bawah pengaturan sistem). Dengan mengikuti Tutorial Internasionalisasi Apple dan beberapa petunjuk di sini oleh Brian Webster dan geon, saya membuat potongan kode ini (letakkan di main.m):

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]));
    }
}

Ini berfungsi baik untuk Storyboard dan kode NSLocalizedString. Kode ini mengasumsikan bahwa pengguna akan memiliki opsi untuk mengubah bahasa di dalam aplikasi secara manual nanti.

Tentu saja, jangan lupa menambahkan terjemahan Storyboard yang tepat dan terjemahan Localizable.strings (lihat tautan ke halaman Apple di atas untuk mengetahui cara melakukannya).

frin
sumber
Saya melihat Anda juga menghadapi masalah dengan bahasa Slovenia :) Untuk meningkatkan jawaban ini untuk bahasa yang tidak didukung oleh iOS, sudahkah Anda mengetahui jika kami dapat menetapkan string yang dapat dilokalisasi khusus yang akan digunakan untuk kontrol sistem di aplikasi (Edit, Done, More, ...)?
miham
1

Berikut ini adalah solusi yang layak untuk masalah ini, dan tidak memerlukan restart aplikasi.

https://github.com/cmaftuleac/BundleLocalization

Implementasi ini bekerja dengan mengubah di dalam NSBundle. Idenya adalah bahwa Anda menimpa metode localizedStringForKey pada instance objek NSBundle, dan kemudian memanggil metode ini pada bundel berbeda dengan bahasa yang berbeda. Sederhana dan elegan sepenuhnya kompatibel dengan semua jenis sumber daya.

Corneliu Maftuleac
sumber
Kode dari proyek ini sangat membantu saya. Cara menemukan bundel untuk kode bahasa tertentu ---NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
Eonil
Kelas ini berfungsi dengan baik, tetapi setelah mengubah bahasa ke yang lain, itu tidak berpengaruh.
Anilkumar iOS ReactNative
0

apa pun yang Anda semua lakukan, cara terbaik adalah mengambil nama_pendek untuk bahasa yang ditentukan, yaitu: fr, en, nl, de, it, dll ... dan tetapkan hal yang sama ke nilai global.

membuat tampilan pemilih untuk muncul seperti menu drop down (kombinasi tombol pada klik yang mana tampilan pemilih muncul dari bawah dengan daftar bahasa) dan pilih bahasa yang Anda inginkan. biarkan nama pendek disimpan secara internal. buat file .h + .m bernama LocalisedString.

Tetapkan nilai global short_name menjadi sama dengan nilai yang diperoleh di LocalisedString.m. Ketika bahasa yang diperlukan dipilih menetapkan NSBundlePath untuk membuat sub-direktori proyek untuk bahasa yang dibutuhkan. untuk misalnya, nl.proj, en.proj.

Ketika folder proj tertentu dipilih, panggil string yang dilokalisasi untuk bahasa masing-masing dan ubah bahasa secara dinamis.

tidak ada aturan yang dilanggar.

Abhijeet
sumber
0

Untuk Swift Anda dapat mengganti main.swiftfile dan mengatur string UserDefaults di sana sebelum aplikasi Anda berjalan. Dengan cara ini Anda tidak perlu memulai ulang Aplikasi untuk melihat efek yang diinginkan.

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))

dipasangkan bersama dengan penghapusan @UIApplicationMaindi AppDelegate.swiftfile Anda .

Andreas
sumber