如何使用Swift以编程方式更改语言环境

Var*_*kul 62 xcode localization ios swift

我正在通过Swift在XCODE 6.3上制作ios应用程序.我的应用程序将具有选择语言功能,如下图所示

在此输入图像描述

我已经有了当地语言的故事板.但我无法找到如何通过按钮以编程方式更改应用程序的本地化.

任何人都知道如何做到这一点

dij*_*iji 72

这是一种使用Swift动态更改它的方法,为String添加扩展函数:

extension String {
func localized(lang:String) ->String {

    let path = NSBundle.mainBundle().pathForResource(lang, ofType: "lproj")
    let bundle = NSBundle(path: path!)

    return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
}}
Run Code Online (Sandbox Code Playgroud)

斯威夫特4:

extension String {
func localized(_ lang:String) ->String {

    let path = Bundle.main.path(forResource: lang, ofType: "lproj")
    let bundle = Bundle(path: path!)

    return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
}}
Run Code Online (Sandbox Code Playgroud)

然后假设你有使用lang_id.lproj设置的常规Localizable.strings(例如en.lproj,de.lproj等),你可以在任何你需要的地方使用它:

var val = "MY_LOCALIZED_STRING".localized("de")
Run Code Online (Sandbox Code Playgroud)

  • swift 3版本:func localized(lang:String) - > String {let path = Bundle.main.path(forResource:lang,ofType:"lproj")let bundle = Bundle(path:path!)return NSLocalizedString(self, tableName:nil,bundle:bundle!,value:"",comment:"")} (4认同)
  • 但是当你改变语言时如何重新加载故事板?目前,当我更改语言时,带有.localized()的字符串可以正常工作,但故事板并未反映为所选语言. (4认同)
  • 这个答案不能回答问题,这是关于使用本地语言的故事板的。它只是翻译String的糖。 (4认同)

Ale*_* G. 22

这允许仅通过更新密钥更改语言.UserDefaults

这是基于@dijipiji的答案.这是一个Swift 3版本.

extension String {
    var localized: String {
        if let _ = UserDefaults.standard.string(forKey: "i18n_language") {} else {
            // we set a default, just in case
            UserDefaults.standard.set("fr", forKey: "i18n_language")
            UserDefaults.standard.synchronize()
        }

        let lang = UserDefaults.standard.string(forKey: "i18n_language")

        let path = Bundle.main.path(forResource: lang, ofType: "lproj")
        let bundle = Bundle(path: path!)

        return NSLocalizedString(self, tableName: nil, bundle: bundle!, value: "", comment: "")
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

只需添加.localized到您的字符串,如下:

"MyString".localized,MyString作为Localizable.strings文件中的一个关键.

改变语言

UserDefaults.standard.set("en", forKey: "i18n_language")
Run Code Online (Sandbox Code Playgroud)

  • 但是当你改变语言时如何重新加载故事板?目前,当我更改语言时,带有.localized()的字符串可以正常工作,但故事板根本不会改变. (7认同)
  • 你不应该使用synchronize()。Apple 文档字面意思是到处都是(至少对于 iOS 10 和 11):https://developer.apple.com/documentation/foundation/userdefaults/1414005-synchronize (2认同)

whi*_*gle 10

花了好几天我才真正找到了解决方案.不需要重新推出,很优雅:http://www.factorialcomplexity.com/blog/2015/01/28/how-to-change-localization-internally-in-your-ios-application.html,检查方法#2.它不需要手动重新建立所有标题和文本,只需覆盖自定义NSBundle类别的本地化.适用于Obj-C和Swift项目(经过一些调整后),就像魅力一样.我怀疑它是否会被苹果批准,但实际上确实如此.


Joh*_*ang 9

Jeremy的答案(这里)也适用于Swift 4(我刚用一个简单的应用程序进行测试,我改变了初始视图控制器中使用的语言).

这是同一段代码的Swift版本(出于某些原因,我的队友更喜欢Swift-only而不是与Objective-C混合,所以我翻译了它):

import UIKit

private var kBundleKey: UInt8 = 0

class BundleEx: Bundle {

    override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
        if let bundle = objc_getAssociatedObject(self, &kBundleKey) {
            return (bundle as! Bundle).localizedString(forKey: key, value: value, table: tableName)
        }
        return super.localizedString(forKey: key, value: value, table: tableName)
    }

}

extension Bundle {

    static let once: Void = {
        object_setClass(Bundle.main, type(of: BundleEx()))
    }()

