Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.

This article also participated in the “Digitalstar Project” to win a creative gift package and creative incentive money

preface

Principle:

  1. Custom tool class LanguageManager to parse localized strings
  2. In – application switch language effective technology implementation: using the destruction of the root controller, re-enter
  3. The localization string specifies the order of arguments

To highlight:

  1. Localization of strings
  2. Custom tool classes LanguageManager,
  3. Example: Login interface switch English (including demo)

Technical implementation of in-application switching language implementation:

  1. Destroy the root controller and re-enter (adopted)

2. Update text to each controller by sending notification (not adopted)

From CSDN download demo internationalization switch within the iOS APP 】 【 source: download.csdn.net/download/u0…

I string localization

1.1 usage

  • Create the string resource file Localizable. Strings

  • Add multilanguage support for Localizable. Strings

Select Make Localize to add Localizable. Strings to the English localization folder en.lproj

Localizable. Strings (English) corresponds to the Localizable. Strings file in the en.lproj folder

Localizable. Strings (Chinese) corresponds to the Localizable. Strings file in the zh-Hans.lproj folder

  • Configure the key and value corresponding to the string in the resource file Localizable.

en.lproj/Localizable.strings

static NSString * const kSystem      = @"SystemDefault";

static NSString * const kCH          = @"zh-Hans";
static NSString * const kEN          = @"en";


static NSString * const kProj        = @"lproj";
static NSString * const kLanguageSet = @"kLanguageSet";
"Connected" = "Connected";
"Tip"="Tip";

Copy the code

zh-Hans.lproj/Localizable.strings

"Connected" = "Connected";
"Tip"="Tip";

Copy the code

  • Use NSLocalizedString(key, comment) in the code to read the localized string. Key is the string to the left of the middle sign of the Localizable. Strings file, and comment is purely a comment
 #define NSLocalizedString(key, comment) \
	    [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil]
#define NSLocalizedStringFromTable(key, tbl, comment) \
	    [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \
	    [bundle localizedStringForKey:(key) value:@"" table:(tbl)]
#define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \
	    [bundle localizedStringForKey:(key) value:(val) table:(tbl)]
Copy the code

The localized string is read using encapsulated macros

// Program localization, referencing the internationalized file
#define QCTLocal(x, ...) HZLocalizedString(x, nil)

#define HZLocalizedString(key, comment)               HZLocalizedStringFromTable(key, @"Localizable", nil)
#define HZLocalizedStringFromTable(key, tbl, comment) [[HZLanguageManager defaultManager] stringWithKey:key table:tbl]




/** internationalization @param key <#key description#> @param table Localizable @return <#return value description#> */
- (NSString *)stringWithKey:(NSString *)key table:(NSString *)table
{
    // If the following system is used
    if (self.languageType==HZLanguageTypeSystem) {
        return  NSLocalizedString(key, nil);
    }
    
    // Return the corresponding internationalized text
    if (_bundle) {
        return  NSLocalizedStringFromTableInBundle(key, table, _bundle, nil);
    }
    
    return NSLocalizedStringFromTable(key, table, nil);
}





// Read the localization string using QCTLocal

        [LBAlertController showAlertTitle:QCTLocal(@"tips") content:QCTLocal(@"str_cann_printer") cancelString:QCTLocal(@"cancel") cancleBlock:nil sureString:QCTLocal(@"sure") sureBlock:^{

Copy the code

If the string is not localized or the value for key is not found, NSLocalizedString will return the key string directly

1.2 Localization string Specifies the parameter order

For the syntax differences between Chinese and English, we often need to adjust the order of the arguments to stringWithFormat when localizing strings

  • IOS localization string Specifies the sequence of parameters: Application scenario: Switching between multiple languages in the APP

Article: kunnan.blog.csdn.net/article/det… How it works: Add a number (1(1(1,2$)) between % and @. The number represents the order of the arguments

"FORMAT" = "I am %2$@ from '%1$@'";

Copy the code

II. Customize the tool class LanguageManager to parse localized strings

2.1 Code Implementation

  • LanguageManager

From CSDN download demo internationalization switch within the iOS APP 】 【 source: download.csdn.net/download/u0…

#import <Foundation/Foundation.h>

#define HZLocalizedString(key, comment)               HZLocalizedStringFromTable(key, @"Localizable", nil)
#define HZLocalizedStringFromTable(key, tbl, comment) [[HZLanguageManager defaultManager] stringWithKey:key table:tbl]

static NSString * const kNoticeLanguageChange = @"kNoticeLanguageChange";


typedef NS_ENUM(NSUInteger, HZLanguageType) {
    HZLanguageTypeSystem,
    HZLanguageTypeEnglish,
    HZLanguageTypeChineseSimple,
};

@interface HZLanguageManager : NSObject

@property (nonatomic.assign.getter=currentLanguageType) HZLanguageType languageType;

+ (instancetype)defaultManager;

- (void)changeLanguageType:(HZLanguageType)type;
- (NSString *)stringWithKey:(NSString *)key table:(NSString *)table;
- (HZLanguageType)currentLanguage;

+ (BOOL )isEN;


Copy the code
  • LanguageManager.h .m
static NSString * const kSystem      = @"SystemDefault";

static NSString * const kCH          = @"zh-Hans";
static NSString * const kEN          = @"en";


static NSString * const kProj        = @"lproj";
static NSString * const kLanguageSet = @"kLanguageSet";

@interface HZLanguageManager(a)

@property (nonatomic.strong) NSBundle *bundle;
@property (nonatomic.strong) NSString *languageString;

@end

@implementation HZLanguageManager

+ (instancetype)defaultManager
{
    static dispatch_once_t onceToken;
    static HZLanguageManager *manager;
    dispatch_once(&onceToken, ^{
        if (!manager) {
            manager = [[HZLanguageManager alloc] init];
        }
    });
    return manager;
}

- (instancetype)init
{
    self = [super init];
    if (!self) {
        return nil;
    }
    // Take the field to see what language it is
    NSString *tempStr = [[NSUserDefaults standardUserDefaults] objectForKey:kLanguageSet];
    // NSString *path;
    
    // If the user has not set the language
    if(! tempStr) { tempStr=kSystem; }self.languageString = tempStr;
    
    
    if ([self.languageString isEqualToString:kCH]) {/ / into Chinese
        
        self.languageType = HZLanguageTypeChineseSimple;
        
    }else if ([self.languageString isEqualToString:kEN]) {/ / in English
        
        self.languageType = HZLanguageTypeEnglish;
        
    }else if([self.languageString isEqualToString:kSystem]){// Indicates the system default value
        
        self.languageType= HZLanguageTypeSystem;
        
        if([self isENLanguage]){//HZLanguageManager
            self.languageType = HZLanguageTypeEnglish;

        }else{
            self.languageType = HZLanguageTypeChineseSimple; }}if ([_languageString isEqualToString:kEN] || [_languageString isEqualToString:kCH]) {
        NSString *path = [[NSBundle mainBundle] pathForResource:_languageString ofType:kProj];
        self.bundle = [NSBundle bundleWithPath:path];
    }
    
    NSLog(% @ "current language HZLanguageTypeSystem HZLanguageTypeEnglish HZLanguageTypeChineseSimple: lu", (unsigned long)self.languageType);
    
    return self;
}



- (void)changeLanguageType:(HZLanguageType)type;
{
    if (self.currentLanguageType == type) {
        return;
    }
    
    _languageType = type;
    switch (type) {
        case HZLanguageTypeSystem:
            
            self.languageString=kSystem;
            break;
        case HZLanguageTypeEnglish:
            
            self.languageString = kEN;
            break;
        case HZLanguageTypeChineseSimple:
            
            self.languageString = kCH;
            break;

    }
    
    / / bundle Settings
    [self resetBundle];
    
    // Set the language and save the record
    [[NSUserDefaults standardUserDefaults] setObject:_languageString forKey:kLanguageSet];
    [[NSUserDefaults standardUserDefaults] synchronize];
    
    / / use the notice to change the text [[NSNotificationCenter defaultCenter] postNotificationName: kNoticeLanguageChange object: nil];
}

- (void)resetBundle{
    if ([_languageString isEqualToString:kEN] || [_languageString isEqualToString:kCH]) {
        NSString *path = [[NSBundle mainBundle] pathForResource:_languageString ofType:kProj];
        self.bundle = [NSBundlebundleWithPath:path]; }} - (NSString *)stringWithKey:(NSString *)key table:(NSString *)table
{
    // If the following system is used
    if (self.languageType==HZLanguageTypeSystem) {
        return  NSLocalizedString(key, nil);
    }
    
    // Return the corresponding internationalized text
    if (_bundle) {
        return  NSLocalizedStringFromTableInBundle(key, table, _bundle, nil);
    }
    
    return NSLocalizedStringFromTable(key, table, nil);
}

-(HZLanguageType)currentLanguage{
    // Get the current language
    // NSString *tempStr = [[NSUserDefaults standardUserDefaults] objectForKey:kLanguageSet];
    // if ([tempStr rangeOfString:@"zh"].length) {
    //// tempStr = kCH;
    // return HZLanguageTypeChineseSimple;
    // }else if([tempStr isEqualToString:kEN]){
    //// tempStr = kEN;
    // return HZLanguageTypeEnglish;
    // }else {//if([tempStr isEqualToString:kSystem])
    //    
    // return HZLanguageTypeSystem;
    / /}
    return    self.languageType;
}


+ (NSArray *)english {
    return@ [@"en".@"en-CN"];
}

+ (NSArray *)chineseHans {
    return@ [@"zh-Hans".@"zh-Hans-CN"];
}

+ (NSArray *)chineseHant {
    return@ [@"zh-Hant".@"zh-Hant-CN"];
}




/** (lldb) po [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"] <__NSCFArray 0x2833357a0>( Zh-hans-am, EN-am, en-gb, ru-am, zh-hant-am, zh-hant-hk) The first one is the user-set language @return */
- (BOOL )isENLanguage {
// NSString *language = [[NSUserDefaults standardUserDefaults] objectForKey:GHLLanguageKey];
    
// if (){
// if ([HZLanguageManager defaultManager].currentLanguage==HZLanguageTypeEnglish) {

    if (self.currentLanguage == HZLanguageTypeEnglish) {

    return YES;
    }
    
    
    
// if () {
        NSArray *languages = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"];
        NSString *language =  languages.firstObject;
        
/ /}
    
// if([[HZLanguageManager chineseHans] containsObject:language] || [[HZLanguageManager chineseHant] containsObject:language] ){
        if([language containsString:@"zh-Hans"] || [language containsString:@"zh-Hant"] ){

        
        return NO;
        }else{
            return YES; }} + (BOOL )isEN{
    
    if([HZLanguageManager defaultManager].currentLanguage == HZLanguageTypeEnglish ){
        // make.width.mas_equalTo(kAdjustRatio(73 * 3));
        return YES;
        
    }else{
        // make.width.mas_equalTo(kAdjustRatio(50 * 3));
// make.left.equalTo(weakSelf.contentView).offset(kAdjustRatio(20));
// make.right.equalTo(weakSelf.contentView).offset(- kAdjustRatio(20));
//
        return NO; }}@end

Copy the code

2.2 Solution to the key failure caused by the excessively long text of the Strings file

/ consts/Localizable/en. Lproj/Localizable strings text content is too long. The key becomes invalid.

  • The solution

Add a new table to store, parse from the two files to find.

	new file:   retail/retail/class/consts/Localizable/en.lproj/Localizable1.strings
	new file:   retail/retail/class/consts/Localizable/zh-Hans.lproj/Localizable1.strings

Copy the code
  • The code to read the local string: ‘If your string resource file name is not Localizable. Strings, such as kn.strings, So you have to use the NSLocalizedStringFromTable (), NSLocalizedStringFromTableInBundle to read the localized strings:

`

- (NSString *)stringWithKey:(NSString *)key table:(NSString *)table
{
    // If the following system is used
    if (self.languageType==HZLanguageTypeSystem) {
        return  NSLocalizedString(key, nil);
    }
    
    // Return the corresponding internationalized text
    if (_bundle) {// If you can't find it, you can find it in file 2.
        //NSLocalizedStringFromTableInBundleWithKey
        return [self NSLocalizedStringFromTableInBundleWithKey:key table:table];
        return  NSLocalizedStringFromTableInBundle(key, table, _bundle, nil);
        
        
        
    }
    
    return NSLocalizedStringFromTable(key, table, nil);
}



/ * * if you have a string resource file name is not Localizable. The strings, such as KN. The strings, so you have to use NSLocalizedStringFromTable () to read the localized string: * /
//{// change the file to another file, first from the file, if you can't find the file, then from the file.
- (NSString*)NSLocalizedStringFromTableInBundleWithKey: (NSString *)key table:(NSString *)table{
    NSString* tmp = key;
    if(_bundle){
        
        tmp =NSLocalizedStringFromTableInBundle(key, table, _bundle, nil);

        if([tmp isEqualToString:key]){
            // Continue the search from the backup table
            
            NSLog(Start from Localizable1 for key:%@, tmp);
            tmp =NSLocalizedStringFromTableInBundle(key, @"Localizable1", _bundle, nil);
// NSLog([NSString stringWithFormat:@" end from Localizable1 key:%@", TMP]);
            NSLog(End search for key from Localizable1 :%@, tmp); }}return tmp;

    
    
    
}



Copy the code

III. Internationalization of info.plist

  • Create a new.strings file called InfoPlist. Strings (the name must be this)
  • After the new building, click on the right side of the spindle is meaningful.
  • The key step comes when we click on our info.plist and right-click Open as Source Code to see the original key from which we want to obtain permissions

The CFBundleDisplayName key in info.plist determines the name of the application

"NSMicrophoneUsageDescription" = "Allow this app to use your microphone for decibel detection and sound recording; audio is recorded locally only and is not sent to anyone, only for decibel detection and sound variation.";

Copy the code

IV, case

4.1 “User Agreement and Privacy Policy” pop-up box (including hyperlink attributes)

IOS “user agreement and privacy policy” bounced (contain hyperlinks properties) [this article contains a complete demo source code, switch demo support in both Chinese and English) | xu li

Kunnan.blog.csdn.net/article/det…

4.2 Switching between Chinese and English on the Login page

  • AppDelegate: Sets the default language
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    if([LanguageManager isEN] ){
// _titleLab.font = kPingFangFont(10);
        [[LanguageManager defaultManager] changeLanguageType: HZLanguageTypeEnglish];

        NSLog(@" Current Bit English version");
        
    }else{
// _titleLab.font = kPingFangFont(12);
        NSLog(@" Current Bit Chinese version"); [[HZLanguageManager defaultManager] changeLanguageType: HZLanguageTypeChineseSimple]; }}Copy the code

Github.com/zhangkn/Lan…

  • Build switch button: languageLab

Handles action events for switching Between Chinese and English languages


- (UILabel *)languageLab{
    if(! _languageLab) { _languageLab = [[UILabel alloc]init];
        _languageLab.textColor = rgb(51.51.51);
        _languageLab.font = kBoldFont(15);
        
        
        _languageLab.textAlignment = NSTextAlignmentRight;
        
        
        
        // Display according to the configuration
// typedef NS_ENUM(NSUInteger, HZLanguageType) {
// HZLanguageTypeSystem,
// HZLanguageTypeEnglish,
// HZLanguageTypeChineseSimple,
/ /};

        // Get the configuration information
        
        // Set the selected language
        if ([HZLanguageManager defaultManager].currentLanguage==HZLanguageTypeSystem) {
// self.seletedIndex=@0;
            
            
            
            
        }
       else if ([HZLanguageManager defaultManager].currentLanguage==HZLanguageTypeChineseSimple) {
// self.seletedIndex=@1;
// _languageLab.text = @"";
           _languageLab.text = @"English";


        }
       else  if ([HZLanguageManager defaultManager].currentLanguage==HZLanguageTypeEnglish) {
// self.seletedIndex=@2;
           
           _languageLab.text = @" Simplified Chinese";

       }else{
           
// _languagelab. text = @" simplified Chinese ";

           
       }
        

        
        
        //
// Ti ti Ajia
        //
        
        _languageLab.userInteractionEnabled = YES;
        
        
        
        
        [self addSubview:_languageLab];
        __weak __typeof__(self) weakSelf = self;

        [_languageLab mas_makeConstraints:^(MASConstraintMaker *make) {
           
            make.top.equalTo(weakSelf).offset(36);
            make.right.equalTo(weakSelf).offset(-kAdjustRatio(16));
            
            make.size.mas_equalTo(CGSizeMake(kAdjustRatio(100), kAdjustRatio(40)));

            
            
        }];
        
        
        UITapGestureRecognizer *cutTap = [[UITapGestureRecognizer alloc] init];
// __weak __typeof__(self) weakSelf = self;
        
        [[cutTap rac_gestureSignal] subscribeNext:^(id x) {
            
            

            switch ([HZLanguageManager defaultManager].currentLanguage) {
                case HZLanguageTypeSystem:
                    {
                        
                    }
                    break;
                    
                case HZLanguageTypeEnglish:
                {
                    
                    [[HZLanguageManager defaultManager] changeLanguageType: HZLanguageTypeChineseSimple];

                    weakSelf.languageLab.text = @" Simplified Chinese";

                }
                    break;
                    
                case HZLanguageTypeChineseSimple:
                {
                    [[HZLanguageManager defaultManager] changeLanguageType: HZLanguageTypeEnglish];

                    weakSelf.languageLab.text = @"English";

                }
                    break;
                    

                    
                default: {}break;
            }
            
            [ AccountLoginView rootViewController4nil];
            
            
        }];
        [_languageLab addGestureRecognizer:cutTap];

        
    }
    return _languageLab;
}


+ (void) rootViewController4nil{
    
    / / destroyed root
    UIWindow *oldWindow=[UIApplication sharedApplication].keyWindow;
    oldWindow.rootViewController=nil;
    
    / / new root
    UIWindow *newWindow = [UIApplication sharedApplication].keyWindow;
    
    
    AccountLoginViewController *VC = [[AccountLoginViewController alloc]init];
    
    HWNavigationController *NA = [[HWNavigationController alloc]initWithRootViewController:VC];
    
    
    
    [AccountLoginView restoreRootViewController:NA newWindow:newWindow];

}

/ * * UIModalTransitionStyleCoverVertical = 0, / / enter UIModalTransitionStyleFlipHorizontal from bottom to top cover, / / flip horizontal UIModalTransitionStyleCrossDissolve, / / gradient in # if __IPHONE_OS_VERSION_MAX_ALLOWED > = __IPHONE_3_2 UIModalTransitionStylePartialCurl, // similar page turn crimp @param rootViewController <#rootViewController description#> @param newWindow <#newWindow description#> https://github.com/codeRiding/CRProject/blob/165886b8426fa43b52e76e659b8e18496e2fa8c8/CRProject/Classes/Expand/Tool/CRCh angeVC.m */
+ (void)restoreRootViewController:(UIViewController *)rootViewController newWindow:(UIWindow*)newWindow
{
    typedef void (^Animation)(void);
    UIWindow* window =  newWindow;
//
    rootViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
//UIModalPresentationPopover
    //UIModalPresentationNone
// rootViewController.modalPresentationStyle = UIModalPresentationOverFullScreen; //UIModalPresentationOverFullScreen

// UIModalTransitionStyleCoverVertical = 0,
// UIModalTransitionStyleFlipHorizontal __TVOS_PROHIBITED,
// UIModalTransitionStyleCrossDissolve,
// UIModalTransitionStylePartialCurl
// rootViewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
    Animation animation = ^{
        BOOL oldState = [UIView areAnimationsEnabled];
        [UIView setAnimationsEnabled:NO];
// [UIApplication sharedApplication].keyWindow.rootViewController = rootViewController;
                        [newWindow switchWithRootViewController:rootViewController];

        [UIView setAnimationsEnabled:oldState];
    };
    //
    [UIView transitionWithView:window
                      duration:0.5f
                       options:UIViewAnimationOptionTransitionCrossDissolve
                    animations:animation
                    completion:nil];

}
Copy the code

4.3 Localization String Specifies the parameter order

For the syntax differences between Chinese and English, we often need to adjust the order of the arguments to stringWithFormat when localizing strings

Principle: in the middle of the % and @ plus values (1, 1 (1, 2 $), the Numbers for the order of the parameters of the article: blog.csdn.net/z929118967/…

see also

  • IOS highlights :(continuously updated)

Kunnan.blog.csdn.net/article/det…

  • Merge Develop to Master and tag the version

Blog.csdn.net/z929118967/…

For more, check out # Applets: iOS Reverse, which presents valuable information only for you, focusing on the mobile technology research field.