Доброго времени суток! Представляю вашему вниманию вольный перевод статьи от GDE (Google developer expert) Dmytro Danylyk. Собственно, вот оригинал. Статья описывает правильные подходы для работы со strings.xml и особенно полезно это будет разработчикам, которые разрабатывают мультиязыковые приложения. Прошу под кат.
Эта статья о такой тривиальной вещи android как string.xml.
Не используйте повторно
Не используйте повторно строки для разных экранов
Давайте представим, что у вас есть loading dialog на Sign In либо Sign Up экране. Так как оба экрана имеют loading dialog, вы решаете использовать те же строки — R.string.loading.
res/values/strings.xml.
Позже, если вы решите использовать различные, вам нужно будет создать 2 разные строки и модифицировать их, непосредственно, в .java классах. Если вы используете разные строки с начала — вам бы пришлось модифицировать лишь strings.xml файл.
res/values/strings.xml
Вы никогда не будете заранее знать поддержку и перевод какого языка вам предстоит добавить. Всё дело в контексте: в одном языке вы можете использовать тоже слово в одном контексте, но в другом — это слово по смыслу не будет подходить.
res/values/strings.xml
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.
Разделяйте
Разделяйте строки, которые относятся к одному экрану с помощью префиксов и комментариев
res/values/strings.xml
- Добавляйте префикс в виде имени экрана к каждой строке для более простого понимания к какому экрану относится данный ресурс.
- Чистый string.xml файл поможет достаточно легко поддерживать и переводить различные языки — экран за экраном.
Создание различных strings.xml для каждого экрана
Если вы хотите, вы можете создать string.xml файл для каждого экрана — settings-strings.xml, profile-strings.xml. Но обычно приложение имеет около 10-20 экранов, соответственно, нужно иметь 10-20 string.xml файлов в каждой языковой папке. Я думаю, что это будет сопряжено с беспорядком.
Форматирование
Используйте Resources#getString(int id, Object… formatArgs) для форматирования строк
Никогда не делайте конкатенацию через + оператор, поскольку в других языках порядок слов может варьироваться.
res/values/strings.xml
java code
Правильный путь — использовать Resources#getString(int id, Object… formatArgs).
res/values/strings.xml
res/values-UA/strings.xml
java code
Множественное число
Используйте Resources#getQuantityString(int id, int quantity) для количественных строк
Не решайте проблемы с множественным числом в java коде, поскольку разные языки имеют разные правила для согласования множественного числа
res/values/strings.xml
java code
Правильный путь это использовать Resources#getQuantityString(int id, int quantity)
res/values/strings.xml
java code
Подстветка слов
Используйте html text для подсветки статический слов
Если вы хотите изменить цвет некоторых слов в TextView — ForegroundColorSpan не всегда лучший вариант, потому как подсветка выполняется через индекс и это не безопасно в мультиязыковом приложении. Лучше использовать html font color tags внутри вашего strings.xml файла.
Представим у вас есть текст “Discover and play games.” и вы хотите выделить “Discover” слово и “play” слово синим цветом.
res/values/strings.xml
java code
Комментарии (32)
Revertis
15.08.2016 20:57Множественное написание string.xml (в единственном числе) это много ошибок, или так и задумано?
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
Но мне все равно нравитсяBringoff
17.08.2016 20:51А в чем профит, собственно? Который перевешивает нарушение code-style.
andreich
18.08.2016 07:15я рассматриваю разделение точкой только для смысловых блоков, тогда как в блоке нижним подчеркиванием разделяю слова, относящиеся к блоку.
например так
<string name="shopping_list.category.other">Другое</string>
На мой взгляд выгляди лаконичней, в сравнении с таким вариантом
<string name="shopping_list_category_other">Другое</string>
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 кода тоже.
withoutuniverse
Код картинками — что-то новенькое :)
Ниже замечания по делу:
1. Для строковых ресурсов так, как вы написали, не напишешь.
Вот правильный пример:
2. Plurals не всегда корректно работают с локалями.
3. Для облегчения перевода одинаковые строки можно объединить в одну, а остальные ссылать на нее:
4. Чтобы проще было разделять ресурсы по блокам, не обязательно использовать конструкцию, как у вас
lazexe
Тот момент когда комментарий к статье на уровне полезной статьи :)
withoutuniverse
Статья полезная, а из моего комментария реально полезен пожалуй только 3 пункт.
Но спасибо :)
Bringoff
withoutuniverse
По 1 замечанию, еще с год назад у меня так не выходило написать, странно. Сейчас попробовал и всё сработало как часы, спасибо.
По 2 пункту — о каких регионах речь?
withoutuniverse
Сейчас это работает только для 1 параметра.
Наверное потому мы везде использовали %1$, даже при наличии лишь 1 параметра — выглядит целостнее.При наличии 2 и более будет выдана ошибка:
Bringoff
region description
...
endregion
Ctrl+Alt+T нажмите.
iamtodor
// Also works
fRoStBiT
По поводу пункта №3:
соблюдается.Мне кажется, что дублирвать значения в XML смысла никакого нет. Главное, чтобы Java-код ссылался на разные строки.
Принцип
aelimill
4. когда строковых переменных очень много в одном файле даже поблочная разбивка и комментарии не помогают, мы сначала делили на разные файлы, а сейчас так и вообще для крупных блоков-экранов используем свои res-папки.
Azzdorf
1) в десятках проектов нигде не встречал %1$s, везде было через %s, что самое интересное, так в документации показываются оба варианта, но во всех «официальных» sample я видел только %s, так что считать какой-то из вариантов неправильным, а единственный истинным — это абсолютизм на уровне ситхов
2) активно пользую в проектах, в т.ч. с right-to-left локалями, пока ни разу не корректностей не встречал, буду ОЧЕНЬ благодарен за конкретные локали или проблемные варианты использования
3) поддержу автора — ссылки на строки внутри хорошо, если мало локалей, но как только переваливает через 10 языков и в команде от 5 человек, которые паралельно работают с строковыми ресурсами, то это превращается в постоянный рефакторинг строковых ресурсов, проще сразу разделять сразу разделять
4) // — недопустимо для xml, и пока мало локалей то всё ок, но если приходится, ДАЖЕ ИНОГДА, прибегать к сторонним утилитам для сверки и консолидации переводов — это будет первое место для ругани
withoutuniverse
В десятках своих проектов? В десятках опенсорсных? В десятках фрилансовых на сапорте?
Не пытаюсь что-то доказать, но я встречал лишь несколько реально крупных проектов, написанных не мной. Примером может послужить Telegram. По ссылке вот тут xml для русской локализации — ССЫЛКА и там нету Plurals и %s. Наверное о чем-то это говорит у проекта с многомилионной аудиторией. Или вы думаете, что они просто не умеют?
По поводу ссылок на свои же ресурсы — это же даже не рекомендация, я написал что можно так делать. Как плюс — можно добиться существенной экономии на переводе.
По // тоже самое, так можно, но я же не настаиваю :)
Azzdorf
т.е.
2. Plurals не всегда корректно работают с локалями.
это просто предположение? спрашиваю серьезно, так как активно ими пользуюсь при разработки или не трогаю их при рефакторинге
сорри если показалось сильной критикой с моей стороны, просто я прывик что 90% стоимости кода — это его поддержка и в данном случаи Ваши варианты (3 и 4) ведут к усложнению саппорта
withoutuniverse
К сожалению, дело давнее, потому и личных пруфов по Plurals не предоставлю, но это не предположение точно. Помню лишь, что проблемы были именно с локализацией. Гугл нашел как минимум одну проблему с ними, когда quantity равна нулю ССЫЛКА.
У нас на проектах используется
MessageFormat
.Azzdorf
Спасибо, полезно для развития
все кто жалуется на логику жалуются, по сути, на стандарт (unicode), с самими plurals проблем нет
также многие путают порядковые и количественные, что также вызывает необоснованный негатив
Azzdorf
пробежался по stackoverflow
не одной заявления о некорректной работе strings plurals
как правило strings plurals — везде отмечен как правильный ответ на вопрос об локализации множественных
по указаной Вами ссылке не нашел ни одного места, где бы plurals вообще можно бы было использовать (просто небыло потребностей)
withoutuniverse
Выше я ответил — плохо пробежался значит.
Вот комментарий по проблемам с Plurals от vikarti, помимо моей ссылки на SO — #comment
Azzdorf
там пролема не с plurals а с восприятием людьми стандарта unicode на котором он основан
Bringoff
Не стоит для аргументации использовать telegram. Он (там один разработчик клиента) переписал половину андроид, даже саппорты гугловые не использует, я не удивлен, что и в строках он что-то не применяет.
withoutuniverse
Вы избирательно читаете комментарии. Уже обсудили, что %s работает только при наличии 1 параметра. При наличии 2 и более — обязательно нумеровать их. Стиль и код выглядит целостнее, когда всё одинаково. Про plurals тоже обсудили уже, они могут навредить при работе с локализациями, при этом только на старых версиях андроида вроде как. Да и
MessageFormat
более гибок, чем телеграм и пользуется.Почему не стоит его использовать при аргументации? Если проект имеет многомиллионную аудиторию и что-то не использует — стоит задуматься «почему?». Я исследовал их исходники, код не идеален с точки зрения читабельности, но фрагменты не используются в угоду скорости и плавности анимаций, коих с фрагментами объективно не добиться. Класс
BaseFragment
есть, просто он неextends Fragment
.Странно, что автор не участвует в дискуссии, мне его статься витися интересной.
Bringoff
Я отвечаю на те комментарии, на которые считаю необходимым.
Не пойму аргументации о единстве стиля. А чем "везде, где один аргумент, писать %s" не стиль? Если изменится количество аргументов, все равно код и строку менять придется.
Количество пользователей вообще никак не коррелирует с качеством кода и используемых подходов. Что телеграмм на практике доказывает. Он занимается велосипедостроением, оправдывая это стремлением к стабильности. Если ресурсы телеграмма позволяют писать собственную реализацию sqlite, им везёт, большинство проектов к такому не готовы. Да и смысла нет.