Строковый ресурс предоставляет текстовые строки для вашего приложения с дополнительным стилем и форматированием текста. Существует три типа ресурсов, которые могут предоставлять вашему приложению строки:
- String
- XML-ресурс, который предоставляет одну строку.
- Массив строк
- Ресурс XML, который предоставляет массив строк.
- Строки с количеством (множественное число)
- XML-ресурс, содержащий разные строки для множественного числа.
Все строки могут содержать разметку стилей и аргументы форматирования. Подробнее о форматировании и стилизации строк…
Строка
Одна строка, на которую можно ссылаться из кода приложения (например, из composable-функции) или из других файлов ресурсов.
- местоположение файла;
res/values/filename.xml
Название файла может быть любым. В качестве идентификатора ресурса используется атрибутnameэлемента<string>.- скомпилированный тип данных ресурса:
- Указатель ресурса на
String. - ссылка на ресурс:
-
В Kotlin:
R.string.string_name
В XML:@string/string_name - Синтаксис:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- elements:
- пример:
- XML-файл сохранен в
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
Этот код приложения извлекает строку из composable-функции с помощью
stringResource():@Composable fun Greeting() { Text(text = stringResource(R.string.hello)) }
Примечание. Чтобы получить строку за пределами composable-функции, используйте
Вы также можете ссылаться на строковые ресурсы из других XML-файлов, напримерcontext.getString(R.string.hello).AndroidManifest.xml:<activity android:name=".MainActivity" android:label="@string/hello" />
Массив строк
Массив строк, на которые можно ссылаться из приложения.
- местоположение файла;
res/values/filename.xml
Название файла может быть любым. В качестве идентификатора ресурса используется атрибутnameэлемента<string-array>.- скомпилированный тип данных ресурса:
- Указатель ресурса на массив объектов
String. - ссылка на ресурс:
-
В Kotlin:
R.array.string_array_name
В XML:@[package:]array/string_array_name - Синтаксис:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- elements:
- пример:
- XML-файл сохранен в
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="planets_array"> <item>Mercury</item> <item>Venus</item> <item>Earth</item> <item>Mars</item> </string-array> </resources>
Этот код приложения извлекает массив строк из composable-функции с помощью
stringArrayResource():@Composable fun PlanetList() { val planets: Array
= stringArrayResource(R.array.planets_array) // Render the array, e.g. inside a LazyColumn. } Примечание. Чтобы получить массив строк за пределами composable-функции, используйте
context.resources.getStringArray(R.array.planets_array).
Строки с количеством (множественное число)
В разных языках действуют разные правила грамматического согласования с количеством. Например, в английском языке количество 1 – это особый случай. Мы пишем "1 книга", но для любого другого количества мы пишем "n книг". Различие между единственным и множественным числом очень распространено, но в некоторых языках есть и другие формы. Полный набор поддерживаемых Android типов: zero, one, two, few, many и other.
Правила выбора формы для определенного языка и количества могут быть очень сложными, поэтому в Android предусмотрены методы, такие как pluralStringResource(), которые позволяют выбрать подходящий ресурс.
Хотя исторически они называются "строками количества" (и до сих пор так называются в API), их следует использовать только для множественного числа. Например, не следует использовать строки количества для реализации чего-то вроде "Входящие" и "Входящие (12)" в Gmail, когда есть непрочитанные сообщения. Использование строк количества вместо оператора if может показаться удобным, но важно помнить, что в некоторых языках (например, в китайском) нет таких грамматических различий, поэтому вы всегда будете получать строку other.
Выбор строки зависит исключительно от грамматической необходимости. В английском языке строка для zero игнорируется, даже если количество равно 0, поскольку 0 грамматически не отличается от 2 или любого другого числа, кроме 1 ("zero books", "one book", "two books" и т. д.). А в корейском языке, наоборот, используется только строка other.
Не стоит думать, что, например, two относится только к числу 2. В некоторых языках 2, 12, 102 и т. д. могут относиться к одной категории, а другие числа – к другой. Положитесь на переводчика, который знает, какие различия действительно важны в его языке.
Если в сообщении нет числа, то, скорее всего, оно не подходит для множественного числа. Например, в литовском языке единственное число используется и для 1, и для 101, поэтому "1 книга" переводится как "1 knyga", а "101 книга" – как "101 knyga". "Книга" – knyga, а "много книг" – daug knygų. Если сообщение на английском языке содержит "a book" (книга) и "many books" (много книг) без указания количества, его можно перевести как "knyga" (книга)/"daug knygų" (много книг). Однако по правилам литовского языка, если количество равно 101, будет показано "knyga" (книга).
Часто можно избежать использования строк количества, используя нейтральные формулировки, такие как "Книги: 1". Это упростит жизнь вам и вашим переводчикам, если такой стиль подходит для вашего приложения.
В API 24 и более поздних версиях можно использовать более мощный класс ICU MessageFormat.
- местоположение файла;
res/values/filename.xml
Название файла может быть любым. В качестве идентификатора ресурса используется атрибутnameэлемента<plurals>.- ссылка на ресурс:
-
Kotlin:
R.plurals.plural_name - Синтаксис:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="plural_name"> <item quantity=["zero" | "one" | "two" | "few" | "many" | "other"] >text_string</item> </plurals> </resources>
- elements:
- пример:
XML-файл сохранен в
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <!-- As a developer, you should always supply "one" and "other" strings. Your translators will know which strings are actually needed for their language. Always include %d in "one" because translators will need to use %d for languages where "one" doesn't mean 1 (as explained above). --> <item quantity="one">%d song found.</item> <item quantity="other">%d songs found.</item> </plurals> </resources>
XML-файл сохранен в
res/values-pl/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <plurals name="numberOfSongsAvailable"> <item quantity="one">Znaleziono %d piosenkę.</item> <item quantity="few">Znaleziono %d piosenki.</item> <item quantity="other">Znaleziono %d piosenek.</item> </plurals> </resources>
Этот код приложения извлекает строку во множественном числе из composable-функции с помощью
pluralStringResource():@Composable fun SongCount(count: Int) { Text( text = pluralStringResource( R.plurals.numberOfSongsAvailable, count, count, ) ) }
При использовании функции
pluralStringResource()вам нужно передатьcountдважды, если ваша строка включает форматирование строки с числом. Например, для строки%d songs foundпервый параметрcountвыбирает подходящую строку во множественном числе, а второй параметрcountвставляется в плейсхолдер%d. Если строки во множественном числе не содержат форматирования, передавать третий параметр вpluralStringResourceне нужно.Примечание. Чтобы получить строку во множественном числе за пределами composable-функции, используйте
context.resources.getQuantityString(R.plurals.numberOfSongsAvailable, count, count).
Формат и стиль
Ниже приведены важные сведения о том, как правильно форматировать и оформлять строковые ресурсы.
Как обрабатывать специальные символы
Если строка содержит символы, которые имеют специальное назначение в XML, их необходимо экранировать в соответствии со стандартными правилами экранирования XML/HTML. Если вам нужно экранировать символ, имеющий особое значение в Android, используйте перед ним обратную косую черту.
По умолчанию Android объединяет последовательности пробельных символов в один пробел. Чтобы избежать этого, заключите нужную часть строки в двойные кавычки. В этом случае все пробелы (включая символы новой строки) будут сохранены в области, заключенной в кавычки. Двойные кавычки позволят вам использовать обычные одинарные неэкранированные кавычки.
| Персонаж | Формы с экранированием |
|---|---|
| @ | \@ |
| ? | \? |
| Новая строка | \n |
| Tab | \t |
| Символ Unicode U+XXXX | \uXXXX |
Одинарная кавычка (') |
Любой из следующих вариантов:
|
Двойная кавычка (") |
\"
Обратите внимание, что одинарные кавычки не поддерживаются. |
Удаление пробелов и экранирование символов Android происходят после того, как файл ресурсов будет обработан как XML. Это означает, что <string>      </string> (пробел, пробел после знака препинания, круглая шпация Unicode) сворачиваются в один пробел (" "), поскольку все они являются пробелами Unicode после синтаксического анализа файла как XML.
Чтобы сохранить пробелы, заключите их в кавычки (<string>"      "</string>) или используйте экранирование Android (<string> \u0032 \u8200 \u8195</string>).
Строки форматирования
Если вам нужно отформатировать строки, вы можете сделать это, поместив аргументы формата в строковый ресурс, как показано в следующем примере.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
Этот код приложения форматирует строку из composable-функции, передавая аргументы напрямую в stringResource():
@Composable fun WelcomeMessage(username: String, mailCount: Int) { Text( text = stringResource( R.string.welcome_messages, username, mailCount, ) ) }
Оформление с помощью HTML-разметки
Вы можете добавить в строки разметку HTML. Пример:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
Поддерживаются следующие элементы HTML:
- Полужирный:
<b> - Курсив:
<i>,<cite>,<dfn>,<em> - Текст на 25% больше:
<big> - Текст на 20% меньше:
<small> - Настройка свойств шрифта:
<font face="font_family" color="hex_color">. Примеры семейств шрифтов:monospace,serifиsans_serif. - Установка моноширинного шрифта:
<tt> - Зачеркнутый:
<s>,<strike>,<del> - Подчеркнутый:
<u> - Надстрочный текст:
<sup> - Подстрочный текст:
<sub> - Маркированный список:
<ul>,<li> - Разрывы строк:
<br> - Подразделение:
<div> - Стиль CSS:
<span style="color|background_color|text-decoration"> - Абзацы:
<p dir="rtl | ltr" style="…">
В некоторых случаях может потребоваться создать ресурс стилизованного текста, который также используется в качестве строки формата. Обычно это не работает, потому что методы форматирования, такие как stringResource(), удаляют всю информацию о стиле из строки.
Чтобы обойти это ограничение, можно использовать в тегах HTML экранированные символы, которые затем восстанавливаются с помощью AnnotatedString.fromHtml() после форматирования. Пример:
- Сохраните ресурс форматированного текста в виде экранированной HTML-строки:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
В эту строку добавляется элемент
<b>. Обратите внимание, что открывающая скобка экранирована с помощью обозначения<. - Затем отформатируйте строку как обычно, но также вызовите
AnnotatedString.fromHtml(), чтобы преобразовать текст HTML в стилизованную строку Compose.
Поскольку fromHtml() форматирует все объекты HTML, обязательно экранируйте все возможные символы HTML в строках, которые вы используете с форматированным текстом, с помощью TextUtils.htmlEncode().
import android.text.TextUtils import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.AnnotatedString import androidx.compose.ui.text.fromHtml @Composable fun WelcomeHtmlMessage(username: String, mailCount: Int) { // Escape the username in case it contains characters like "<" or "&" val escapedUsername = TextUtils.htmlEncode(username) val text = stringResource( R.string.welcome_messages, escapedUsername, mailCount, ) Text( text = AnnotatedString.fromHtml(text) ) }
Стилизация с помощью AnnotatedString
AnnotatedString – это текстовый объект Compose, стиль которого можно настраивать с помощью таких свойств, как цвет и насыщенность шрифта. Создавайте стилизованный текст программно с помощью buildAnnotatedString и withStyle.
Этот код приложения создает один текстовый элемент со смешанными стилями:
@Composable fun StyledGreeting() { val styled = buildAnnotatedString { append("Welcome to ") withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append("Android") } append("!") } Text(text = styled) }
Чтобы применить цвет, размер шрифта и оформление текста, используйте SpanStyle. Чтобы применить стиль на уровне абзаца (например, выравнивание или высоту строки), используйте ParagraphStyle:
@Composable fun RichText() { val text = buildAnnotatedString { withStyle(ParagraphStyle(lineHeight = 24.sp, textAlign = TextAlign.Center)) { withStyle(SpanStyle(color = Color.Gray)) { append("Hello, ") } withStyle( SpanStyle( fontWeight = FontWeight.Bold, color = Color.Red, ) ) { append("world") } append("!") } } Text(text = text) }
Создание AnnotatedString напрямую – рекомендуемый подход для одноязычных приложений или статического текста в Compose. Однако для форматированного текста, требующего локализации, используйте подход XML <annotation>, описанный в следующем разделе.
Как оформлять переведенные строки с помощью аннотаций
Для строк, которым требуется собственный стиль и перевод, определите тег <annotation> в файле strings.xml для каждого региона. Переводчики сохраняют аннотацию независимо от того, где она находится в предложении. Прочитайте строку с помощью context.resources.getText(), пройдитесь по ее диапазонам Annotation и преобразуйте результат в AnnotatedString:
@Composable fun AnnotatedTitle() { val context = LocalContext.current val source = context.resources.getText(R.string.title) as SpannedString val text = buildAnnotatedString { append(source.toString()) source.getSpans(0, source.length, Annotation::class.java) .forEach { annotation -> if (annotation.key == "font" && annotation.value == "title_emphasis") { addStyle( SpanStyle( fontFamily = FontFamily( Font(R.font.permanent_marker) ) ), source.getSpanStart(annotation), source.getSpanEnd(annotation), ) } } } Text(text = text) }
Тег <annotation> в XML-файле не изменен. Различаются только коды получения. Переводчики по-прежнему перемещают тег, чтобы выделить нужное слово на каждом языке.
Дополнительные ресурсы
Дополнительную информацию о строковых ресурсах можно найти в следующих источниках: