文字列リソース

文字列リソースは、アプリにテキスト文字列と、オプションのテキストのスタイルやフォーマットを提供します。アプリに文字列を提供できるリソースには、次の 3 つのタイプがあります。

String
単一の文字列を提供する XML リソース。
文字列配列
文字列配列を提供する XML リソース。
数量文字列(複数形)
複数形を表すさまざまな文字列を保有する XML リソース。

どの文字列にも、スタイル設定のマークアップと書式設定引数を適用できます。文字列のスタイル設定と書式設定については、 書式設定とスタイル設定をご覧ください。

String

アプリコード(コンポーズ可能な関数など)や他のリソース ファイルから参照できる単一の文字列。

ファイルの場所:
res/values/filename.xml
ファイル名は任意です。<string> 要素の name をリソース ID として使用します。
コンパイルされるリソースのデータ型:
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>
要素:
<resources>
必須。ルートノードにする必要があります。

属性はありません。

<string>
文字列。スタイル設定タグを含めることができます。アポストロフィや引用符はエスケープする必要があります。文字列のスタイルと書式を適切に設定する方法については、後述の書式設定とスタイル設定をご覧ください。

属性:

name
文字列。文字列の名前。この名前がリソース ID として使用されます。
例:
res/values/strings.xml に保存された XML ファイル:
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello!</string>
</resources>

次のアプリケーション コードは、stringResource() を使用して、コンポーズ可能な関数内の文字列を取得します。

@Composable
fun Greeting() {
    Text(text = stringResource(R.string.hello))
}

注: コンポーズ可能な関数の外部で文字列を取得するには、context.getString(R.string.hello) を使用します。

文字列リソースは、AndroidManifest.xml などの他の XML ファイルから参照することもできます。
<activity
    android:name=".MainActivity"
    android:label="@string/hello" />

文字列配列

アプリから参照可能な文字列の配列。

ファイルの場所:
res/values/filename.xml
ファイル名は任意です。<string-array> 要素の name をリソース ID として使用します。
コンパイルされるリソースのデータ型:
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>
要素:
<resources>
必須。ルートノードにする必要があります。

属性はありません。

<string-array>
文字列の配列を定義します。1 つまたは複数の <item> 要素を格納します。

属性:

name
文字列。配列の名前。この名前は、配列を参照するためのリソース ID として使用されます。
<item>
文字列。スタイル設定タグを含めることができます。この値は、別の文字列リソースへの参照として設定できます。<string-array> 要素の子を指定する必要があります。アポストロフィや引用符はエスケープする必要があります。文字列の適切なスタイル設定と書式設定については、以下の書式設定とスタイル設定をご覧ください。

属性はありません。

例:
res/values/strings.xml に保存された 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>

次のアプリケーション コードは、stringArrayResource() を使用して、コンポーズ可能な関数内の文字列配列を取得します。

@Composable
fun PlanetList() {
    val planets: Array =
        stringArrayResource(R.array.planets_array)
    // Render the array, e.g. inside a LazyColumn.
}

注: コンポーズ可能な関数の外部で文字列配列を取得するには、context.resources.getStringArray(R.array.planets_array) を使用します。

数量文字列(複数形)

言語によって、数量の文法上の運用に関するルールは異なります。英語では、たとえば数量 1 が特殊なケースです。1 の場合は「1 book」と記述しますが、その他の数量については「n books」と記述します。このような単数形と複数形の区別は一般的なものですが、さらに細かく区別する言語もあります。Android でサポートされている区分は、zeroonetwofewmanyother です。

特定の言語および数量にどの区分が当てはまるかを決定するルールは非常に複雑になる可能性があるため、Android では `pluralStringResource()` などのメソッドによって、適切なリソースが選択されるようになっています。pluralStringResource()

数量文字列は慣例的に、また API では現在も「数量」文字列と呼ばれていますが、実際には複数形の処理にのみ使用します。 たとえば、Gmail の「受信トレイ」を、未読メッセージがある場合に「受信トレイ (12)」などと表示するための実装に数量文字列を使用するのは間違いです。if ステートメントの代わりに数量文字列を使用する方が便利にも見えますが、一部の言語(中国語など)では単複の文法的な区別が行われないため、常に other 文字列が取得されます。

使用する文字列は、文法上の必要性 のみに基づいて選択されます。英語における 0 は、2 やその他 1 を除く数字と文法的な違いはないため(「zero books」、「one book」、「two books」となる)、数量が 0 であっても zero の文字列は無視されます。これに対して韓国語では、other という文字列だけが使用されます。

また、two は数量 2 のみに適用されるように思えますが、言語によっては、2、12、102 などが同じルールで扱われ、その他の数量とは区別される場合があります。各言語でどのような区別が求められるかは、翻訳者が判断することになります。

メッセージに数値が含まれていない場合、複数形の使用には適さない可能性があります。たとえば、リトアニア語では単数形が 1 と 101 の両方に使用されるため、「1 book」は「1 knyga」、「101 books」は「101 knyga」に翻訳されます。一方、「a book」は「knyga」で、「many books」は「daug knygų」になります。英語の複数形のメッセージに「a book」(単数形)と「many books」(複数形)が含まれていて、数字がない場合は、「knyga」(a book)/「daug knygų」(many books)と翻訳しますが、リトアニア語の文法では、101 という数値があった場合でも、1 冊の本を表す「knyga」と記載されます。

多くの場合、「Books: 1」のような数量に依存しない形式にすることで、数量文字列を回避できます。このスタイルをアプリで使用できれば、その後のアプリの管理や、翻訳時の負担が軽減されます。

API 24 以降では、さらに強力な ICU MessageFormat クラスを使用できます。

ファイルの場所:
res/values/filename.xml
ファイル名は任意です。<plurals> 要素の name をリソース ID として使用します。
リソースの参照:
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>
要素:
<resources>
必須。ルートノードにする必要があります。

属性はありません。

<plurals>
文字列のコレクション。ものの量に応じてこのうち 1 つの文字列が提供されます。1 つまたは複数の <item> 要素を格納します。

属性:

name
文字列。文字列のペアの名前。この名前がリソース ID として使用されます。
<item>
複数形または単数形の文字列。この値は、別の文字列リソースへの参照として設定できます。<plurals> 要素の子を指定する必要があります。アポストロフィや引用符はエスケープする必要があります。文字列の適切なスタイル設定と書式設定については、以下の書式設定と スタイル設定をご覧ください。

属性:

quantity
キーワード。この文字列を使用するタイミングを示す値。値が有効となる場合の例を丸かっこ内で示しています。
説明
zero数字の 0 の処理が特殊である言語(アラビア語など)。
one1 などの数字の処理が特殊である言語(英語をはじめとする大半の言語の 1 が該当。ロシア語の場合は、末尾が 1 であり、かつ 11 でない数字がこのクラスに該当)。
two2 などの数字の処理が特殊である言語(ウェールズ語の 2、スロベニア語の 102 など)。
few「小さな」数字の処理が特殊である言語(チェコ語の 2、3、4 や、ポーランド語の 12、13、14 を除く、末尾が 2、3、4 の数字など)。
many「大きな」数字の処理が特殊である言語(マルタ語の末尾が 11~99 の数字など)。
other数量について特殊な処理を必要としない言語(中国語のすべての数字、英語の 42 など)。
例:

res/values/strings.xml に保存された 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>

res/values-pl/strings.xml に保存された 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>

次のアプリケーション コードは、pluralStringResource() を使用して、コンポーズ可能な関数内の複数形の文字列を取得します。

@Composable
fun SongCount(count: Int) {
    Text(
        text = pluralStringResource(
            R.plurals.numberOfSongsAvailable,
            count,
            count,
        )
    )
}

