【问题标题】:How to force NSLocalizedString to use a specific language如何强制 NSLocalizedString 使用特定语言
【发布时间】:2013-04-03 15:53:40
【问题描述】:

在 iPhone 上 NSLocalizedString 返回 iPhone 语言的字符串。 是否可以强制NSLocalizedString 使用特定语言来拥有应用程序 使用与设备不同的语言?

【问题讨论】:

标签: ios objective-c localization internationalization nslocalizedstring


【解决方案1】:

对我来说,Test-Plan 用户,在 TestPlan 的 Arguments Passed On Launch 中指定 -AppleLanguages (en_BZ)(伯利兹英语)是有效的。

由于我们使用 en_GB 和 en_BZ,iOS 总是首选 en_GB。即便如此,当我将设备语言切换为 EN 并将区域切换为 BZ 并在测试计划 Application LanguageApplication Region 设置中设置这些值时。除了上面好的旧论点方法外,没有任何帮助:)

【讨论】:

    【解决方案2】:

    对于 Swift,您可以在应用运行之前覆盖 main.swift 文件并在其中设置 UserDefaults 字符串。这样您不必重新启动应用程序即可看到所需的效果。

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

    在您的AppDelegate.swift 文件中删除@UIApplicationMain

    【讨论】:

      【解决方案3】:

      在 swift 4 中,我已经解决了,无需重新启动或使用库。

      在尝试了许多选项后,我找到了这个函数,您可以在其中传递要翻译的 stringToLocalize(Localizable.String,字符串文件),以及您要翻译的语言,它返回的是您在字符串文件中拥有的该字符串的值:

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

      考虑到这个函数,我在一个 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!)!
          }
      }
      

      从整个应用程序中访问,并在其余 ViewControllers 的每个字符串中,而不是放置:

      NSLocalizedString ("StringToLocalize", comment: “")
      

      我已经替换为

      let customLang = CustomLanguage() //declare at top
      let bundleLanguage = customLang.createBundle()
      
      NSLocalizedString("StringToLocalize", tableName: nil, bundle: bundleLanguage, value: "", comment: “”) //use in each String
      

      我不知道这是否是最好的方法,但我发现它非常简单,并且对我有用,希望对您有所帮助!

      【讨论】:

      • 这个答案很棒,因为它也适用于例如在 Linux 上运行的 Swift 包。
      【解决方案4】:

      我最近遇到了同样的问题,我不想启动并修补我的整个 NSLocalizedString,也不想强制重启应用以使新语言正常工作。我希望一切都按原样工作。

      我的解决方案是动态更改主包的类并在那里加载适当的包:

      头文件

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

      实施

      #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
      

      所以基本上,当您的应用启动时,在您加载第一个控制器之前,只需调用:

      [NSBundle setLanguage:@"en"];
      

      当您的用户在您的设置屏幕中更改他的首选语言时,只需再次调用它:

      [NSBundle setLanguage:@"fr"];
      

      要重置回系统默认值,只需传递 nil:

      [NSBundle setLanguage:nil];
      

      享受...

      对于那些需要 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)
          }
      }
      

      【讨论】:

      • 嗨@Wirsing,到目前为止,这对我来说非常有用。我什至已经将一个应用程序上传到商店,Apple 没有抱怨。
      • 这是一个很好的解决方案,我在这里也引用了这个:medium.com/ios-apprentice/905e4052b9de
      • 嗨@JamesTang,感谢您的参考和您的帖子 - 我在那里找到了很多关于本地化的有用信息。
      • @Gilad 您的方法非常适用于动态字符串(我在 localizable.strings 中定义的字符串),但对于情节提要按钮和标签,它仅适用于 main 方法。那么您可以扩展您的答案以包括 UI 控件本地化吗?我的意思是在我调用 [NSBundle setLanguage:@"??"];?? 后如何刷新(不关闭)故事板
      • 对于 XIB/storyboard:你需要确保在加载视图之前调用这个方法。就实时更新视图而言:在我的情况下,我只是重新加载了视图控制器(我将它放在导航控制器中并替换了控制器。重新加载后 - 它得到了新的翻译字符串)。我正在为它开发一个 cocoapod,我可能还会在其中包含一个示例。敬请期待……
      【解决方案5】:

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

      用法:

      Locale.preferredLanguage = "uk"
      
      label.text = "localizedKey".localized
      

      【讨论】:

      • 谢谢。运作良好。
      • 是的,它正在工作,但应用程序需要重新启动才能更改语言。
      【解决方案6】:

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

      给出了一些可以使用的语言代码示例。希望这会有所帮助

      【讨论】:

        【解决方案7】:

        您如何看待 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)
            }
        }
        

        简单用法:

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

        【讨论】:

        • 嗨,如何本地化来自服务器的动态文本,在我的应用程序中,我必须以简体中文显示每个文本,但是如何以中文显示英文文本。帮助我。
        • 这是一个绝妙的答案;)
        • 很好的答案。帮助了我
        【解决方案8】:

        我通常这样做,但您的项目中必须有所有本地化文件。

        @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。这是一个非常好的技巧,我在其他任何地方都没有见过。通过从本地化文件夹之一创建一个“子包”,只要您将 NSLocalizedString 与此处绕道而行的东西包装在一起,您就可以使字符串工作正常。
        • 优秀的毛罗。我注意到它也适用于您项目中的文件。如果出于某种原因(如我的情况),您需要从网络下载字符串文件,并将它们存储在您的“文档”目录中(文件夹结构为 Documents/en.lproj/Localizable.strings、Documents/fr.lproj/ Localizable.strings, ...)。你甚至可以制作一个 NSBundle。只需将此代码用于路径: NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"/Documents/%@.lproj", l, nil]];
        • 在我看来,这是最好的方法,下面还有 Alessandro 的贡献。它不是那么侵入性,不需要重新启动。
        • 我做错了什么?我做了一个Language类,继承NSObject,把这个放到实现中,把方法名放到.h里,然后把[Language setLanguage:@"es"];在我的更改语言按钮中,代码运行(按钮方法被调用,然后转到语言类),但什么也不做。我也设置了 localizable.strings(西班牙语)。但它似乎适用于很多其他人。请有人帮我把它弄糊涂。
        • @KKendall 你这样称呼它:[Language setLanguage:@"es"]; NSString *stringToUse = [Language get:@"Your Text" alter:nil];
        【解决方案9】:

        也许你应该补充这个(在 #import 之后的 .pch 文件上):

        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:使用未声明的标识符“bundle”
        【解决方案10】:

        Swift 版本:

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

        【讨论】:

          【解决方案11】:

          NSLocalizedString()(及其变体)访问NSUserDefaults 中的“AppleLanguages”键以确定用户对首选语言的设置。这将返回一组语言代码,第一个是用户为其手机设置的语言代码,如果资源在首选语言中不可用,则后续代码用作后备。 (在桌面上,用户可以在 System Preferences 中以自定义顺序指定多种语言)

          如果您愿意,可以使用 setObject:forKey: 方法设置您自己的语言列表,从而覆盖您自己的应用程序的全局设置。这将优先于全局设置值,并返回到应用程序中执行本地化的任何代码。代码如下所示:

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

          这将使德语成为您的应用程序的首选语言,英语和法语作为备用语言。您可能希望在应用程序启动的早期调用它。您可以在此处阅读有关语言/区域设置偏好的更多信息:Internationalization Programming Topics: Getting the Current Language and Locale

          【讨论】:

          • 这对我不起作用,无论如何它都会使用默认语言。
          • 丹尼斯;如果您应用程序启动之前设置语言偏好,它似乎效果更好。在调用 UIApplicationMain() 之前,我在 main() 函数中执行此操作。一旦它真正运行,它不会改变使用的语言,而只是设置下一次的偏好。
          • 您必须在初始化 UIKit 之前设置语言,并且您必须指定完整的语言+区域区域设置 - 查看完整示例blog.federicomestrone.com/2010/09/15/…
          • 如果在 main() 中设置 AppleLanguages 将在运行时更改语言 - 真的!但是......第一次安装应用程序时,nsuserdefaults 在调用 UIApplicationMain() 后初始化,这将忽略先前设置的 AppleLanguages,并且需要强制重启应用程序才能看到所需的语言。
          • 这不适用于 Localizable.stringsdict 中定义的复数项。知道是否有可能的解决方法吗?
          【解决方案12】:

          基于 Tudorizer 的回答,无需离开或重新启动应用程序即可更改语言。

          使用类来访问首选语言,而不是宏,以检查是否存在特定语言代码。

          以下是用于获取适用于 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
          

          使用上面的类引用一个字符串文件/图片/视频/等:

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

          如下所示内联更改语言或更新上述类中的“changeCurrentLanguage”方法以获取引用新语言的字符串参数。

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

          【讨论】:

            【解决方案13】:

            不要在 iOS 9 上使用。这将对通过它的所有字符串返回 nil。

            我找到了另一个解决方案,它允许您更新语言字符串,无需重新启动应用程序并与 genstrings 兼容:

            将此宏放在 Prefix.pch 中:

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

            以及任何需要本地化字符串的地方:

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

            设置语言使用:

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

            即使连续语言跳跃也能工作,例如:

            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, @""));
            

            【讨论】:

            • @powerj1984:不,它只会更改源文件中的字符串。如果要更改 xib 语言,则必须从所选语言的包中手动重新加载 xib。
            • @gklka 我已经按照 Tudozier 给出的步骤进行操作,但我的 XIB 并没有改变语言,正如你所说的手动重新加载 XIB,重新加载 XIB 的真正含义是什么?
            • @DkKumar:你必须做类似这样的事情:stackoverflow.com/questions/21304988/…
            • @gklka 您的回答似乎是正确的,我已经按照您在回答中描述的步骤执行了相同的步骤,但问题是如果我们更改捆绑路径而不是找到所有资源(即 .在 XIB 中使用的 png 文件)在同一个包中,所以我们必须过度复制所有包中的图像文件夹,如 en.lproj、es.lproj 等.. 这样会影响 IPA 大小的增加,所以有什么办法克服这个问题?正如你在帖子中所说,让我试试这个,让你更多地了解这个谢谢你帮助我
            • 这在 iOS 9 中被严重破坏,为所有字符串返回 null。
            【解决方案14】:

            简而言之:

            本地化您的应用程序

            您要做的第一件事是使用至少两种语言(在本例中为英语和法语)对您的应用进行本地化。

            覆盖 NSLocalizedString

            在您的代码中,不要使用NSLocalizedString(key, comment),而是使用如下定义的宏MYLocalizedString(key, comment)#define MYLocalizedString(key, comment) [[MYLocalizationSystem sharedInstance] localizedStringForKey:(key) value:(comment)];

            这个MYLocalizationSystem 单身人士将:

            • 通过设置正确的本地化 NSBundle 用户要求来设置语言
            • 根据之前设置的语言返回本地化的 NSString

            设置用户语言

            当用户更改法语应用程序语言时,请致电[[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];
            }
            

            在本例中此方法将本地化的包设置为 fr.lproj

            返回本地化字符串

            一旦你设置了本地化的包,你就可以用这个方法从他那里得到正确的本地化字符串:

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

            希望这会对你有所帮助。

            您将在NSWinery.io的这篇文章中找到更多详细信息

            【讨论】:

            • 我们要求您不要仅仅在回答中链接到解决方案;该链接可能有一天会停止工作。虽然您不必从答案中删除链接,但我们确实要求您编辑答案以包含链接文章相关部分的摘要。
            【解决方案15】:

            这是解决这个问题的一个不错的方法,它不需要重新启动应用程序。

            https://github.com/cmaftuleac/BundleLocalization

            此实现通过在 NSBundle 内部进行调整来工作。这个想法是,您在 NSBundle 对象的实例上覆盖方法本地化StringForKey,然后在具有不同语言的不同包上调用此方法。简洁优雅,全面兼容各类资源。

            【讨论】:

            • 项目中的这段代码对我帮助很大。如何找到特定语言代码的捆绑包 --- NSString *path = [[NSBundle mainBundle] pathForResource:lang ofType:@"lproj" ];
            • 这个类工作正常,但是换成另一种语言后就没有效果了。
            【解决方案16】:

            你可以这样做:

            NSString *bundlePath = [[NSBundle mainBundle] pathForResource:@"Localizable" ofType:@"strings" inDirectory:nil forLocalization:@"es"];
            
            
            NSBundle *spanishBundle = [[NSBundle alloc] initWithPath:[bundlePath stringByDeletingLastPathComponent]];
            
            NSLocalizedStringFromTableInBundle(@"House", nil, spanishBundle, nil):
            

            【讨论】:

              【解决方案17】:

              NSLocalizedString() 从标准用户默认值 ([NSUserDefaults standardUserDefaults]) 中读取键 AppleLanguages 的值。它使用该值在运行时在所有现有本地化中选择适当的本地化。当 Apple 在应用程序启动时构建用户默认字典时,他们会在系统偏好设置中查找首选语言键并从那里复制值。例如,这也解释了为什么在 OS X 中更改语言设置对运行的应用程序没有影响,只会对此后启动的应用程序产生影响。复制后,值不会因为设置更改而更新。这就是为什么如果您更改语言,iOS 会重新启动所有应用程序。

              但是,用户默认字典的所有值都可以被命令行参数覆盖。请参阅 NSArgumentDomain 上的 NSUserDefaults 文档。这甚至包括从应用首选项 (.plist) 文件加载的那些值。 如果您只想更改一次值以进行测试,了解这一点真的很好。

              因此,如果您只想更改语言以进行测试,您可能不想更改代码(如果您稍后忘记删除此代码...),而是告诉 Xcode 使用命令启动您的应用程序行参数(例如使用西班牙语本地化):

              根本不需要接触您的代码。只需为不同的语言创建不同的方案,您就可以通过切换方案快速启动应用程序一次在一种语言和另一种语言中。

              【讨论】:

              • 它仅在第一次工作后再次加载到设备首选项中。语言..
              • @Aks 每次都为我工作。确保您正在启动正确的方案,确保您从 Xcode 内部开始(重新启动、分叉等不会得到参数)并确保您不会像使用较新的 Xcode 版本那样覆盖 Options 中的语言苹果也提供了。
              • 感谢您的回复@Mecki.. 对我来说,它不能在 xcode 中工作,但是当我在代码中提到它时,它可以工作.. 但如果我用其他一些首选语言设置了我的设备,它仍然需要重新启动应用程序以加载到我在参数中传递的首选语言....
              • @Aks 在设备上使用它时,它只会在直接从 Xcode 启动时工作,当您通过在某些设备上点击它的图标再次启动应用程序时它不会工作,它也不会当应用程序被杀死(例如,因为它进入后台)并被系统重新启动(因为此重新启动不是由 Xcode 完成的重新启动)时工作 - 因此如果 iOS 必须杀死你的应用程序并返回可能无法正常工作介于两者之间的应用程序(例如,因为它需要内存)。
              • 您可以将此参数传递与 StandardUserDefaults 中的更改结合起来,每次都会像魅力一样工作
              【解决方案18】:

              我想出了一个允许您使用NSLocalizedString 的解决方案。我创建了一个NSBundle 类别,调用NSBundle+RunTimeLanguage。界面是这样的。

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

              实现是这样的。

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

              不仅仅是将 import NSBundle+RunTimeLanguage.h 添加到使用 NSLocalizedString 的文件中。

              如您所见,我将语言代码存储在AppDelegate 的属性中。这可以存储在您想要的任何地方。

              我唯一不喜欢的是 NSLocalizedString marco 重新定义的警告。也许有人可以帮我修复这部分。

              【讨论】:

              • #define 之前添加#undef NSLocalizedString 以禁用警告
              • 这适用于 xib 文件的本地化吗?我有 .xib 文件和 .strings 来翻译特定语言的 UI 名称。我试过了,它不适用于 XIB,但我不确定我是否做得正确
              • Kong 很抱歉延迟回复。这适用于您使用 NSLocalizedString 的任何地方。所以它不能直接在 XIB 中工作。您需要 IBOutlets 到 XIB 中的字符串,然后必须以编程方式在代码中设置字符串值。
              • 这种方法对我有用,我能够即时更改语言。请注意,像“es”、“fr”和“en”这样的语言代码工作正常。但是“zh”(用于简体中文)失败并给了我空字符串。我在我的系统上进行了全局搜索“es.lproj”到查看我访问的文件在哪里,我发现“zh.lproj”实际上是“zh-Hans.lproj”。
              【解决方案19】:

              就我而言,我有两个本地化文件 ja 和 en

              如果系统中的首选语言既不是 en 也不是 ja,我想强制它为 en

              我要编辑 main.m 文件

              我会检查第一个首选语言是 en 还是 ja,如果不是,我会将第二个首选语言更改为 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 这对我很有用,但这不会更改应用程序的默认启动图像(启动画面),我对每种语言都有不同的启动画面。你知道如何申请吗??
              • 我认为splash在主程序开始运行之前运行,所以我不知道如何覆盖它,plist可能会有所帮助,但下次打开应用程序时可能会起作用
              【解决方案20】:

              我想添加对 iOS 未正式支持的语言的支持(未在系统设置下的语言部分列出)。通过遵循Apple's Internationalization Tutorial 和 Brian Webster 和 geon 的一些提示,我想出了这段代码(放在 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]));
                  }
              }
              

              这适用于 Storyboard 和 NSLocalizedString 代码。该代码假定用户稍后可以选择在应用内手动更改语言。

              当然,不要忘记添加适当的 Storyboard 翻译和 Localizable.strings 翻译(有关如何执行此操作,请参阅上面的 Apple 页面链接)。

              【讨论】:

              • 我看到你也面临斯洛文尼亚语的问题 :) 为了改进 iOS 不支持的语言的答案,你有没有想过我们是否可以设置自定义的可本地化字符串,这些字符串将用于系统控件应用程序(编辑、完成、更多...)?
              【解决方案21】:

              通过从应用程序中选择特定语言来使用特定语言的技巧是强制NSLocalizedString 根据所选语言使用特定捆绑包,

              这是我为此写的帖子 learning advance localization in ios apps

              这是一个示例应用程序的代码advance localization in ios apps

              【讨论】:

              • 它也适用于 iOS7,我必须从 Brian 的解决方案切换到这个,因为 iOS 似乎再次覆盖了语言选项,因此我坚持第一次设置语言。您的解决方案就像一个魅力!
              【解决方案22】:

              在文件.pch中定义:

              #define currentLanguageBundle [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:[[NSLocale preferredLanguages] objectAtIndex:0] ofType:@"lproj"]]
              
              
              #define NSLocalizedString(str,nil) NSLocalizedStringFromTableInBundle(str, nil, currentLanguageBundle, @"")
              

              【讨论】:

              • 如何消除警告“ovverride...”?
              • 简单的解决方案可以满足我的一切需求。能够以此为指导来解决我的问题。如果 pathForResource 因为我没有本地化文件而返回 nil,那么我使用 pathForResource:@"Base" 因为我没有尝试从基本本地化中提取字符串。谢谢。
              • 这很hacky(其他所有答案也是如此),并且在我正在编写的单元测试中最容易实现。
              【解决方案23】:

              此函数将尝试获取当前语言的本地化字符串,如果找不到,它将使用英语获取它。

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

              【讨论】:

                【解决方案24】:

                正如 Brian Webster 所提到的,需要“在应用程序启动的早期某个时间”设置语言。我认为AppDelegate 中的applicationDidFinishLaunching: 应该是一个合适的地方,因为这是我进行所有其他初始化的地方。

                但正如 William Denniss 所提到的,这似乎只有在 应用重新启动后才会生效,这有点没用。

                不过,如果我将代码放在主函数中,它似乎可以正常工作:

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

                我会很感激这方面的任何 cmets。

                【讨论】:

                • 在我的实现中这是一个用户可设置的东西——所以我只是弹出一个对话框告诉他们他们需要重新启动:)
                • 它几乎适用于所有人 - 除了本地化的 Default.png 图像。
                • 如果您让用户设置语言然后告诉他们重新启动应用程序,请记住如果他们重新启动太快,NSUserDefaults 可能不会被保存。大多数用户并没有这么快,但是当您测试应用程序时,您可能会太快并因此看到不一致的行为。我花了几个小时才意识到为什么我的语言切换有时有效,有时无效!
                • 这不是问题,在调用setObject:forKey:后使用[[NSUserDefaults standardUserDefaults] synchronize];
                【解决方案25】:

                如前所述,只需:

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

                但为了避免重启应用,请将这一行放在main.m 的main 方法中,就在UIApplicationMain(...) 之前。

                【讨论】:

                • 非常有帮助的答案!附言对非初学者来说可能听起来很明显,但您应该在 NSAutoreleasePool * pool .. 之后插入该行,否则一些自动释放的对象会泄漏。
                • 重要提示:如果您之前致电[[NSBundle mainBundle] URLForResource:withExtension:],这将不起作用。
                • 如果使用Swift,那么没有main.m呢?
                • @turingtested 你在 swift 和 storyboard 上试过了吗,效果好吗?
                • 嗨,如何本地化来自服务器的动态文本,在我的应用程序中,我必须以简体中文显示每个文本,但是如何以中文显示英文文本。帮助我。
                【解决方案26】:

                无论你们做什么,最好的方法是获取指定语言的 short_name,即:fr、en、nl、de、it 等...并将其分配给全局值。

                制作一个像下拉菜单一样弹出的选择器视图(单击按钮,从下方显示一个选择器视图与语言列表的组合)并选择您想要的语言。让短名称存储在内部。 制作一个名为 LocalisedString 的 .h + .m 文件。

                设置short_name的全局值等于LocalisedString.m中获取的值 选择所需语言后,分配 NSBundlePath 为所需语言创建项目子目录。例如,nl.proj、en.proj。

                When the particular proj folder is selected call the localised string for the respective language and change the language dynamically.

                没有违反规则。

                【讨论】:

                  【解决方案27】:

                  我最喜欢 Mauro Delrio 的方法。 我还在我的 Project_Prefix.pch 中添加了以下内容

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

                  因此,如果您想使用标准方法(使用 NSLocalizedString),您可以在所有文件中进行快速语法替换。

                  【讨论】:

                  • 我也喜欢他的方法,我添加了一个加载png图像的方法: +(UIImage )imageNamed:(NSString *)imageFileName{ NSString fullPath = [bundle pathForResource:imageFileName ofType:@"png"]; UIImage* imageObj = [[UIImage alloc] initWithContentsOfFile:fullPath];返回 [imageObj 自动释放]; }
                  【解决方案28】:

                  您可以使用要执行此操作的本地化字符串集构建一个子捆绑包,然后使用NSLocalizedStringFromTableInBundle() 加载它们。 (我假设这是与您可能在应用程序上执行的正常 UI 本地化分开的内容。)

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多