    class func setLanguage(_ language: String?) {
        Bundle.once
        let isLanguageRTL = Bundle.isLanguageRTL(language)
        if (isLanguageRTL) {
            UIView.appearance().semanticContentAttribute = .forceRightToLeft
        } else {
            UIView.appearance().semanticContentAttribute = .forceLeftToRight
        }
        UserDefaults.standard.set(isLanguageRTL, forKey: "AppleTextDirection")
        UserDefaults.standard.set(isLanguageRTL, forKey: "NSForceRightToLeftWritingDirection")
        UserDefaults.standard.synchronize()

        let value = (language != nil ? Bundle.init(path: (Bundle.main.path(forResource: language, ofType: "lproj"))!) : nil)
        objc_setAssociatedObject(Bundle.main, &kBundleKey, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }

    class func isLanguageRTL(_ languageCode: String?) -> Bool {
        return (languageCode != nil && Locale.characterDirection(forLanguage: languageCode!) == .rightToLeft)
    }

}
Run Code Online (Sandbox Code Playgroud)


mr.*_*fox 8

Swift 4中的可用代码:

extension Bundle {
    private static var bundle: Bundle!

    public static func localizedBundle() -> Bundle! {
        if bundle == nil {
            let appLang = UserDefaults.standard.string(forKey: "app_lang") ?? "ru"
            let path = Bundle.main.path(forResource: appLang, ofType: "lproj")
            bundle = Bundle(path: path!)
        }

        return bundle;
    }

    public static func setLanguage(lang: String) {
        UserDefaults.standard.set(lang, forKey: "app_lang")
        let path = Bundle.main.path(forResource: lang, ofType: "lproj")
        bundle = Bundle(path: path!)
    }
}
Run Code Online (Sandbox Code Playgroud)

extension String {
    func localized() -> String {
        return NSLocalizedString(self, tableName: nil, bundle: Bundle.localizedBundle(), value: "", comment: "")
    }

    func localizeWithFormat(arguments: CVarArg...) -> String{
        return String(format: self.localized(), arguments: arguments)
    }
}
Run Code Online (Sandbox Code Playgroud)

呼叫:

let localizedString = "enter".localized()
Run Code Online (Sandbox Code Playgroud)

设置新的语言环境(例如"ru"):

Bundle.setLanguage(lang: "ru")
Run Code Online (Sandbox Code Playgroud)


Dan*_*ark 6

Swift 4

UserDefaults.standard.set(["es", "de", "it"], forKey: "AppleLanguages")
UserDefaults.standard.synchronize()
Run Code Online (Sandbox Code Playgroud)

Swift 3

NSUserDefaults.standardUserDefaults().setObject(["es", "de", "it"], forKey: "AppleLanguages")
NSUserDefaults.standardUserDefaults().synchronize()
Run Code Online (Sandbox Code Playgroud)

Source: here

  • 谢谢!帮助我在启动时强制设置应用程序语言,将这些行添加到 AppDelegate 中。 (2认同)

Den*_*Den 6

斯威夫特4.2

就我而言,如果用户更改语言设置,则必须在运行时更新2件事。

1. Localizable.strings

可本地化的字符串

2.故事板的本地化

故事板本地化

我让@John Pang代码更加快捷

BundleExtension.swift

import UIKit

private var bundleKey: UInt8 = 0

final class BundleExtension: Bundle {

     override func localizedString(forKey key: String, value: String?, table tableName: String?) -> String {
        return (objc_getAssociatedObject(self, &bundleKey) as? Bundle)?.localizedString(forKey: key, value: value, table: tableName) ?? super.localizedString(forKey: key, value: value, table: tableName)
    }
}

extension Bundle {

    static let once: Void = { object_setClass(Bundle.main, type(of: BundleExtension())) }()