pluralStringResource() 関数を使用する際、文字列に 数値の文字列形式が含まれる場合は、count を 2 回渡す必要があります。たとえば、 %d songs found という文字列の場合、最初の count パラメータが適切な複数形の文字列を選択し、 2 つ目の count パラメータが %d プレースホルダに挿入されます。複数形の文字列に文字列形式が含まれていない場合、3 つ目のパラメータを pluralStringResource に渡す必要はありません。

注: コンポーズ可能な関数の外部で複数形の文字列を取得するには、context.resources.getQuantityString(R.plurals.numberOfSongsAvailable, count, count) を使用します。

書式とスタイル

ここでは、文字列リソースの書式とスタイルを適切に設定する方法について説明します。

特殊文字の処理

XML で特別な意味を持つ文字が文字列に含まれている場合は、それらの文字を XML/HTML の標準のエスケープ ルールに従ってエスケープする必要があります。Android で特別な意味を持つ文字をエスケープする必要がある場合は、該当する文字の前にバックスラッシュを置きます。

Android ではデフォルトで、連続する空白文字が 1 つのスペースに短縮されます。これを回避するには、文字列の該当する部分を二重引用符で囲みます。それにより、引用符で囲んだ部分の空白文字(改行を含む)が保持されます。この二重引用符により、エスケープされない標準の単一引用符を使用することも可能になります。

文字 エスケープ書式
@ \@
\?
改行 \n
Tab \t
U+XXXX Unicode 文字 \uXXXX
単一引用符('

次のいずれか:

  • \'
  • 文字列全体を二重引用符で囲む(例: "This'll work"
二重引用符(" \"

文字列を単一引用符で囲んでも機能しません。

空白の短縮と Android のエスケープは、リソース ファイルが XML として解析された後に行われます。つまり、<string> &#32; &#8200; &#8195;</string> (スペース、句読点スペース、Unicode Em スペース)は、ファイルが XML として解析されるとすべて Unicode のスペースになるため、すべてが 1 つのスペース (" ")に短縮されます。 それらのスペースを保持するには、スペースを引用符で囲む (<string>" &#32; &#8200; &#8195;"</string>) か、Android のエスケープ (<string> \u0032 \u8200 \u8195</string>)を使用します。

文字列の書式設定

文字列の書式を設定する場合は、次のリソース例に示すように、文字列リソースに書式の引数を指定します。

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

このアプリケーション コードは、引数を 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">。フォント ファミリーの例としては、 monospaceserifsans_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() によって復元されます。次に例を示します。

  1. スタイル付きのテキスト リソースを HTML エスケープ文字列として保存します。
    <resources>
      <string name="welcome_messages">Hello, %1$s! You have &lt;b>%2$d new messages&lt;/b>.</string>
    </resources>

    この書式設定された文字列では、<b> 要素が追加されています。左かっこは HTML エスケープされています。&lt; 表記を使用しています。

  2. 次に、文字列を通常どおり書式設定し、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 テキスト オブジェクトです。buildAnnotatedStringwithStyle を使用して、スタイル付きのテキストをプログラムで作成します。

このアプリケーション コードは、さまざまなスタイルが混在する単一のテキスト要素を作成します。

@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)
}
context.getText(R.string.your_string)

AnnotatedString を直接作成する方法は、単一言語のアプリや Compose の静的テキストにおすすめです。ただし、ローカライズが必要なスタイル付きのテキストについては、次のセクションで説明する XML <annotation> の方法をご覧ください。

アノテーションを使用した翻訳済み文字列のスタイル設定

カスタム スタイル設定と翻訳の両方が必要な文字列の場合は、各ロケールの strings.xml<annotation> タグを定義します。翻訳者は、文中のどこに配置されるかに関係なく、アノテーションを保持します。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)
}

XML の <annotation> タグは変更されません。取得コードのみが異なります。翻訳者は、各言語で正しい単語を囲むようにタグを移動します。

参考情報

文字列リソースについて詳しくは、次のリソースをご覧ください。

ドキュメント

Views コンテンツ