Раскадровка /XIB и лучшие практики локализации
Официально рекомендуемый метод локализации XIB/Storyboard - создавать файлы.xib и.storyboard внутри xx.lproj (где xx - двухбуквенный идентификатор языка) для каждой локализации, которую вы хотите поддерживать.
Это создает проблему, потому что у вас есть несколько файлов, которые во многих случаях имеют один и тот же пользовательский интерфейс, которые подвержены изменениям. Если вы хотите изменить дизайн пользовательского интерфейса для одного представления, вам придется делать это несколько раз (хуже, если вы ввели локализуемые строковые значения в самой XIB). Это идет вразрез с принципом СУХОЙ.
Кажется, это более эффективно, чтобы позвонить NSLocalizedString()
где вам это нужно, и просто используйте один XIB или раскадровку для одной базовой локализации.
Итак, почему (не) я должен создавать локализованные файлы XIB/Storyboard?
11 ответов
Для просто изменения текстовых меток я сделал что-то вроде этого
+(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.
Таким образом, вы можете хранить все свои строки в одном файле, и вам не нужно создавать отдельные 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
Добавил бы это как комментарий к вышеупомянутому решению, но у меня нет никакого представителя!
Как пояснил Leszek S, вы можете создать категорию.
Здесь я приведу пример в swift 3 с расширением для UILabel и UIButton:
- Прежде всего создайте файл "StringExtension.swift"
Добавьте к этому этот код:
extension String { func localized() -> String { let bundle = Bundle.main return NSLocalizedString(self, tableName: nil, bundle: bundle, value: "", comment: "") } }
Затем создайте еще один новый файл с нужным именем (например) "LocalizableObjectsExtensions.swift"
Добавьте на него расширение для 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! } } }
Теперь зайдите в раскадровку и для вашей кнопки и / или ярлыка, который вы хотите локализовать, просто добавьте в инспектор идентификации вашего объекта это:
К сведению: здесь Key Path - это имя функции, которую вы добавили в свои расширения (UIlabel и UIButton), а Value - это имя ключа, который вы хотите автоматически перевести, который находится в вашем файле Localizable.strings. Например, в вашем Localizable.strings (французский) у вас есть ключ / значение "ourOffers" = "NOS OFFRES";
Теперь построй и беги. Ваш объект будет переведен на язык вашего устройства, если у вас есть ключ / значение в вашей Localizable.string. Наслаждаться:)
Вы можете автоматизировать многое из этого с ibtool
, это достойное введение: http://www.bdunagan.com/2009/03/15/ibtool-localization-made-easy/
Полезный пост, намного проще, чем несколько XIB. Я расширил код для обработки 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];
}
}
Я искал именно тот ответ, который дал Лен, помеченный как правильный, но он мне нужен в Свифте. Так что я перевел на это. Спасибо, Лен.
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 для каждого языка, сообщите нам об этом.
Я использовал тот же подход, который описал Лешек Сзари для моих взглядов в Swift.
Используя логическое значение в отличие от ключей локализации, я добавил выпадающее меню "Вкл / Выкл", которое определяет, должны ли исходные текстовые значения быть локализованы или нет. Это позволяет поддерживать раскадровку в чистоте без дополнительного ухода.
Когда выбрано значение, к представлению добавляется один атрибут времени выполнения, который используется как условие из его установщика.
Вот код из моего файла.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
IMHO Xcode имеет одну из худших функций локализации, доступных...
Мне действительно не нравится разрабатывать для Android, но я должен признать, что Android Studio имеет лучшую систему локализации.
Тем не менее, потому что я действительно не могу больше воссоздавать Storyboard.strings после каждого мода (вы знаете, Xcode не будет обновлять их для вас...), вот как я делаю:
У меня есть несколько расширений для циклических подпредставлений (и подпредставлений подпредставлений), и я имею дело с каждым из основных объектов (надписи, текстовое поле, кнопки...), локализуя их основные свойства (текст, заполнение...) с помощью простого helper (AltoUtil.ls), который является "короткой" версией для NSLocalizedString.
Затем я вставляю тексты и заполнители с подчеркиванием (например, "_first_name", "_email_address") в свою раскадровку /xibs и добавляю эти строки в каждый файл Localizable.strings.
Теперь мне просто нужно вызвать функцию localize() в viewDidLoad (или где мне это нужно), чтобы я мог локализовать весь контроллер представления. Для ячеек я просто вызываю localize() внутри метода awakeFromNib(), например.
Я уверен, что это не самый быстрый метод (из-за цикла subviews), но я не испытываю замедления по сравнению с другими методами, которые я использовал, и он довольно продуктивен.
import UIKit
extension UIView {
func localize()
{
for view in self.allSubviews()
{
if let label = view as? UILabel
{
label.text = AltoUtil.ls(label.text)
}
else if let textField = view as? UITextField
{
textField.text = AltoUtil.ls(textField.text)
textField.placeholder = AltoUtil.ls(textField.placeholder)
}
else if let button = view as? UIButton
{
button.setTitle(AltoUtil.ls(button.title(for: UIControl.State.normal)), for: UIControl.State.normal)
}
else if let searchBar = view as? UISearchBar
{
searchBar.placeholder = AltoUtil.ls(searchBar.placeholder)
}
}
}
func allSubviews() -> [UIView]
{
return subviews + subviews.flatMap { $0.allSubviews() }
}
}
Второе расширение необходимо для локализации элементов заголовка и панели вкладок контроллеров представления в контроллерах представления. Вы можете добавить любой предмет, который нужно локализовать.
import UIKit
extension UIViewController {
func localize()
{
self.title = AltoUtil.ls(self.navigationItem.title)
self.tabBarItem?.title = AltoUtil.ls(self.tabBarItem?.title)
self.view.localize()
}
}
Я наткнулся на этот пост и несколько других, пытаясь упростить локализацию xib для себя. Я опубликовал свой метод включения IBOutles для надписей / кнопок по этому вопросу, отлично сработал для меня, ограничивает все изменения файлами Localization.strings.
/questions/39232429/lokalizatsiya-iphone-dlya-fajlov-xib/39232444#39232444