    static func set(language: Language) {
        Bundle.once

        let isLanguageRTL = Locale.characterDirection(forLanguage: language.code) == .rightToLeft
        UIView.appearance().semanticContentAttribute = isLanguageRTL == true ? .forceRightToLeft : .forceLeftToRight

        UserDefaults.standard.set(isLanguageRTL,   forKey: "AppleTe  zxtDirection")
        UserDefaults.standard.set(isLanguageRTL,   forKey: "NSForceRightToLeftWritingDirection")
        UserDefaults.standard.set([language.code], forKey: "AppleLanguages")
        UserDefaults.standard.synchronize()

        guard let path = Bundle.main.path(forResource: language.code, ofType: "lproj") else {
            log(.error, "Failed to get a bundle path.")
            return
        }

        objc_setAssociatedObject(Bundle.main, &bundleKey, Bundle(path: path), objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
}
Run Code Online (Sandbox Code Playgroud)

语言速记

import Foundation

enum Language: Equatable {
    case english(English)
    case chinese(Chinese)
    case korean
    case japanese

    enum English {
        case us
        case uk
        case australian
        case canadian
        case indian
    }

    enum Chinese {
        case simplified
        case traditional
        case hongKong
    }
}

extension Language {

    var code: String {
        switch self {
        case .english(let english):
            switch english {
            case .us:                return "en"
            case .uk:                return "en-GB"
            case .australian:        return "en-AU"
            case .canadian:          return "en-CA"
            case .indian:            return "en-IN"
            }

        case .chinese(let chinese):
            switch chinese {
            case .simplified:       return "zh-Hans"
            case .traditional:      return "zh-Hant"
            case .hongKong:         return "zh-HK"
            }

        case .korean:               return "ko"
        case .japanese:             return "ja"
        }
    }

    var name: String {
        switch self {
        case .english(let english):
            switch english {
            case .us:                return "English"
            case .uk:                return "English (UK)"
            case .australian:        return "English (Australia)"
            case .canadian:          return "English (Canada)"
            case .indian:            return "English (India)"
            }

        case .chinese(let chinese):
            switch chinese {
            case .simplified:       return "????"
            case .traditional:      return "????"
            case .hongKong:         return "???? (??)"
            }

        case .korean:               return "???"
        case .japanese:             return "???"
        }
    }
}

extension Language {

    init?(languageCode: String?) {
        guard let languageCode = languageCode else { return nil }
        switch languageCode {
        case "en", "en-US":     self = .english(.us)
        case "en-GB":           self = .english(.uk)
        case "en-AU":           self = .english(.australian)
        case "en-CA":           self = .english(.canadian)
        case "en-IN":           self = .english(.indian)

        case "zh-Hans":         self = .chinese(.simplified)
        case "zh-Hant":         self = .chinese(.traditional)
        case "zh-HK":           self = .chinese(.hongKong)

        case "ko":              self = .korean
        case "ja":              self = .japanese
        default:                return nil
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这样使用

var language: [Language] = [.korean, .english(.us), .english(.uk), .english(.australian), .english(.canadian), .english(.indian),
                            .chinese(.simplified), .chinese(.traditional), .chinese(.hongKong),
                            .japanese]

Bundle.set(language: languages[indexPath.row].language)
Run Code Online (Sandbox Code Playgroud)

选择语言画面


Locale.current.languageCode ”将始终返回系统设置语言。因此,我们必须使用“ Locale.preferredLanguages.first ”。但是,返回值看起来像“ ko-US”。这是问题!因此,我使LocaleManager仅获得语言代码。

LocaleManager.swift

import Foundation

    struct LocaleManager {

    /// "ko-US" ? "ko"
    static var languageCode: String? {
        guard var splits = Locale.preferredLanguages.first?.split(separator: "-"), let first = splits.first else { return nil }
        guard 1 < splits.count else { return String(first) }
        splits.removeLast()
        return String(splits.joined(separator: "-"))
}

    static var language: Language? {
        return Language(languageCode: languageCode)
    }
}
Run Code Online (Sandbox Code Playgroud)

这样使用

guard let languageCode = LocaleManager.languageCode, let title = RemoteConfiguration.shared.logIn?.main?.title?[languageCode] else {
      return NSLocalizedString("Welcome!", comment: "")
}
return title
Run Code Online (Sandbox Code Playgroud)


Onu*_*dur 6

以下是苹果公司关于更改语言的说法;

一般来说,您不应在应用程序中更改 iOS 系统语言(通过使用 AppleLanguages pref 键)。这违背了在“设置”应用程序中切换语言的基本 iOS 用户模型,并且还使用了未记录的首选项键,这意味着在将来的某个时候,键名称可能会更改,这会破坏您的应用程序。

因此,建议您将用户导航到应用程序的常规设置页面,该页面位于

设置 -> [your_app_name] -> 首选语言

为了直接从您的应用程序打开应用程序设置,您可以使用这些代码;

对于斯威夫特;

let settingsURL = URL(string: UIApplication.openSettingsURLString)!
UIApplication.shared.open(settingsURL, options: [:], completionHandler: nil)
Run Code Online (Sandbox Code Playgroud)

对于 Obj-C;

NSURL *settingsURL = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
[[UIApplication sharedApplication] openURL:settingsURL options:@{} completionHandler:nil];
Run Code Online (Sandbox Code Playgroud)

提示: 在导航到设置页面之前,最好弹出并说明用户切换到设置页面后应该做什么,这对于您的应用程序来说是更好的用户体验。