- Android String Placeholders
- Quick reminder
- Formatting strings
- Error
- getString()
- Professional Translation
- Using placeholders
- Conclusion
- Android TextView: «Не конкатенировать текст, отображаемый с помощью setText»
- ОТВЕТЫ
- Ответ 1
- Ответ 2
- Ответ 3
- Ответ 4
- Ответ 5
- Ответ 6
- Ответ 7
- Android TextView: «Не объединяйте текст, отображаемый с setText»
- Android TextView: «не объединяйте текст, отображаемый с помощью setText»
- 6 ответов
- Styling dynamic strings directly in Android xml with HTML markup
- Digging into a better solution
- BONUS
Android String Placeholders
This article reviews different ways to create dynamic translatable strings in Android.
Quick reminder
In Android, message strings are extracted to XML files, and the system loads the resources corresponding to the current configuration.
Formatting strings
Let’s say we want to display a dynamic string, such as Player Foo — Score: 42.
We may be tempted to implement that quickly with String.format() .
You will get a compile time error message on the definition.
Error
Multiple substitutions specified in non-positional format; did you mean to add the formatted=»false» attribute?
This error message is misleading, because one may believe that using formatted=»false» is the way to go.
Although the error message now disappears, the real solution is to use a positional format.
When translating strings, the word order will change. For instance, Name: John Smith in English becomes Nom : Smith John in French.
Using positional format prevents translation mistakes.
getString()
Did you know that instead of String.format() , you can use an overloaded version of getString() that handles formatting?
Is that stricly equivalent to the previous code? Let’s look at the Android source!
Almost the same, except that we are using the resource configuration locale, whereas we were previously using the default locale.
Locale.getDefault() is usually equal to mConfiguration.locale , so this won’t really be a problem until you start messing with the default locale.
By the way, you probably know that getString() is also available on Context .
What’s the difference? None. It just delegates to Resources .
If someone knows the story behind this weird shortcut method, let me know. For now, I’ll just assume this is a consequence of Drunk Driven Development.
Professional Translation
Your users deserve better than Google translate. XML resource files should be translated by a professional translator.
This translator will know nothing about your app internals. Therefore, it may be really hard to find out what those %1$s cryptic signs mean.
You can use comments to help the translator.
By the way, if you need excellent quality software translation, I know someone that’s been translating software for more than 25 years. Yes, he is my father 🙂 .
Using placeholders
Another interesting approach is to use named placeholders instead of format specifiers.
I won’t discuss which syntax is better for this kind of problem, let’s just pick a simple one:
I find this much more readable! Now, you’ll need an API to transform that format to the final string.
Implementing this API is fairly straightforward.
This is just an example implementation, I’ll leave a better one to you as an exercice. An interesting point here is that with() returns this , so you can use it as a fluid API.
Conclusion
I shamelessly stole this
Of course, you may already use Java libraries that can do this. If you are aware of a good one that does a decent job, let me know!
Источник
Android TextView: «Не конкатенировать текст, отображаемый с помощью setText»
Я устанавливаю текст с помощью setText() следующим образом.
В этом первом простом использовании, а втором задается текст с форматированием текста.
Студия Android настолько интересна, что я использовал Меню Analyze -> Code Cleanup , и я получил предложение в двух строчках, например.
Не объединяйте текст, отображаемый с помощью setText. Использовать строку ресурса с заполнителями. меньше. (Ctrl + F1)
При вызове TextView # setText:
- Никогда не вызывайте Number # toString() для форматирования чисел; он не будет правильно обрабатывать разделители дроби и специфичные для локали цифры. Рассмотреть возможность используя формат String # с правильными спецификациями формата (% d или% f) вместо.
- Не передавайте строковый литерал (например, «Hello») для отображения текста. Закодированный текст не может быть должным образом переведен на другие языки. Попробуйте вместо этого использовать строки ресурсов Android.
- Не создавайте сообщения, объединяя текстовые блоки. Такие сообщения не могут быть должным образом переведены.
Что я могу сделать для этого? Кто-нибудь может помочь объяснить, что это за штука и что мне делать?
ОТВЕТЫ
Ответ 1
В ресурсе есть перегруженная версия getString, которая принимает varargs типа Object : getString (int, java.lang.Object. ), Если вы правильно настроили свою строку в файле strings.xml с правильными держателями мест, вы можете использовать эту версию для получения форматированной версии вашей последней строки. Например.
с помощью getString(R.string.welcome_message, «Test», 0);
android вернет строку с
О setText(«» + name);
Ваш первый пример prodNameView.setText(«» + name); не имеет для меня никакого смысла. TextView способен обрабатывать нулевые значения. Если имя равно null, текст не будет нарисован.
Ответ 2
Не путайте с % 1 $ s и % 2 $ d в принятом ответе. Вот несколько дополнительных сведений.
- Спецификаторы формата могут иметь следующий синтаксис:
- Необязательный arguments_index указывается как число, заканчивающееся символом «$» после «%», и выбирает указанный аргумент в списке аргументов. На первый аргумент ссылается «1 $», на второй — «2 $» и т.д.
- Обязательный спецификатор формата — это символ, указывающий, как должен форматироваться аргумент. Набор действительных преобразований для данного аргумента зависит от типа данных аргумента .
Пример
Мы создадим следующую отформатированную строку, где серые части будут вставлены программно.
Привет Test ! у вас есть 0 новые сообщения
Ваш string resource :
Hello, %1$s ! You have %2$d new messages
Сделайте string substitution как указано ниже:
getString(R.string.welcome_message, «Test» , 0 );
- % 1 $ s будет заменен строкой «Test»
- % 2 $ d будет заменено строкой «0»
Ответ 3
Я столкнулся с тем же сообщением об ошибке lint и решил его таким образом.
Первоначально мой код был:
Я получил следующую ошибку
Итак, я добавил это в strings.xml
Какой мой начальный «» + заполнитель для моего номера (количества).
Примечание: Моя переменная quantity была ранее определена и это то, что я хотел добавить в строку. Мой код в результате был
После этого моя ошибка ушла. Поведение в приложении не изменилось, и мое количество продолжало отображаться так, как я хотел, без ошибок.
Ответ 4
Не объединяйте текст внутри вашего метода setText(), объединяйте все, что вам нужно, в String и помещайте это значение String в свой метод setText().
пример: правильный путь
Не объединяйте внутри setText() как
Ответ 5
Вы должны проверить этот поток и использовать заполнитель, подобный его (не проверен)
Ответ 6
проблема заключается в том, что вы добавляете «» в начале каждой строки.
lint будет проверять аргументы, передаваемые на setText , и будет генерировать предупреждения, в вашем случае следующее предупреждение следующее:
Не создавать сообщения объединяя текстовые фрагменты. Такие сообщения не могут быть должным образом в переводе.
поскольку вы объединяете каждую строку с помощью «» .
удалите эту конкатенацию, поскольку аргументы, которые вы передаете, уже являются текстами. Кроме того, вы можете использовать .toString() , если вообще не требуется нигде вместо того, чтобы конкатенировать вашу строку с помощью «»
Ответ 7
Если вам не нужна поддержка i18n, отключите эту проверку в Android Studio
Файл → Настройки → Редактор → Проверки → Android → Lint → Интернационализация TextView (снимите этот флажок)
Источник
Android TextView: «Не объединяйте текст, отображаемый с setText»
Я устанавливаю текст с помощью setText () следующим образом.
В этом первом простое использование, а во втором — установка текста с форматированием текста.
Android Studio настолько интересна, что я использовал меню Analyze -> Code Cleanup и получил предложение в двух строках, например.
Не объединяйте текст, отображаемый с помощью setText. Используйте строку ресурса с заполнителями. меньше . (Ctrl + F1)
При вызове TextView # setText:
- Никогда не вызывайте Number # toString () для форматирования чисел; он не будет правильно обрабатывать разделители дробей и цифры, зависящие от языка. Вместо этого рассмотрите возможность использования формата String # с соответствующими спецификациями формата (% d или% f).
- Не передавайте строковый литерал (например, «Hello») для отображения текста. Жестко закодированный текст нельзя правильно перевести на другие языки. Вместо этого рассмотрите возможность использования строк ресурсов Android.
- Не создавайте сообщения, объединяя фрагменты текста. Такие сообщения нельзя правильно перевести.
Что я могу для этого сделать? Кто-нибудь может помочь объяснить, что это за штука и что мне делать?
Источник
Android TextView: «не объединяйте текст, отображаемый с помощью setText»
Я устанавливаю текст с помощью setText () следующим образом.
в этой первый один простой в использовании и второй — это создание текста с форматированием текста.
Android Studio настолько интересна, что я использовал меню Analyze -> Code Cleanup и у меня есть предложение выше двух строк.
не объединяйте текст, отображаемый с помощью setText. Использовать ресурсы строка с заполнителями. меньше. (Ctrl+F1)
при вызове TextView#setText:
- никогда не вызывайте номер#toString () для форматирования номеров; он не будет обрабатывать разделители фракций и цифры, специфичные для локали. Считать использование формата String#с соответствующими спецификациями формата (%d или %f) вместо.
- не передавайте строковый литерал (например, «Hello») для отображения текста. Жестко текст не может быть правильно переведено на другой языки. Вместо этого рассмотрите возможность использования строк ресурсов Android.
- не создавайте сообщения путем объединения фрагментов текста. Такие сообщения не могут быть правильно переведены.
что я могу сделать для этого? Любой может помочь объяснить, что это такое и что мне делать?
6 ответов
ресурс имеет перегруженную версию getString, которая принимает varargs типа Object : метода getString(int и Ява.ленг.Объект. ). Если вы правильно настроили строку в строках.xml, с правильными держателями мест, вы можете использовать эту версию для получения отформатированной версии конечной строки. Е. Г.
используя getString(R.string.welcome_message, «Test», 0);
android вернет строку с
о setText(«» + name);
ваш первый пример, prodNameView.setText(«» + name); не имеет никакого смысла для меня. TextView способен обрабатывать значения null. Если name равно null, текст не будет отображаться.
Не путайте с %1$s и %2$d в принятом ответе.Вот несколько дополнительных сведений.
- спецификаторы формата могут иметь следующий синтаксис:
- необязательный элемент argument_index указывается как число, заканчивающееся на » $ «после» % » и выбирает указанный аргумент в списке аргументов. Первый аргумент ссылается на «1$», второй —«2$», etc.
- необходимые формата — символ, указывающий, как должен быть отформатирован аргумент. Набор допустимых преобразований для данного аргумента зависит от аргумента тип данных.
пример
мы создадим следующую форматированную строку, куда вставляются серые части программно.
Привет Test ! у вас есть 0 новые сообщения
код string resource :
Здравствуйте, %1$s ! У вас есть %2$d новый сообщения
сделать string substitution , как указано ниже:
метода getString(Р. строкой.welcome_message, «Test» , 0 );
- %1$S, там будет подстановка по строке «Test»
- %2$d будет заменено строкой «0»
я столкнулся с тем же сообщением об ошибке lint и решил его таким образом.
изначально мой код:
я получил следующую ошибку
Итак, я добавил Это к strings.xml
который является моим начальным «» + заполнителем для моего номера (количества).
Примечание: мой quantity переменная была определена ранее и является тем, что я хотел добавить в строку. Мой код в результате был
после этого, моя ошибка ушла. Поведение в приложении не изменилось, и мое количество продолжало отображаться, как я хотел, чтобы теперь без ошибки корпии.
вы должны проверить это нить и использовать заполнитель, как его один (не проверено)
Источник
Styling dynamic strings directly in Android xml with HTML markup
See the original article for free with syntax highlighting and code formatting on my personal blog: https://sergiosastre.hashnode.dev .
In Android, Strings are one of the most common Objects when working with views that show plain text. While implementing user interfaces, it happens often that the text requires some styling. For styled Strings, we are required to use CharSequences instead. Android supports some html tags out of the box, and those can be defined in the xml string resource, for instance
and resolved into a CharSequence by calling context.getText(stringRes: Int) which takes care of all the supported HTML tags to style the text without us needing to do anything else.
However, sometimes we need to build a part of the string dynamically. In order to do this, we need to mark the dynamic parts in the xml with placeholders in the form of %
Nevertheless, things start getting complicated if we define HTML tags together with dynamic placeholders in xml string resources, for instance something like this.
If we take a look at the method signature of String.format(text: String, vararg args: String) , its first argument requires a String instead of a CharSequence . This means, the dynamic text placeholders will be correctly replaced, but our CharSequence has to be converted to String , throwing away its styling.
In order to deal with HTML markup, Android provides HtmlCompat. It requires that the string resource encodes its opening unsafe characters, namely: ‘ , which becomes ‘
or alternatively, we can wrap the resource inside CDATASections instead to the xml as follows:
In any case, given our dynamic placeholder text to be “placeholder1”, we can get the expected result by using HtmlCompat as follows:
Although the code above seems to work robustly, the result differs if the dynamic placeholder text contains at least one unescaped HTML character, for instance: , > , & , \ or » , like in
, leading to the result below
Yes, the placeholder just disappears. That’s because characters must be escaped before calling HtmlCompat.fromHtml() . We solve that by encoding the placeholders before using HtmlCompat, like this
Although it works and it is the recommended way according to the official documentation, I personally do not like any of the approaches before. Why?
- You end up changing the xml string resource completely for the sake of using a dynamic text placeholder
- You lose xml highlighting in the styled parts of the string resource and therefore, it is harder to read
A better approach would be to create a method that can handle the original xml string resource with HTML tags and placeholders. In doing so, it does not matter whether the string resource contains HTML markup or not, the method simply handles the placeholders while keeping the style defined by the (existing, if any) HTML tags … no need to either replace opening unsafe characters or add CDATASections.
And yes, it is possible with a bit of hackery. Let’s see how.
Digging into a better solution
We already know that using context.getText(R.string.lorem_ipsum) returns the string resource styled as a CharSequence . If the string resource has a placeholder, it will be shown the same as in the xml.
We also know that HtmlCompat.fromHtml() processes «some» HTML tags. Its inverse method exists and does exactly the opposite: takes a Spanned object and converts it to a string with the corresponding HTML tags. The flag we pass to the method also matters: HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL also adds a new line at the end of the HTML string and we have to account for that. Therefore, we can get the desired HTML string as follows
which results into
We’ve got the equivalent HTML string to the styled String of the first step so far. However, the final goal is to replace its placeholders with the corresponding values. As you might remember, I mentioned at the beginning of the article that we can use String.format(text: String, vararg args: String) for that. It would not work with a CharSequence , but that is why we converted it into its equivalent HTML string in the first place.
Just convert the HTML text into a CharSequence and we get the desired style. Remember to use HtmlCompat.FROM_HTML_MODE_COMPACT , since it is the inverse of the HtmlCompat.TO_HTML_PARAGRAPH_LINES_INDIVIDUAL we’ve previously used
Well we are almost done… as we have seen at the beginning of this article, if the placeholders are Strings containing unsafe characters, they do not show up. Therefore, do not forget that we need to encode the string values that will substitute the placeholders. A Kotlin extension function following all the aforementioned steps would look like this
BONUS
The same idea applies to plural resources. Simply replace
Did you like this post? You might also like to take a look at other articles I’ve written:
Источник