Раскадровка / XIB и лучшие практики локализации

на официально рекомендуемый метод для XIB/раскадровка локализации является создание .xib and .раскадровка файлов внутри xx.lproj (где xx-идентификатор языка с двумя буквами) для каждой локализации, которую вы хотите поддерживать.

это создает проблему, потому что у вас есть несколько файлов, которые во многих случаях имеют один и тот же пользовательский интерфейс, которые подвержены изменениям. Если вы хотите перепроектировать пользовательский интерфейс для одного представления, вам придется сделать это несколько раз (хуже, если вы ввели локализуемую строку значения в самом xib). Это противоречит принципу сухости.

Кажется более эффективным вызвать NSLocalizedString() где вам это нужно, и просто используйте один XIB или раскадровку для одной базовой локализации.

Итак, почему я должен (не) создавать локализованные файлы XIB / раскадровки?

10 ответов


для изменения текста надписи Я сделал что-то вроде этого

+(void) replaceTextWithLocalizedTextInSubviewsForView:(UIView*)view
{
    for (UIView* v in view.subviews)
    {
        if (v.subviews.count > 0)
        {
            [self replaceTextWithLocalizedTextInSubviewsForView:v];
        }

        if ([v isKindOfClass:[UILabel class]])
        {
            UILabel* l = (UILabel*)v;
            l.text = NSLocalizedString(l.text, nil);
            [l sizeToFit];
        }        

        if ([v isKindOfClass:[UIButton class]])
        {
            UIButton* b = (UIButton*)v;
            [b setTitle:NSLocalizedString(b.titleLabel.text, nil) forState:UIControlStateNormal];
        }        
    }    
}

вызовите эту функцию в своем viewDidLoad: такой:

[[self class] replaceTextWithLocalizedTextInSubviewsForView:self.view];

это сэкономило мне много работы, объявив и подключив IBOutlets, когда все, что вы хотите, это локализованные метки.


вы можете сделать категорию на UILabel, UIButton и т. д. вот так:

#import "UILabel+Localization.h"

@implementation UILabel (Localization)

- (void)setLocalizeKey:(NSString*)key
{
    self.text = NSLocalizedString(key, nil);
}

@end

и после этого в вашем xib-файле используйте пользовательские атрибуты среды выполнения для связи UILabel (или UIButton и т. д.) к ключу, сохраненному в вашем Localizable.strings file

user defined runtime attributes

таким образом, вы можете иметь все ваши строки в одном файле и вам не придется создавать отдельный xib для каждого языка.


решение льна работает хорошо, одна вещь, чтобы отметить, что если у вас есть UILabels или UIButtons, которые содержатся в UICollectionViewCells на UICollectionViews (или аналогичный) и эти коллекции часто меняются в текущем представлении, например, из-за действия пользователя или заполняются асинхронным запросом, а затем для обновления меток с правильными строками локализации вы можете вызвать функцию локализации в viewDidLayoutSubviews вместо viewDidLoad (который вызывается только один раз):

- (void)viewDidLayoutSubviews
{
    [LocalizationHelper replaceTextWithLocalizedTextInSubviewsForView:self.view];
}

как можно как видно из этого кода, я сохраняю метод локализации в статическом вспомогательном классе (как предложил другой глава):

@implementation LocalizationHelper

+(void) replaceTextWithLocalizedTextInSubviewsForView:(UIView*)view
{
    for (UIView* v in view.subviews)
       ... <code from above> ...
}
@end

добавил бы это в качестве комментария к вышеуказанному решению, но у меня нет репутации!


вы можете автоматизировать многое из этого с помощью ibtool. это достойное введение: http://www.bdunagan.com/2009/03/15/ibtool-localization-made-easy/


как объяснил Лешек S, Вы можете создать Категорию.

здесь я приведу вам пример в swift 3 с расширением для UILabel и UIButton:

  1. прежде всего создайте"StringExtension.Свифт!--10--> файл"
  2. добавьте на него этот код:

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

  3. создайте еще один новый файл с именем, которое вы хотите (например) "LocalizableObjectsExtensions.Свифт!--10-->"
  4. добавьте на него расширение для UIButton и один для UILabel, как это (конечно, вы можете создать расширение для того, что вы хотите, UITextField...):

    extension UIButton { var localizedText: String { set (key) { setTitle(key.localized(), for: .normal) } get { return titleLabel!.text! } } }

    extension UILabel { var localizedText: String { set (key) { text = key.localized() } get { return text! } } }

  5. Теперь перейдите в раскадровку и для вашей кнопки и / или метки, которую вы хотите локализовать, просто добавьте в Инспектор идентификации Вашего объекта это:

enter image description here

FYI: здесь ключевой путь-это имя функции, добавленной в ваши расширения (UIlabel и UIButton), а значение-это имя ключа, который вы хотите перевести автоматически, который находится в вашем локализации.струны. Например, в вашем локализации.strings (French) у вас есть ключ / значение "ourOffers" = "NOS OFFRES";

Теперь build & Run. Ваш объект будет переведенные на язык вашего устройства, если у вас есть ключ/значение в вашей локализации.строка. Наслаждайтесь :)


Полезный пост, намного проще, чем несколько XIBs. Я расширил код для обработки UISegmentedControl:

if ([v isKindOfClass:[UISegmentedControl class]]) {
    UISegmentedControl* s = (UISegmentedControl*)v;
    for (int i = 0; i < s.numberOfSegments; i++) {
        [s setTitle:NSLocalizedString([s titleForSegmentAtIndex:i],nil) forSegmentAtIndex:i];
    }
}

Я искал точный ответ, данный льном, отмеченный как правильный, но мне нужно было это в Swift. Поэтому я перевел на него. Спасибо, Лен.

    func replaceTextWithLocalizedTextInSubviewsForView(view: UIView) {

    for v in view.subviews {

        if v.subviews.count > 0 {
            self.replaceTextWithLocalizedTextInSubviewsForView(v)
        }

        if (v.isKindOfClass(UILabel)) {
            let myLabel: UILabel = v as! UILabel
            myLabel.text = NSLocalizedString(myLabel.text!, comment: "Text to translate.")
            myLabel.sizeToFit()
        }

        if (v.isKindOfClass(UIButton)) {
            let myButton: UIButton = v as! UIButton
            myButton.setTitle(NSLocalizedString((myButton.titleLabel?.text)!, comment: "Text to translate.") as String, forState: .Normal)
            myButton.sizeToFit()
        }
    }
}

это работает для Swift 2.1


в каждом месте, где я смотрю, говорится, что вы должны реплицировать весь xib-файл для каждого экземпляра локализации, даже если вы действительно хотели только вырвать текст и реплицировать текст на другом языке для каждого экземпляра локализации.

Если кто-нибудь знает о методе репликации только видимого пользователем текста xib (на другом языке) без репликации всего xib-файла для каждого языка, пожалуйста, сообщите нам об этом.


я наткнулся на этот пост и несколько других, пытаясь облегчить локализацию xib для себя. Я опубликовал свой метод включения IBOutles для меток / кнопок по этому вопросу, отлично работал для меня, сохраняет все изменения, ограниченные локализацией.файлы строк.

https://stackoverflow.com/a/15485572/1449834


я использовал аналогичный подход, как Лешек Сары описал для моих взглядов в Swift.

используя логическое значение в отличие от ключей локализации, я добавил выпадающее меню" Вкл/Выкл", которое определяет, должны ли быть локализованы начальные текстовые значения или нет. Это позволяет держать раскадровку в чистоте без дополнительного ухода.

Image1

при выборе значения в представление добавляется один атрибут среды выполнения, который используется как состояние изнутри это сеттер.

Image2

Image3

вот код от моей .swift файл, который расширяет UIButton, UILabel, UITabBarItem и UITextField, включая заполнитель текстового поля и кнопки управления состояниями:

import UIKit

extension String {
    public var localize: String {
        return NSLocalizedString(self, comment: "")
    }
}

extension UIButton {
    @IBInspectable public var Localize: Bool {
        get { return false }
        set { if (newValue) {
            setTitle( title(for:.normal)?.localize,      for:.normal)
            setTitle( title(for:.highlighted)?.localize, for:.highlighted)
            setTitle( title(for:.selected)?.localize,    for:.selected)
            setTitle( title(for:.disabled)?.localize,    for:.disabled)
        }}
    }
}

extension UILabel {
    @IBInspectable public var Localize: Bool {
        get { return false }
        set { if (newValue) { text = text?.localize }}
    }
}

extension UITabBarItem {
    @IBInspectable public var Localize: Bool {
        get { return false }
        set { if (newValue) { title = title?.localize }}
    }
}

extension UITextField {
    @IBInspectable public var Localize: Bool {
        get { return false }
        set { if (newValue) {
            placeholder = placeholder?.localize
            text = text?.localize
        }}
    }
}

вы также можете использовать новое свойство, чтобы легко переводить значения, которые установлены, пока ваша программа работает следующим образом:

let button = UIButton()

button.setTitle("Normal Text", for: .normal)
button.setTitle("Selected Text", for: .selected)

button.Localize = true