【问题标题】:iOS Localization: Best PracticesiOS 本地化:最佳实践
【发布时间】:2015-12-10 03:27:57
【问题描述】:

您在 iOS 本地化方面的最佳做法是什么? 我在本地化方面做了很多工作,但感觉还不够好且可扩展。需要有更好的方法。 这是我目前的做法:

使用 .strings 文件 + NSLocalizedString

  • 这很好用。尤其是在将字符串文件拆分成更小的部分时。但如果是很多小文件。添加另一种语言可能会很乏味。

将 .stringsdict 用于零、一、多等字符串

  • 这也很有效。缺点是一个词有很多“代码”。

为 Storyboard 使用 .strings 文件

  • 这是最棘手的部分。从情节提要本身生成 .string 文件并不难。但由于某种原因,无法更新字符串??所以。如果您将更多字符串添加到情节提要文件中,则无法在不重新生成的情况下将新字符串放入旧字符串中。这意味着您所有的旧翻译都将丢失。
  • 我已阅读并测试过 FileMerge。 (工作正常,但似乎还有很长的路要走)
  • 我已经阅读并测试了一些 python 脚本。 (根本不工作)

我尝试从 Xcode 创建一个 xliff 文件,但从未成功。 它总是无法导出文件。

错误信息: 读取字符串文件失败./..../Localizable.strings/ 数据格式不正确,无法读取。

那么.. 你如何处理 iOS 中的本地化字符串?尤其。您对故事板文件进行本地化的方法是什么?我见过人们在代码中设置所有本地化字符串。但为此创建大量IBOutlets 感觉是不必要的步骤。

【问题讨论】:

    标签: ios xcode localization storyboard nslocalizedstring


    【解决方案1】:

    我所做的最初是一项艰巨的任务,但从长远来看是值得的,就是将您的所有翻译放入一个 excel 文件中,然后将您的 excel 文档另存为 csv。然后我写了一个小解析器,它将把 csv 文件转换成字符串文件格式。如果您也有一个 android 项目,则可以很好地保持字符串对齐。

    【讨论】:

    • Excel 几乎是最糟糕的解决方案,因为它是手动的,而且对多种语言的支持很差
    【解决方案2】:

    .strings.stringsdict 确实运行良好。我不喜欢任何故事板翻译方法,恕我直言,它们太脆弱了,仅仅因为您添加/删除/或更改了故事板中的任何内容,就不得不再次完成整个循环。

    我采用以下方法取得了不错的效果:

    1. 在情节提要实体中对标题/副标题/占位符/文本使用 .strings 本地化键。
    2. 在您的 UIViewController 基类(或类别)中定义一个辅助函数,该函数遍历您的 UI 并使用您在情节提要中的键设置支持的小部件的本地化。

    我在viewDidLoad 中调用了辅助函数。这是一个例子:

    static void translateLocalizableStringsInView( UIView* v )
    {
        NSBundle* mainBundle = [NSBundle mainBundle];
        UIView* view = v;
    
        if ( [view isKindOfClass:UILabel.class] )
        {
            UILabel* label = (UILabel*)view;
            if ( label.text.length )
            {
                NSString* localizedString = [mainBundle localizedStringForKey:label.text value:nil table:nil];
                if ( localizedString.length )
                {
                    label.text = localizedString;
                }
            }
        }
        else if ( [view isKindOfClass:UITextField.class] )
        {
            UITextField* textField = (UITextField*)view;
            if ( textField.text.length )
            {
                NSString* localizedString = [mainBundle localizedStringForKey:textField.text value:nil table:nil];
                if ( localizedString.length )
                {
                    textField.text = localizedString;
                }
            }
            if ( textField.placeholder.length )
            {
                NSString* localizedString = [mainBundle localizedStringForKey:textField.placeholder value:nil table:nil];
                if ( localizedString.length )
                {
                    textField.placeholder = localizedString;
                }
            }
        }
        else if ( [view isKindOfClass:UIButton.class] )
        {
            UIButton* button = (UIButton*)view;
            NSString* title = [button titleForState:UIControlStateNormal];
            if ( title.length )
            {
                NSString* localizedString = [mainBundle localizedStringForKey:title value:nil table:nil];
                if ( localizedString.length )
                {
                    [button setTitle:localizedString forState:UIControlStateNormal];
                }
            }
        }
        else if ( [view isKindOfClass:UISegmentedControl.class] )
        {
            UISegmentedControl* sc = (UISegmentedControl*)view;
            for ( NSUInteger i = 0; i < sc.numberOfSegments; ++i )
            {
                NSString* title = [sc titleForSegmentAtIndex:i];
                if ( title.length )
                {
                    NSString* localizedString = [mainBundle localizedStringForKey:title value:nil table:nil];
                    if ( localizedString.length )
                    {
                        [sc setTitle:localizedString forSegmentAtIndex:i];
                    }
                }
            }
        }
    }
    
    
    
    @implementation UIViewController (LocalizableStrings)
    
    -(void)LT_translateLocalizableStringsInView
    {
        [self.view LT_iterateThroughAllSubviewsRecursively:YES usingBlock:^(UIView * _Nonnull view, BOOL * _Nonnull stop) {
            translateLocalizableStringsInView( view );
        }];
    
        if ( self.navigationItem.titleView )
        {
            translateLocalizableStringsInView( self.navigationItem.titleView );
        }
    }
    

    【讨论】:

      【解决方案3】:

      使用自 Xcode 6 起提供的导出/导入 XLIFF 功能。这是大多数翻译工具都知道的通用文件格式,Xcode 会为您保持一切同步。 WWDC 2014 也有一些会议对此进行了详细介绍。

      确保您的故事板位于 Base.lproj 中(这是新项目的默认设置),并且您正在使用具有本地化友好约束的自动布局(这是必要的,以便布局正确调整以适应不同长度的翻译) .

      【讨论】:

      • 好建议,但如上所述。尝试导出 xliff 文件时总是出现一些错误。读取字符串文件失败 ./..../Localizable.strings/ 由于格式不正确,无法读取数据。
      • 您不需要使用 XLIFF 导入/导出手动创建字符串文件。只需在您的代码中调用 NSLocalizedString ,它就会自动生成。如果您仍然遇到问题,请在 bugreport.apple.com 上提交错误,并附上一个示例项目,该项目重现了所附的问题,并在此处使用错误编号进行评论。谢谢!
      猜你喜欢
      • 2010-10-11
      • 2011-04-07
      • 1970-01-01
      • 2010-12-17
      • 1970-01-01
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多