Zasób tekstowy zawiera ciągi tekstowe dla aplikacji z opcjonalnym stylem i formatowaniem tekstu. Istnieją 3 rodzaje zasobów, które mogą dostarczać aplikacji ciągi znaków:
- String
- Zasób XML, który zawiera pojedynczy ciąg znaków.
- Tablica ciągów znaków
- Zasób XML, który zawiera tablicę ciągów znaków.
- Ciągi znaków ilości (liczba mnoga)
- Plik zasobu XML zawierający różne ciągi znaków do tworzenia form liczby mnogiej.
Wszystkie ciągi tekstowe mogą stosować pewne znaczniki stylów i argumenty formatowania. Informacje o stylizowaniu i formatowaniu ciągów znaków znajdziesz w sekcji Formatowanie i stylizowanie.
Ciąg znaków
Pojedynczy ciąg znaków, do którego można się odwoływać w kodzie aplikacji (np. w funkcji typu „composable”) lub w innych plikach zasobów.
- lokalizacja pliku:
res/values/filename.xml
Nazwa pliku jest dowolna. Element<string>z atrybutemnamejest używany jako identyfikator zasobu.- skompilowany typ danych zasobu:
- Wskaźnik zasobu do
String. - odwołanie do zasobu:
-
W języku Kotlin:
R.string.string_name
W języku XML:@string/string_name - składnia:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- elements:
- przykład:
- Plik XML zapisany w lokalizacji
res/values/strings.xml:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>
Ten kod aplikacji pobiera ciąg znaków z funkcji kompozycyjnej za pomocą
stringResource():@Composable fun Greeting() { Text(text = stringResource(R.string.hello)) }
Uwaga: aby pobrać ciąg znaków poza funkcją typu „composable”, użyj funkcji
Możesz też odwoływać się do zasobów ciągów znaków z innych plików XML, np. z plikucontext.getString(R.string.hello).AndroidManifest.xml:<activity android:name=".MainActivity" android:label="@string/hello" />
Tablica tekstowa
Tablica ciągów tekstowych, do których można się odwoływać z aplikacji.
- lokalizacja pliku:
res/values/filename.xml
Nazwa pliku jest dowolna. Element<string-array>z atrybutemnamejest używany jako identyfikator zasobu.- skompilowany typ danych zasobu:
- Wskaźnik zasobu do tablicy elementów
String. - odwołanie do zasobu:
-
W języku Kotlin:
R.array.string_array_name
W języku XML:@[package:]array/string_array_name - składnia:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="string_array_name"> <item >text_string</item> </string-array> </resources>
- elements:
- przykład:
- Plik XML zapisany w lokalizacji
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>
Ten kod aplikacji pobiera tablicę tekstową z funkcji kompozycyjnej za pomocą funkcji
stringArrayResource():@Composable fun PlanetList() { val planets: Array
= stringArrayResource(R.array.planets_array) // Render the array, e.g. inside a LazyColumn. } Uwaga: aby pobrać tablicę tekstową poza funkcją typu „composable”, użyj funkcji
context.resources.getStringArray(R.array.planets_array).
Ciągi ilościowe (liczba mnoga)
W różnych językach obowiązują różne zasady dotyczące zgodności gramatycznej z liczbą. Na przykład w języku angielskim liczba 1 jest przypadkiem szczególnym. Piszesz „1 książka”, ale w przypadku innych ilości piszesz „n książek”. To rozróżnienie między liczbą pojedynczą a mnogą jest bardzo powszechne, ale w innych językach występuje więcej rozróżnień. Pełny zestaw obsługiwany przez Androida to zero, one, two, few, many i other.
Reguły decydujące o tym, którego przypadku użyć w danym języku i dla danej ilości, mogą być bardzo złożone, dlatego Android udostępnia metody takie jak pluralStringResource(), które pozwalają wybrać odpowiedni zasób.
Chociaż historycznie ciągi ilościowe były nazywane „ciągami ilości” (i tak są nadal nazywane w interfejsie API), powinny być używane tylko w przypadku liczby mnogiej. Nie należy używać ciągów ilościowych do implementowania takich funkcji jak „Skrzynka odbiorcza” w Gmailu i „Skrzynka odbiorcza (12)” w przypadku nieprzeczytanych wiadomości. Używanie ciągów ilościowych zamiast instrukcji if może się wydawać wygodne, ale warto pamiętać, że w niektórych językach (np. w chińskim) takie rozróżnienia gramatyczne nie występują, więc zawsze otrzymasz ciąg other.
Wybór ciągu znaków zależy wyłącznie od konieczności gramatycznej. W języku angielskim ciąg znaków dla zero jest ignorowany, nawet jeśli ilość jest mniejsza niż 0, ponieważ 0 nie różni się gramatycznie od 2 ani od żadnej innej liczby z wyjątkiem 1 („zero books”, „one book”, „two books” itd.). Z kolei w przypadku języka koreańskiego wyłącznie używany jest ciąg znaków other.
Nie daj się też zwieść temu, że np. two brzmi tak, jakby odnosiło się tylko do liczby 2: w danym języku może być wymagane, aby liczby 2, 12, 102 (i tak dalej) były traktowane w ten sam sposób, ale inaczej niż inne liczby. Zaufaj tłumaczowi, który wie, jakie rozróżnienia są ważne w jego języku.
Jeśli wiadomość nie zawiera liczby, prawdopodobnie nie jest dobrym kandydatem do liczby mnogiej. Na przykład w języku litewskim forma liczby pojedynczej jest używana zarówno w przypadku liczby 1, jak i 101, więc „1 książka” jest tłumaczona jako „1 knyga”, a „101 książek” jako „101 knyga”. „a book” to „knyga”, a „many books” to „daug knygų”. Jeśli komunikat w języku angielskim w liczbie mnogiej zawiera „a book” (liczba pojedyncza) i „many books” (liczba mnoga) bez podania konkretnej liczby, można go przetłumaczyć jako „knyga” (książka) lub „daug knygų” (wiele książek), ale zgodnie z zasadami języka litewskiego w przypadku liczby 101 wyświetli się „knyga” (jedna książka).
Często można uniknąć ciągów znaków ilościowych, używając sformułowań neutralnych pod względem ilości, np. „Książki: 1”. Ułatwi to pracę Tobie i tłumaczom, jeśli jest to akceptowalny styl w przypadku Twojej aplikacji.
W przypadku interfejsu API w wersji 24 lub nowszej możesz zamiast tego użyć znacznie bardziej zaawansowanej klasy ICU MessageFormat.
- lokalizacja pliku:
res/values/filename.xml
Nazwa pliku jest dowolna. Element<plurals>z atrybutemnamejest używany jako identyfikator zasobu.- odwołanie do zasobu:
-
W Kotlinie:
R.plurals.plural_name - składnia:
-
<?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:
- przykład:
Plik XML zapisany w lokalizacji
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>
Plik XML zapisany w lokalizacji
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>
Ten kod aplikacji pobiera ciąg znaków w liczbie mnogiej z funkcji kompozycyjnej za pomocą funkcji
pluralStringResource():@Composable fun SongCount(count: Int) { Text( text = pluralStringResource( R.plurals.numberOfSongsAvailable, count, count, ) ) }
Jeśli używasz funkcji
pluralStringResource(), musisz przekazać wartośćcount2 razy, jeśli ciąg znaków zawiera formatowanie ciągu znaków z liczbą. Na przykład w przypadku ciągu znaków%d songs foundpierwszy parametrcountwybiera odpowiedni ciąg znaków w liczbie mnogiej, a drugi parametrcountjest wstawiany w miejsce symbolu zastępczego%d. Jeśli ciągi w liczbie mnogiej nie zawierają formatowania, nie musisz przekazywać trzeciego parametru do funkcjipluralStringResource.Uwaga: aby pobrać ciąg w liczbie mnogiej poza funkcją typu „composable”, użyj funkcji
context.resources.getQuantityString(R.plurals.numberOfSongsAvailable, count, count).
Format i styl
Oto kilka ważnych informacji o prawidłowym formatowaniu i stylizowaniu zasobów w postaci ciągów znaków.
Obsługa znaków specjalnych
Jeśli ciąg znaków zawiera znaki, które mają specjalne zastosowanie w XML, musisz je zmienić zgodnie ze standardowymi regułami zmiany znaków w XML/HTML. Jeśli musisz wskazać zmianę znaczenia znaku, który ma specjalne znaczenie w Androidzie, użyj poprzedzającego go lewego ukośnika.
Domyślnie Android zwija sekwencje znaków odstępu do pojedynczej spacji. Aby tego uniknąć, umieść odpowiednią część ciągu znaków w cudzysłowie. W tym przypadku wszystkie znaki odstępu (w tym nowe wiersze) zostaną zachowane w cytowanym regionie. Podwójne cudzysłowy umożliwiają też używanie zwykłych pojedynczych cudzysłowów niepoprzedzonych znakiem zmiany znaczenia.
| Znak | Formularze z odpowiednio zmienionymi znakami |
|---|---|
| @ | \@ |
| ? | \? |
| Nowy wiersz | \n |
| Tab | \t |
| Znak Unicode U+XXXX | \uXXXX |
Pojedynczy cudzysłów (') |
Dowolna z tych wartości:
|
Podwójny cudzysłów (") |
\"
Pamiętaj, że umieszczenie ciągu znaków w pojedynczych cudzysłowach nie działa. |
Zwijanie białych znaków i ucieczka znaków w Androidzie następują po przeanalizowaniu pliku zasobów jako XML. Oznacza to, że znaki <string>      </string> (spacja, spacja interpunkcyjna, spacja Unicode Em) są spłaszczane do pojedynczej spacji (" "), ponieważ po przeanalizowaniu pliku jako XML wszystkie są traktowane jako spacje Unicode.
Aby zachować te spacje w niezmienionej formie, możesz je ująć w cudzysłów (<string>"      "</string>) lub użyć znaków ucieczki w Androidzie (<string> \u0032 \u8200 \u8195</string>).
Ciągi formatujące
Jeśli chcesz sformatować ciągi znaków, możesz to zrobić, umieszczając argumenty formatu w zasobie tekstowym, jak pokazano w tym przykładzie zasobu:
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
Ten kod aplikacji formatuje ciąg znaków w funkcji kompozycyjnej, przekazując argumenty bezpośrednio do funkcji stringResource():
@Composable fun WelcomeMessage(username: String, mailCount: Int) { Text( text = stringResource( R.string.welcome_messages, username, mailCount, ) ) }
Stylizowanie za pomocą znaczników HTML
Do ciągów znaków możesz dodawać style za pomocą znaczników HTML. Przykład:
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="welcome">Welcome to <b>Android</b>!</string> </resources>
Obsługiwane są te elementy HTML:
- Pogrubienie:
<b> - Kursywa:
<i>,<cite>,<dfn>,<em> - Tekst o 25% większy:
<big> - Tekst o 20% mniejszy:
<small> - Ustawianie właściwości czcionki:
<font face="font_family" color="hex_color">. Przykłady możliwych rodzin czcionek tomonospace,serifisans_serif. - Ustawianie rodziny czcionek o stałej szerokości:
<tt> - Przekreślenie:
<s>,<strike>,<del> - Podkreślenie:
<u> - Indeks górny:
<sup> - Indeks dolny:
<sub> - Lista punktowana:
<ul>,<li> - Podziały wiersza:
<br> - Oddział:
<div> - Styl CSS:
<span style="color|background_color|text-decoration"> - Akapity:
<p dir="rtl | ltr" style="…">
W niektórych przypadkach możesz utworzyć zasób tekstowy ze stylem, który będzie też używany jako ciąg formatujący. Zwykle nie działa to, ponieważ metody formatowania, takie jak stringResource(), usuwają z ciągu wszystkie informacje o stylu.
Obejście tego problemu polega na zapisaniu tagów HTML z użyciem znaków specjalnych, które są następnie odzyskiwane za pomocą AnnotatedString.fromHtml() po sformatowaniu. Przykład:
- Zapisz zasób tekstu ze stylami jako ciąg tekstowy z kodowaniem HTML:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
Do tego sformatowanego ciągu dodawany jest element
<b>. Zwróć uwagę, że nawias otwierający jest zakodowany w HTML-u za pomocą notacji<. - Następnie sformatuj ciąg znaków jak zwykle, ale wywołaj też funkcję
AnnotatedString.fromHtml(), aby przekonwertować tekst HTML na sformatowany ciąg znaków Compose.
Ponieważ funkcja fromHtml() formatuje wszystkie encje HTML, pamiętaj, aby w ciągach używanych z sformatowanym tekstem zmienić znaczenie wszystkich możliwych znaków HTML za pomocą funkcji 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) ) }
Stylizowanie za pomocą klasy AnnotatedString
AnnotatedString to obiekt tekstowy Compose, który możesz stylizować za pomocą właściwości takich jak kolor i grubość czcionki. Twórz sformatowany tekst programowo za pomocą buildAnnotatedString i withStyle.
Ten kod aplikacji tworzy jeden element tekstowy z mieszanymi stylami:
@Composable fun StyledGreeting() { val styled = buildAnnotatedString { append("Welcome to ") withStyle(SpanStyle(fontWeight = FontWeight.Bold)) { append("Android") } append("!") } Text(text = styled) }
Aby zastosować kolor, rozmiar czcionki i dekorację tekstu, użyj SpanStyle. Aby zastosować styl na poziomie akapitu (np. wyrównanie lub wysokość wiersza), użyj 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) }
Bezpośrednie tworzenie AnnotatedString to zalecane podejście w przypadku aplikacji w jednym języku lub statycznego tekstu w Compose. Jeśli jednak chodzi o sformatowany tekst, który wymaga lokalizacji, zapoznaj się z podejściem opartym na XML <annotation> opisanym w następnej sekcji.
Stylizowanie przetłumaczonych ciągów znaków za pomocą adnotacji
W przypadku ciągów znaków, które wymagają niestandardowego formatowania i tłumaczenia, zdefiniuj tag <annotation> w pliku strings.xml każdego języka. Tłumacze zachowują adnotację niezależnie od tego, gdzie znajduje się ona w zdaniu. Odczytaj ciąg znaków za pomocą funkcji context.resources.getText(), przejdź przez jego zakresy Annotation i przekonwertuj wynik na 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) }
Tag <annotation> w pliku XML pozostaje bez zmian. Różni się tylko kod odzyskiwania. Tłumacze nadal przenoszą tag, aby otaczał on odpowiednie słowo w każdym języku.
Dodatkowe materiały
Więcej informacji o zasobach tekstowych znajdziesz w tych materiałach: