Pull to refresh

Comments 23

Самый главный минус XLIFF — это отсутствие нормальной поддержки плурализации («один конь», «два коня»). Этого вполне достаточно, чтобы окончательно закопать эту технологию для нормального использования. Вся суть в (ещё более) удобном отделении данных о локализации и супер удобное взаимодействие с локализаторами. XLIFF распространенный формат, для него есть куча софта и он используется на разных платформах. Получается, что вашим локализаторам прийдется часть ресурсов размещать в XLIFF, а часть в проприетарном замороченном apple формате .stringsdict. Естественно они делать этого не будут (или будут плохо) и все прелести автоматизации сходят на нет.

Кстати, я решительно не согласен с предложенными вами способами именования ключей для строк («Auth», «Error»), в прошлом году я записал свои мысли на этот счет стандартных средств интернационализации тут.

Так что я бы рекомендовал какое-то другое решение для управления локализациями.
Самый главный минус XLIFF — это отсутствие нормальной поддержки плурализации («один конь», «два коня»).

Да это минус, но у меня с ним не было больших проблем.


Кстати, я решительно не согласен с предложенными вами способами именования ключей для строк («Auth», «Error»)

Такое именование ключей вызвано форматом XLIFF, потому что он не подразумевает работу с ключами. Он собирает таблички из оригинальной строки и перевода к ней. Если бы оригинальной строкой выступал был абстрактный ключ, то это было бы уже нарушением формата.

Можно поподробнее о «нарушении формата»? Поковырял интеграцию Xcode с XLIFF ещё раз и немного сам стандарт. Не понял про «таблички из оригинальной строки и перевода к ней». Ключи на языке разработки — это как раз та практика, которую предлагает Apple (я её не поддерживаю). Xcode работает с файлами ресурсов (т.е. ключи даже не обязательно использовать из кода) и он использует и ключ и перевод.

Например, для такой строчки:

/* Testy Commenty! */
"testy" = "ru Testy!";


Получается такой кусок в одном из XLIFF:

<trans-unit id="testy">
        <source>en Testy!</source>
        <target>ru Testy!</target>
</trans-unit>


Просто API работает так, что, если для ключа нет перевода, то NSLocalizedString + NSString возвращают ключ.
Или может быть я что-то упустил?
> Ключом выступает не абстрактная строка, а текст на Development Language. Если меняется оригинальный текст, то его приходится заново переводить.

При локализация ксибов я использую такой подход:

Для интерфейстых элементов создаю собственные сабклассы со свойством
@proprerty (nonatomic, strong) IBDesignable NSString* locKey;

В сеттере которого присваиваю текст, полученный из NSLocalizedString по присвоенному по свойству ключу.

Это свойство видно в Interface Builder, в него и нужно прописать ключ локализации.
Вот, точно! В категорию нельзя ли обернуть, кстати, это?
Только что проверил: внезапно, работает. То есть, не нужен даже сабкласс.
Вообще, я так запихиваю через Interface Builder многие вещи: шрифт из пресета, цвет placeholder'а у UITextField (который по умолчанию серый и не меняется в визуальном дизайнере), угол скругления, кастомный стиль кнопки и т.д. Практически всё, что обычно вручную делается в awakeFromNib можно реализовать таким образом.
Это я так же делаю, просто до упрощения локализации таким путем мысль еще не доходила.
Была идея вставлять ключи от строк прямо в текстовые поля и заменять на локализованные строки при инстанцировании и т.п. Но то была не оформленная идея, которая казалось немного кривой. А ваш способ, по-моему, идеален.
Вашу идею, кстати, я тоже реализовывал, до того как нашёл способ добавить свойство в Interface Builder.
Там есть некоторые трудности с тем, что для некоторых контролов текст может быть выставлен для любых состояний (всех сочетаний получается 16 штук), причём непонятно, какие из них действительно выставлены.
С другой стороны, если у вас для разных состояний тексты действительно отличаются — возможно лучше использовать именно этот путь.
Видел у ребят на соседних пару проектах это сделано через категории, они перенесли многие настройки UI компонентов (цвета, локализацию и что-то еще) в IB как раз через ibinspectable. Я не фанат такого, но оказалось реально удобно. Просто скетч проекта открываешь и копипастишь всё и в xcode, и код писать не надо.
И как это работает, например, с UIButton? Плохая идея сабклассить класс кластеры. Но вообще, если использовать нибы, IBDesignable действительно удобный инструмент.
UIButton — не кластер. Честно говоря, я не помню ни одного кластера среди наследников от UIView
Когда речь заходит про паттерн кластер в Cocoa, то обычно приводят в пример NSArray и UButton. Хотя я лично не проверял, каких именно типов возвращаются объекты из метода + (instancetype)buttonWithType:(UIButtonType)buttonType; Но пишут, что это наследники UIButton для не Custom типа…
Заглянул в доки — действительно, формально он не класс кластер (по крайней мере так не пишут прямо), так что тут я не прав. Но сабклассить его всё равно не стоит хотябы потому, что никто не гарантирует каким образом будет реализована иерархия классов и как API может измениться со временем.
Отличить кластер можно по возвращаему типу, не совпадающему с оригинальным. Для [NSArray array], например, это __NSArray0.
Конструкторы UIButton возвращает всегда UIButton. Так что даже если там внутри происходит какая-то «магия» — на наследование она не влияет.

