热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在iOS中更改app语言,无需重新启动app-ChangeapplanguageiniOSwithoutrestartingtheapp

Ihaveseemssomeappscanchangethelanguageinternallywithintheappwithouttheneedofrestart

I have seems some apps can change the language internally within the app without the need of restarting the app, I am wondering how they are implemented.

我觉得一些应用程序可以在不需要重新启动的情况下改变应用程序内部的语言,我想知道它们是如何实现的。

For example, for us using NSLocalizedString, I know it is possible to set the language at runtime at main.m when your AppDelegate is not initialized, but once it is initialized (particularly your view controller is created), change it has not effect until the next restart

例如,对于我们使用NSLocalizedString,我知道在运行时在main中设置语言是可能的。m当你的AppDelegate没有初始化时,但是一旦初始化(尤其是你的视图控制器被创建),在下一次重新启动之前它是不会生效的

[[NSUserDefaults standardUserDefaults] 
    setObject:[NSMutableArray arrayWithObjects:language, nil] 
    forKey:@"AppleLanguages"];

Anyone have idea how those dynamic language change can be done without restarting the app?

有人知道动态语言的改变是如何在不重新启动应用程序的情况下完成的吗?

6 个解决方案

#1


5  

There's some discussion of other approaches here, in particular a notification based approach:

这里有一些关于其他方法的讨论,特别是基于通知的方法:

iOS: How to change app language programmatically WITHOUT restarting the app?

iOS:如何在不重新启动应用程序的情况下通过编程方式改变应用程序语言?

In my view there are really three tasks here: (1) re-localization of resources automatically loaded from nibs. (for example if you dynamically instantiate another custom UIView from a nib, the "old" language strings and settings (images, text direction) will still be loaded) (2) re-localization of strings currently displayed on the screen. (3) re-localization of strings inserted by the developer (you) in program code.

在我看来,这里确实有三个任务:(1)从nib自动加载的资源的重新定位。(例如,如果从nib动态实例化另一个自定义的UIView,“旧”语言字符串和设置(图像、文本方向)仍然会被加载)(2)当前显示在屏幕上的字符串的重新定位。(3)程序代码中由开发人员(您)插入的字符串的重新定位。

Let's start with (3). If you look for the definition you will notice that NSLocalizedString is a macro. So if you don't want to change existing code too much, you can probably solve the problem of (3) by creating a new header file. In that header file, #undef and then re-#define NSLocalizedString to pick the localized string from the appropriate place--not the one that iOS defaults to, but one that you keep track of in some global variable (e.g., in an app delegate ivar). If you don't want to redefine NSLocalizedString but you still make your own alternative , you should probably still #undef NSLocalizedString if you don't want future developers to accidentally call it instead of the macro you replace it with. Not an ideal solution, but maybe the most practical.

让我们从(3)开始。如果你寻找定义,你会注意到NSLocalizedString是一个宏。因此,如果您不想对现有代码做太多修改,您可以通过创建一个新的头文件来解决(3)的问题。在那个头文件中,#undef然后re-#define NSLocalizedString从适当的位置选择本地化的字符串——不是iOS默认的字符串,而是在全局变量(例如,在app delegate ivar中)中跟踪的字符串。如果您不想重新定义NSLocalizedString,但是您仍然可以选择,如果您不想让未来的开发人员意外地调用它,而不是用宏替换它,那么您应该仍然使用#undef NSLocalizedString。这不是一个理想的解决方案,但可能是最实用的。

As for (1), if you haven't done your localization in Interface Builder, but rather you do it dynamically in viewDidLoad, etc., no problem. You can use the same behavior just discussed (i.e., the modified NSLocalizedString, etc.). Otherwise you can either (a) implement a notification system as described in the link above (complicated), or (b) consider moving localization from IB to viewDidLoad, or (c) try overriding initWithNibName: and swap out the object loaded with the old language resources, with one loaded with the new language resources. This was an approach mentioned by Mohamed at the very bottom of this discussion: http://learning-ios.blogspot.ca/2011/04/advance-localization-in-ios-apps.html. He claims it causes problems (viewDidLoad isn't called). Even if it doesn't work, trying it out might point you towards something that does.

至于(1),如果您没有在接口构建器中进行本地化,而是在viewDidLoad中动态地进行本地化,那么没有问题。您可以使用刚才讨论的相同行为(例如。,修改后的NSLocalizedString,等等)。否则,您可以(a)实现上面链接(复杂)中描述的通知系统,或者(b)考虑将本地化从IB迁移到viewDidLoad,或者(c)尝试重写initWithNibName:并交换加载旧语言资源的对象,其中一个对象加载新语言资源。这是Mohamed在讨论的最后提到的方法:http://learning- ios.blogspot.ca/2011/04/advancelocaliz-ios-apps.html。他声称它会引起问题(viewDidLoad不被调用)。即使它不起作用,尝试它可能会让你指向有作用的东西。

Finally, (2) is presumably the easiest task: just remove and re-add the current view (or in some cases, just redraw it).

最后,(2)可能是最简单的任务:只需删除并重新添加当前视图(在某些情况下,只需重新绘制它)。

#2


2  

the idea is to write a new macro like NSLocalizedString which should check if to take the translation from another specific bundle or not.

其想法是编写一个新的宏,比如NSLocalizedString,它应该检查是否从另一个特定的bundle中获取翻译。

The method 2 in this article explain exactly how to do it. In this particular case, the author doesn't use a new macro, but directly set a custom class for [NSBundle mainBundle].

本文中的方法2详细地解释了如何实现它。在本例中,作者不使用新的宏,而是直接为[NSBundle mainBundle]设置自定义类。

I hope that @holex will understand the problem reading this.

我希望@holex能理解阅读本文的问题。

#3


1  

I'm always using this way, it works perfectly, it might help you as well.

我一直用这种方法,它很有效,可能对你也有帮助。


you should set all the texts with NSLocalizableString(...) for the UI for the current language in the -viewWillAppear: method of your every UIViewController.

你应该用NSLocalizableString(…)为当前语言的UI设置所有文本在-viewWillAppear中:每个UIViewController的方法。

using this way you (I mean, the users) don't need to restart the application after changing the language of iOS in the Settings.

使用这种方式,您(我的意思是,用户)无需在设置中更改iOS语言后重新启动应用程序。


of course, I'm using the Apple's standard localisation architecture.

当然,我使用的是苹果的标准本地化架构。

UPDATE on (24 Oct 2013)

I've experienced the –viewWillAppear: method won't be performed for the actual view when the application enters to foreground; to solve that issue I also commit the procedure (see above) when I receive UIApplicationWillEnterForegroundNotification notification in the view.

我经历过-viewWillAppear:当应用程序进入前台时,不会对实际视图执行方法;为了解决这个问题,当我收到uiapplicationwillentergroundnotification通知时,我也提交了这个过程(见上面)。

#4


1  

My implementation uses a class to change the language and access the current language bundle. It's an example so if you were to use different languages than I am then change the methods to use your exact language codes.

我的实现使用一个类来更改语言并访问当前语言包。这是一个例子,如果你用的是不同于我的语言那么你就改变方法来使用你的语言代码。

This class will access the preferred languages from NSLocale and take the first object which is the language being used.

这个类将访问来自NSLocale的首选语言,并使用第一个对象,该对象是正在使用的语言。

@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

Use the class above to reference a string file / image / video / etc:

使用上面的类来引用字符串文件/图像/视频等:

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

Change language in-line like below or update the "changeCurrentLanguage" method in the class above to take a string parameter referencing the new language code.

更改如下所示的语言,或者更新上面类中的“changeCurrentLanguage”方法,获取引用新语言代码的字符串参数。

// Change the preferred language to Spanish
[[NSUserDefaults standardUserDefaults] setObject:@[@"es"] forKey:@"AppleLanguages"];

#5


0  

I was stuck in same issue, my requirement was "User can select language from drop down & application have to work according selected language (English or arabic)" What i have done i create two XIB and fetch XIB and Text according selected language. In this way user can select language. I used NSBundle for the same. like

我遇到了同样的问题,我的要求是“用户可以从下拉列表中选择语言,应用程序必须按照选定的语言(英语或阿拉伯语)工作”我所做的是创建了两个XIB,并根据所选的语言获取XIB和文本。这样用户就可以选择语言。我也用了NSBundle。就像

For XIB

对于XIB

self.homeScreen =  [[HomeScreen alloc] initWithNibName:@"HomeScreen" bundle:[CommonData sharedCommonData].languageBundle];

For Text

用于文本

_lblHeading.text = [self languageSelectedStringForKey:@"ViewHeadingInfo"];

/**
 This method is responsible for selecting language bundle according to user's selection. 
 @param: the string which is to be converted in selected language. 
 @return: the converted string.
 @throws:
 */

-(NSString*) languageSelectedStringForKey:(NSString*) key

{

    NSString* str=[[CommonData sharedCommonData].languageBundle localizedStringForKey:key value:@"" table:nil];

    return str;

}

#6


-1  

You need to load another bundle like this(where @"en" could be locale you need):

您需要加载另一个类似这样的包(其中@“en”可能是您需要的语言环境):

NSString *path = [[NSBundle mainBundle] pathForResource:@"en" ofType:@"lproj"];
NSBundle *languageBundle = [NSBundle bundleWithPath:path];

and make macros/function like NSLocalizedString which use your loaded bundle or use methods on that bundle directly like this

然后创建宏/函数,比如NSLocalizedString它会使用你的加载包,或者直接使用这个包上的方法

[languageBundle localizedStringForKey:key value:value table:tableName];

[[NSBundle mainBundle] localizations] lists all app localizations(including "Base").

[[NSBundle mainBundle]本地化]列出所有应用程序本地化(包括“Base”)。

Also I wrote helper class which does this(note that it has ReactiveCocoa as a dependency). It allows language change without app restart and sends current locale each time it's changed.

我还编写了帮助类来实现这一点(注意它有ReactiveCocoa作为依赖项)。它允许无需重新启动就进行语言更改,并在每次更改时发送当前语言环境。


推荐阅读
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • SpringBoot uri统一权限管理的实现方法及步骤详解
    本文详细介绍了SpringBoot中实现uri统一权限管理的方法,包括表结构定义、自动统计URI并自动删除脏数据、程序启动加载等步骤。通过该方法可以提高系统的安全性,实现对系统任意接口的权限拦截验证。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 有没有一种方法可以在不继承UIAlertController的子类或不涉及UIAlertActions的情况下 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • ScrollView嵌套Collectionview无痕衔接四向滚动,支持自定义TitleView
    本文介绍了如何实现ScrollView嵌套Collectionview无痕衔接四向滚动,并支持自定义TitleView。通过使用MainScrollView作为最底层,headView作为上部分,TitleView作为中间部分,Collectionview作为下面部分,实现了滚动效果。同时还介绍了使用runtime拦截_notifyDidScroll方法来实现滚动代理的方法。具体实现代码可以在github地址中找到。 ... [详细]
  • iOS Swift中如何实现自动登录?
    本文介绍了在iOS Swift中如何实现自动登录的方法,包括使用故事板、SWRevealViewController等技术,以及解决用户注销后重新登录自动跳转到主页的问题。 ... [详细]
  • 本文介绍了在iOS开发中使用UITextField实现字符限制的方法,包括利用代理方法和使用BNTextField-Limit库的实现策略。通过这些方法,开发者可以方便地限制UITextField的字符个数和输入规则。 ... [详细]
  • 在开发中,有时候一个业务上要求的原子操作不仅仅包括数据库,还可能涉及外部接口或者消息队列。此时,传统的数据库事务无法满足需求。本文介绍了Java中如何利用java.lang.Runtime.addShutdownHook方法来保证业务线程的完整性。通过添加钩子,在程序退出时触发钩子,可以执行一些操作,如循环检查某个线程的状态,直到业务线程正常退出,再结束钩子程序。例子程序展示了如何利用钩子来保证业务线程的完整性。 ... [详细]
  • Annotation的大材小用
    为什么80%的码农都做不了架构师?最近在开发一些通用的excel数据导入的功能,由于涉及到导入的模块很多,所以开发了一个比较通用的e ... [详细]
  • Java编程思想一书中第21章并发中关于线程间协作的一节中有个关于汽车打蜡与抛光的小例子(原书的704页)。这个例子主要展示的是两个线程如何通过wait ... [详细]
  • 基于分布式锁的防止重复请求解决方案
    一、前言关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求。而这样的重复请求如果是幂等的(每次请求的结果都相同,如查 ... [详细]
  • go channel 缓冲区最大限制_Golang学习笔记之并发.协程(Goroutine)、信道(Channel)
    原文作者:学生黄哲来源:简书Go是并发语言,而不是并行语言。一、并发和并行的区别•并发(concurrency)是指一次处理大量事情的能力 ... [详细]
author-avatar
mizrke
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有