Доброго времени суток! Представляю вашему вниманию вольный перевод статьи от GDE (Google developer expert) Dmytro Danylyk. Собственно, вот оригинал. Статья описывает правильные подходы для работы со strings.xml и особенно полезно это будет разработчикам, которые разрабатывают мультиязыковые приложения. Прошу под кат.



Эта статья о такой тривиальной вещи android как string.xml.


Не используйте повторно


Не используйте повторно строки для разных экранов

Давайте представим, что у вас есть loading dialog на Sign In либо Sign Up экране. Так как оба экрана имеют loading dialog, вы решаете использовать те же строки — R.string.loading.


image

res/values/strings.xml.


Позже, если вы решите использовать различные, вам нужно будет создать 2 разные строки и модифицировать их, непосредственно, в .java классах. Если вы используете разные строки с начала — вам бы пришлось модифицировать лишь strings.xml файл.


image

res/values/strings.xml


Вы никогда не будете заранее знать поддержку и перевод какого языка вам предстоит добавить. Всё дело в контексте: в одном языке вы можете использовать тоже слово в одном контексте, но в другом — это слово по смыслу не будет подходить.


image

res/values/strings.xml


image

res/values-UA/strings.xml


Обратите внимание, что в данном случае английская версия strings.xml использует тоже самое слово — “Yes” для обоих случаев R.string.download_file_yes и R.string.terms_of_use_yes strings.
Но украинский вариант strings.xml использует 2 разных слова — “Гаразд” для R.string.download_file_yes и “Так” для R.string.terms_of_use_yes.


Разделяйте


Разделяйте строки, которые относятся к одному экрану с помощью префиксов и комментариев

image

res/values/strings.xml


  1. Добавляйте префикс в виде имени экрана к каждой строке для более простого понимания к какому экрану относится данный ресурс.
  2. Чистый string.xml файл поможет достаточно легко поддерживать и переводить различные языки — экран за экраном.

Создание различных strings.xml для каждого экрана

Если вы хотите, вы можете создать string.xml файл для каждого экрана — settings-strings.xml, profile-strings.xml. Но обычно приложение имеет около 10-20 экранов, соответственно, нужно иметь 10-20 string.xml файлов в каждой языковой папке. Я думаю, что это будет сопряжено с беспорядком.


Форматирование


Используйте Resources#getString(int id, Object… formatArgs) для форматирования строк

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


image

res/values/strings.xml


image

java code


Правильный путь — использовать Resources#getString(int id, Object… formatArgs).


image

res/values/strings.xml


image

res/values-UA/strings.xml


image

java code


Множественное число


Используйте Resources#getQuantityString(int id, int quantity) для количественных строк

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


image

res/values/strings.xml


image

java code


Правильный путь это использовать Resources#getQuantityString(int id, int quantity)


image

res/values/strings.xml


image

java code


Подстветка слов


Используйте html text для подсветки статический слов

Если вы хотите изменить цвет некоторых слов в TextView — ForegroundColorSpan не всегда лучший вариант, потому как подсветка выполняется через индекс и это не безопасно в мультиязыковом приложении. Лучше использовать html font color tags внутри вашего strings.xml файла.
Представим у вас есть текст “Discover and play games.” и вы хотите выделить “Discover” слово и “play” слово синим цветом.


image

res/values/strings.xml


image

java code

Поделиться с друзьями
-->

Комментарии (32)


  1. withoutuniverse
    15.08.2016 20:54
    +5

    Код картинками — что-то новенькое :)

    Ниже замечания по делу:
    1. Для строковых ресурсов так, как вы написали, не напишешь.
    Вот правильный пример:

    <string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>

    2. Plurals не всегда корректно работают с локалями.
    3. Для облегчения перевода одинаковые строки можно объединить в одну, а остальные ссылать на нее:
    <string name="my_string">111</string>
    <string name="your_string">@string/my_string</string>

    4. Чтобы проще было разделять ресурсы по блокам, не обязательно использовать конструкцию, как у вас
    <!-- Работает -->
    // Тоже работает!
    <string name="...">...</string>


    1. lazexe
      15.08.2016 21:21

      Тот момент когда комментарий к статье на уровне полезной статьи :)


      1. withoutuniverse
        15.08.2016 22:04

        Статья полезная, а из моего комментария реально полезен пожалуй только 3 пункт.
        Но спасибо :)


    1. Bringoff
      15.08.2016 21:25
      -1

      1. Можно и так, как в статье. Цифры нужны только для изменения порядка использования параметров.
      2. А можно вообще регионы использовать.


      1. withoutuniverse
        15.08.2016 22:02

        По 1 замечанию, еще с год назад у меня так не выходило написать, странно. Сейчас попробовал и всё сработало как часы, спасибо.
        По 2 пункту — о каких регионах речь?


        1. withoutuniverse
          17.08.2016 10:06

          Сейчас это работает только для 1 параметра.
          При наличии 2 и более будет выдана ошибка:

          Error:(1264) Multiple substitutions specified in non-positional format; did you mean to add the formatted=«false» attribute?
          Наверное потому мы везде использовали %1$, даже при наличии лишь 1 параметра — выглядит целостнее.


        1. Bringoff
          17.08.2016 20:56

          region description

          ...


          endregion

          Ctrl+Alt+T нажмите.


    1. iamtodor
      15.08.2016 23:10
      -1

      1. Выше приведен пример, что все работает.
      2. В статье был сделан акцент на разделении строк, а ваш пункт №3 категорически этому противоречит.
      3. Я бы сказал, что это зависит от code style, в xml не принято ставить такого типа комментарии
        // Also works


      1. fRoStBiT
        16.08.2016 10:30
        +1

        По поводу пункта №3:
        Мне кажется, что дублирвать значения в XML смысла никакого нет. Главное, чтобы Java-код ссылался на разные строки.
        Принцип

        Если вы используете разные строки с начала — вам бы пришлось модифицировать лишь strings.xml файл.
        соблюдается.


    1. aelimill
      16.08.2016 10:30
      -1

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


    1. Azzdorf
      17.08.2016 09:29
      -1

      1) в десятках проектов нигде не встречал %1$s, везде было через %s, что самое интересное, так в документации показываются оба варианта, но во всех «официальных» sample я видел только %s, так что считать какой-то из вариантов неправильным, а единственный истинным — это абсолютизм на уровне ситхов
      2) активно пользую в проектах, в т.ч. с right-to-left локалями, пока ни разу не корректностей не встречал, буду ОЧЕНЬ благодарен за конкретные локали или проблемные варианты использования
      3) поддержу автора — ссылки на строки внутри хорошо, если мало локалей, но как только переваливает через 10 языков и в команде от 5 человек, которые паралельно работают с строковыми ресурсами, то это превращается в постоянный рефакторинг строковых ресурсов, проще сразу разделять сразу разделять
      4) // — недопустимо для xml, и пока мало локалей то всё ок, но если приходится, ДАЖЕ ИНОГДА, прибегать к сторонним утилитам для сверки и консолидации переводов — это будет первое место для ругани


      1. withoutuniverse
        17.08.2016 09:50

        В десятках своих проектов? В десятках опенсорсных? В десятках фрилансовых на сапорте?
        Не пытаюсь что-то доказать, но я встречал лишь несколько реально крупных проектов, написанных не мной. Примером может послужить Telegram. По ссылке вот тут xml для русской локализации — ССЫЛКА и там нету Plurals и %s. Наверное о чем-то это говорит у проекта с многомилионной аудиторией. Или вы думаете, что они просто не умеют?

        По поводу ссылок на свои же ресурсы — это же даже не рекомендация, я написал что можно так делать. Как плюс — можно добиться существенной экономии на переводе.
        По // тоже самое, так можно, но я же не настаиваю :)


        1. Azzdorf
          17.08.2016 09:58
          -1

          т.е.
          2. Plurals не всегда корректно работают с локалями.
          это просто предположение? спрашиваю серьезно, так как активно ими пользуюсь при разработки или не трогаю их при рефакторинге

          сорри если показалось сильной критикой с моей стороны, просто я прывик что 90% стоимости кода — это его поддержка и в данном случаи Ваши варианты (3 и 4) ведут к усложнению саппорта


          1. withoutuniverse
            17.08.2016 10:17

            К сожалению, дело давнее, потому и личных пруфов по Plurals не предоставлю, но это не предположение точно. Помню лишь, что проблемы были именно с локализацией. Гугл нашел как минимум одну проблему с ними, когда quantity равна нулю ССЫЛКА.
            У нас на проектах используется MessageFormat.


            1. Azzdorf
              17.08.2016 12:04

              Спасибо, полезно для развития
              все кто жалуется на логику жалуются, по сути, на стандарт (unicode), с самими plurals проблем нет
              также многие путают порядковые и количественные, что также вызывает необоснованный негатив


        1. Azzdorf
          17.08.2016 10:14
          -1

          пробежался по stackoverflow
          не одной заявления о некорректной работе strings plurals

          как правило strings plurals — везде отмечен как правильный ответ на вопрос об локализации множественных
          по указаной Вами ссылке не нашел ни одного места, где бы plurals вообще можно бы было использовать (просто небыло потребностей)


          1. withoutuniverse
            17.08.2016 12:00

            Выше я ответил — плохо пробежался значит.
            Вот комментарий по проблемам с Plurals от vikarti, помимо моей ссылки на SO — #comment


            1. Azzdorf
              17.08.2016 12:10
              -1

              там пролема не с plurals а с восприятием людьми стандарта unicode на котором он основан


        1. Bringoff
          17.08.2016 20:53

          Не стоит для аргументации использовать telegram. Он (там один разработчик клиента) переписал половину андроид, даже саппорты гугловые не использует, я не удивлен, что и в строках он что-то не применяет.


          1. withoutuniverse
            17.08.2016 21:27

            Вы избирательно читаете комментарии. Уже обсудили, что %s работает только при наличии 1 параметра. При наличии 2 и более — обязательно нумеровать их. Стиль и код выглядит целостнее, когда всё одинаково. Про plurals тоже обсудили уже, они могут навредить при работе с локализациями, при этом только на старых версиях андроида вроде как. Да и MessageFormat более гибок, чем телеграм и пользуется.
            Почему не стоит его использовать при аргументации? Если проект имеет многомиллионную аудиторию и что-то не использует — стоит задуматься «почему?». Я исследовал их исходники, код не идеален с точки зрения читабельности, но фрагменты не используются в угоду скорости и плавности анимаций, коих с фрагментами объективно не добиться. Класс BaseFragment есть, просто он не extends Fragment.

            Странно, что автор не участвует в дискуссии, мне его статься витися интересной.


            1. Bringoff
              17.08.2016 21:54

              Я отвечаю на те комментарии, на которые считаю необходимым.
              Не пойму аргументации о единстве стиля. А чем "везде, где один аргумент, писать %s" не стиль? Если изменится количество аргументов, все равно код и строку менять придется.
              Количество пользователей вообще никак не коррелирует с качеством кода и используемых подходов. Что телеграмм на практике доказывает. Он занимается велосипедостроением, оправдывая это стремлением к стабильности. Если ресурсы телеграмма позволяют писать собственную реализацию sqlite, им везёт, большинство проектов к такому не готовы. Да и смысла нет.


  1. Revertis
    15.08.2016 20:57

    Множественное написание string.xml (в единственном числе) это много ошибок, или так и задумано?


    1. konstantin_berkow
      15.08.2016 22:19

      Проверил, во всех проектах всегда генерируется strings.xml


      1. Revertis
        16.08.2016 07:28

        В статье тогда поисправляйте везде!


    1. malakhv
      16.08.2016 10:29
      +1

      Ну по большому счету, имя файла не имеет никакого значения.


  1. samodum
    15.08.2016 23:49

    «то же самое»!


  1. artemgapchenko
    16.08.2016 08:10

    deleted.


  1. andreich
    16.08.2016 08:31
    +2

    Для себя заметил, что когда разделяешь сроки по экранам префиксами, то удобней пользоваться точками, нежели нижним подчеркиванием.
    Я, например, делаю вот так, профит замечаешь позже, главное не скатиться с такого именования

    <string name="history.status.received">Получен</string>
    <string name="history.status.canceled">Отклонен</string>
    


    В java коде правда это автоматом заменяется на такую конструкцию
    R.string.history_status_receiverd
    

    Но мне все равно нравится


    1. Bringoff
      17.08.2016 20:51

      А в чем профит, собственно? Который перевешивает нарушение code-style.


      1. andreich
        18.08.2016 07:15

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

        <string name="shopping_list.category.other">Другое</string>
        

        На мой взгляд выгляди лаконичней, в сравнении с таким вариантом
        <string name="shopping_list_category_other">Другое</string>
        


  1. akhbulatov
    16.08.2016 23:08

    Как вариант, можно использовать такой гайд по строкам. Сам пользуюсь им.


  1. vikarti
    17.08.2016 10:33
    +1

    с Plurals штатным есть проблемы на API ниже 11 (если оно еще актуально для вас) — читаем например http://www.dimasokol.ru/plurals-in-android/
    На одном сравнительно недавнем проекте сначала было требование поддерживать 2.3.1 — пришлось использовать оберточку https://github.com/populov/android-i18n-plurals.

    Подход с %1$s я например использую всегда. Даже зная что кроме русского и английского других языков в принципе не будет. И для моего open-source кода тоже.