cschuff
cschuff

Reputation: 5542

iOS: How to do I18N/Localization in-app?

How can I do I18N within my app leaving the language setting of the device out?

I want to have a screen after the splash screen asking the user for the language he want to use the app in. This should be independent from the system language.

Is there an easy way to just set the language setting in the apps context? Something like:

[[UIApplication sharedApplication] setLocale/setBundle/setLanguage]

Thanks for any advice.

EDIT

Ok, I made some progress. Is there a way to override NSLocalizedString()? The problem is that setting the NSUserDefaults to another language code will only be recognized after restarting the app. That is of course no option for me.

Upvotes: 1

Views: 3579

Answers (3)

BaQiWL
BaQiWL

Reputation: 437

Using the latest Xcode15, you can use String Catalogs to add and manage localized key-value pairs, use NSLocalizedString to call, or use SwiftGen to automatically generate code. If you need to translate into multiple languages, you can use I18n Studio

Upvotes: 0

cschuff
cschuff

Reputation: 5542

I ended up with this solution. I first define a static class to set my In-App language on:

@implementation I18NUtil

static NSBundle *_bundle;
static NSString *_language;

+ (id)alloc 
{
    [NSException raise:@"Cannot be instantiated!" format:@"Static class 'ClassName' cannot be instantiated!"];
    return nil;
}

+ (void)setLanguage:(NSString *)languageCode 
{
    [[NSUserDefaults standardUserDefaults] setObject:[NSArray arrayWithObjects:languageCode, nil] forKey:@"AppleLanguages"];

    NSString *path = [[NSBundle mainBundle] pathForResource:languageCode ofType:@"lproj"];
    _bundle = [NSBundle bundleWithPath:path];
    _language = languageCode;
}

+ (NSString *)localizedString:(NSString *)key
{
   return [_bundle localizedStringForKey:key value:@"" table:nil];
}

@end

You could easily use:

[I18NUtil localizedString:@"myLocalizedString"]

in your whole project now.

But I found it a lot easier to override the NSLocalizedString macro and use the i18n like I am used to it. You have to include this into your AppName-Prefix.pch:

#ifdef __OBJC__
    ...

    // Override native NSLocalizedString(key,message) to achieve in-app and on-the-fly i18n
    // Needs to be defined AFTER importing Foundation.h
    #import "I18NUtil.h"

    #ifdef NSLocalizedString
        #undef NSLocalizedString
    #endif

    #define NSLocalizedString(key, message) \
        [I18NUtil localizedString:(key)]
#endif

Have fun!

Upvotes: 3

djromero
djromero

Reputation: 19641

You can use an arbitrary strings file with NSLocalizedStringFromTable.

For instance, you can have all your strings file organized like this:

localizable_buttons_english.strings
localizable_buttons_spanish.strings
...
localizable_errors_english.strings
localizable_errors_spanish.strings
...

Then, using user's chosen language in your app preferences to obtain the translation in any language:

NSString *lang = <# read user prefs #> // Example: spanish
NSString *table = [NSString stringWithFormat:@"localizable_buttons_%@", lang];
NSString *text = NSLocalizedStringFromTable(@"SendButtonLabel", table, nil);
sendButton.titleLabel.text = text;

// localizable_buttons_english.strings
"SendButtonLabel" = "Send";

// localizable_buttons_spanish.strings
"SendButtonLabel" = "Enviar";

Localizing NIB files is just a matter of loading the NIBs programmatically using the user chosen language to build the NIB name.

Upvotes: 1

Related Questions