【问题标题】:Set iOS language without restarting在不重启的情况下设置 iOS 语言
【发布时间】:2016-01-26 22:20:38
【问题描述】:

我知道有很多帖子说不应该这样做,或者说不可能。我修改了一些想法,现在我要问这个问题,因为我想绝对确定没有其他选择。

选项 1:

最流行的解决方案是将AppleLanguages 更改为this 帖子中的内容。我不介意要求重启的想法,所以这对我来说是一个可以接受的解决方案,除了你不能以编程方式重启你的应用程序(找不到方法,或者会被 Apple 拒绝)。要求用户手动重启应用程序并不理想。

选项 2:

下一个解决方案是获取适当的捆绑包并对每个 UILabelUIButton 等执行 localizedStringForKey 查找。这可能有点乏味,但对我来说没关系,因为我已经添加了本地化属性(类似于this)到这些视图,这样我就可以有一个集中的字符串文件。

AppDelegate.swift:

static var userLanguage: String?
    {
        set
        {
            let defaults = NSUserDefaults.standardUserDefaults();
            defaults.setObject(newValue, forKey: LanguageKey);
            defaults.synchronize();

            let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle());
            instance.window?.rootViewController = storyboard.instantiateInitialViewController();
        }

        get
        {
            let defaults = NSUserDefaults.standardUserDefaults();
            return defaults.stringForKey(LanguageKey);
        }
    }

Localization.swift:

private var bundle: NSBundle
{
    get
    {
        let bundle: NSBundle;
        #if TARGET_INTERFACE_BUILDER
            bundle = NSBundle(forClass: self.dynamicType);
        #else
            bundle = NSBundle.mainBundle();
        #endif

        let lang: String;
        if(AppDelegate.userLanguage == nil || AppDelegate.userLanguage == "en")
        {
            lang = "Base";
        }
        else
        {
            lang = AppDelegate.userLanguage!;
        }

        let path = bundle.pathForResource(lang, ofType: "lproj");
        if(path != nil)
        {
            let toreturn = NSBundle(path: path!);
            if(toreturn != nil)
            {
                return toreturn!;
            }
        }

        return bundle;
    }
}

extension UILabel
{
    @IBInspectable var localizedText: String?
    {
        get { return "" }

        set
        {
            if(newValue != nil)
            {
                text = bundle.localizedStringForKey(newValue!, value:"", table: nil);
            }
        }
    }
}

选项 2 的问题在于,它只为这些字段设置语言。布局方向不变,不使用语言特定布局等文件。

通过扩展 UIApplication,我可以指定一个自定义的 userInterfaceLayoutDirection,它成功地在 LTR 和 RTL 之间交换所有布局。

DemoApplication.swift:

class DemoApplication: UIApplication
{
    override internal var userInterfaceLayoutDirection: UIUserInterfaceLayoutDirection
    {
        get
        {
            if(AppDelegate.userLanguage == "ar")
            {
                return UIUserInterfaceLayoutDirection.RightToLeft;
            }

            return UIUserInterfaceLayoutDirection.LeftToRight;
        }
    }
}

现在,当我设置AppDelegate.userLanguage 时,应用程序将重置为初始视图控制器,显示新语言,在 LTR 和 RTL 之间翻转布局。这确实没有解决语言特定文件的问题,而且我还注意到文本在其自身范围内保持左对齐或右对齐。

因为我找不到原生 iOS 类的源代码,所以我看不到在启动时设置了哪些语言特定的变量,所以我假设它链接到 NSBundle.mainBundle。我尝试使用方法swizzling 覆盖它。

extension NSBundle
{
    override public class func initialize()
    {
        struct Static
        {
            static var token: dispatch_once_t = 0;
        }

        // make sure this isn't a subclass
        if (self !== NSBundle.self)
        {
            return;
        }

        dispatch_once(&Static.token)
        {
            do
            {
                try jr_swizzleClassMethod("mainBundle", withClassMethod: "mainBundleExt");
            }
            catch
            {
                print("\(error)");
            }
        }

        super.initialize();
    }

    public class func mainBundleExt() -> NSBundle
    {
        let bundle = self.mainBundleExt();  // Due to swizzling, this is the "super" method

        let lang: String;
        if(AppDelegate.userLanguage == nil || AppDelegate.userLanguage == "en")
        {
            lang = "Base";
        }
        else
        {
            lang = AppDelegate.userLanguage!;
        }

        let path = bundle.pathForResource(lang, ofType: "lproj");
        if(path != nil)
        {
            let toreturn = NSBundle(path: path!);
            if(toreturn != nil)
            {
                return toreturn!;
            }
        }
    }
}

但这不起作用,似乎仍然使用默认的mainBundle

所以我的问题是:mainBundle 是如何赋值的?启动时设置了哪些其他语言特定的变量,例如userInterfaceLayoutDirection。 我假设有 2 或 3 个这些变量。最后,这是否可行,还是我只是在浪费时间?

谢谢。

【问题讨论】:

  • check this question。这是无需重新启动应用程序的最简单和最好的方法...
  • 感谢您的链接。我仔细看了看,它似乎与我尝试过的很接近。似乎没有处理 LTR 和 RTL 之间的切换,还是我遗漏了什么?
  • @Kevin 您找到 LTR 和 RTL 问题的解决方案了吗?
  • @TawaNicolas 不幸的是,我已经有一段时间没有在 iOS 中工作了。很抱歉没有任何帮助。
  • 不支持在外观()代理上设置语义内容属性。您将遇到许多其他问题和错误,因为该应用程序仍然认为它运行的语言不是您要覆盖的语言。向您的应用程序添加语言切换器只会使其更加混乱;用户希望他们的应用遵循他们设备设置的语言。

标签: ios swift localization


【解决方案1】:

我以前遇到过这个问题,我使用过一个库。它帮助我即时更改语言。 尝试使用这个: https://github.com/Decybel07/L10n-swift

L10n.shared.language = "en"
L10n.shared.language = "en-GB"

运行时,可以通过设置语言属性随时切换语言

【讨论】:

  • 如果我错了请纠正我,但这个库似乎不处理userInterfaceLayoutDirection。它提供了几个根据 L10n 填充其内容的 UI 元素
【解决方案2】:

使用这行代码,它会在不关闭应用程序的情况下更改布局。从右到左

UIView.appearance().semanticContentAttribute = .forceRightToLeft

对于从左到右翻转

UIView.appearance().semanticContentAttribute = .forceLeftToRight

如果您想更改文本字段布局或文本更改,请使用此代码,因为我遇到了这个问题。文本字段的文本没有改变布局。检查此代码以更改文本字段文本的布局

extension UITextField {
open override func awakeFromNib() {
        super.awakeFromNib()
        if UserDefaults.languageCode == "ar" {
            if textAlignment == .natural {
                self.textAlignment = .right
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    • 1970-01-01
    • 2013-08-05
    • 2010-09-15
    • 2016-05-31
    • 1970-01-01
    • 2016-11-21
    相关资源
    最近更新 更多