> Но сабклассить его всё равно не стоит
В эппловской документации для таких классов содержится отдельное предупреждение (как, например, у UIWebView: «Subclassing Notes: The UIWebView class should not be subclassed.»)

В случае же кнопки — некоторые вещи просто невозможно реализовать без наследования (модификация intrinsicContentSize, например)
Да, всё верно, сейчас везде возвращается UIButton(по крайней мере -class возвращает его, не проверял все типы) и документация (обычно) явно описывает вопросы сабклассинга. Но, я помню времена, когда от типа зависел возвращаемый сабкласс. И достаточно много времени потратил на исследования различных хаков, которые применяет эппл под капотом. Сейчас не могу нагуглить, но я читал множество предостережений насчет UIButton и его отношения к class cluster, ребята из WWDC Labs советуют этого не делать.

То что это работает сейчас не значит, что это продолжит работать завтра. Сабклассить UIButton и навешивать это всё через IB — скользкая опасная дорога. Сегодня UIButton можно достаточно гибко кастумизировать, и я бы предпочел использовать средства UIButton, или сабкласс UIControl.
Ну, как уже выяснилось в соседней метке — IB видит в том числе и свойства, объявленные в категориях.

По поводу UIButton: я работаю с платформой начиная с iPhone OS 3.1.3, и не разу не замечал у UIButton признаков кластера, в отличии от того же NSArray. Возможно — я был недостаточно внимателен. Возможно — вы что-то путаете.

По поводу наследования: не вижу ни одного повода от него отказываться — это основная концепция ООП.
К тому же нужно всего лишь следить за отсутствием конфликтов имён и не использовать приватные методы. Для того, чтобы при таком подходе что-то сломалось — Эппл должен переписать половину SDK, по пути сломав половину приложений из AppStore. Этого не случится никогда.

Аналогичная ситуация, но признаки я встречал, поэтому сейчас немного удивлен их отсутствием.

Насчет опасности: я не про навешивание свойств в категории, это не будет работать, только если они выплюнут «бинарно совместимый» класс и засвиззлят -class и кучу всего ещё. Такое бывает, но редко и нам об этом никто не рассказывает. Такое действительно очень маловероятно.

Насчет наследования сейчас просто начнется холивар, так что, думаю, не стоит его начинать, всем понятна противоположная точка зрения.
Чтобы быстро тестировать приложение под другой локалью, можно добавить в настройки схемы (или создать копий схемы под каждую локаль и язык) пару аргументов для Run. А именно:
  • выбрать схему
  • выбрать Edit Scheme в выпадающем меню
  • выбрать Run
  • выбрать Arguments
  • добавить -AppleLocale de_De
  • выбрать -AppleLanguages (de)

Параметры в скобках соответствуют международным стандартам и легко гуглятся.
Xcode Version 8.3.3 (8E3004b).
Для того, чтобы оставить приложению только русский язык теперь есть другой способ (возможно и был, не проверял на версиях старее).

Итак, цель: Один язык в приложении кроме английского.
1. Идем в настройки проекта (не Target), в списке ищем Localizations. Удаляем все лишние языки.
2. Идем в Target проекта (или extensions) -> Info -> Localization native development пишем «ru» для русского, для других языков смотри список (Настройки проекта — Localizations -> "+" открывается список с названием языка и коротким названием).
3.Чистим проект, удаляем приложение с девайса.

Итого: всегда русский язык в приложении
Sign up to leave a comment.