文字列リソースは、アプリケーションのテキスト文字列に対して、テキストのスタイルや書式を任意で設定します。 アプリケーションに文字列を提供できるリソースは 3 種類あります。
- 文字列
- 1 つの文字列を提供する XML リソース。
- 文字列配列
- 文字列配列を提供する XML リソース。
- 数量文字列(複数形)
- さまざまな複数形の文字列を扱う XML リソース。
すべての文字列は、スタイル設定のマークアップや書式設定の引数を適用可能です。文字列のスタイル設定と形式指定の詳細は、書式設定とスタイル設定のセクションをご覧ください。
文字列
アプリケーションから、または他のリソース ファイル(XML レイアウトなど)から参照できる、1 つの文字列。
注: 文字列は、name 属性(XML ファイルの名前ではありません)で提供された値を使って参照される、単純なリソースです。
そのため、文字列リソースと他の単純なリソースを、1 つの XML ファイル内の 1 つの <resources> 要素の中で組み合わせることが可能です。
- ファイルの場所:
res/values/filename.xml
ファイル名は任意です。<string>要素のnameはリソース ID として使用されます。- コンパイルずみのリソース データタイプ:
Stringに対するリソース ポインタ- リソース リファレンス:
-
Java の場合:
R.string.string_name
XML の場合:@string/string_name - 構文:
-
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="string_name" >text_string</string> </resources>
- エレメント:
- 例:
res/values/strings.xmlに保存された XML ファイル:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello!</string> </resources>このレイアウト XML は文字列をビューに適用します。
<TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" />このアプリケーション コードは文字列を取得します。
String string =
getString(R.string.hello);getString(int)とgetText(int)のどちらかを使って文字列を取得できます。getText(int)は文字列に適用されたリッチテキストのスタイルを保持します。
文字列配列
アプリケーションから参照可能な文字列配列。
注: 文字列配列は、name 属性(XML ファイルの名前ではありません)で提供された値を使って参照される、単純なリソースです。
そのため、文字列配列リソースと他の単純なリソースを、1 つの XML ファイル内の 1 つの <resources> 要素の中で組み合わせることが可能です。
- ファイルの場所:
res/values/filename.xml
ファイル名は任意です。<string-array>要素のnameはリソース ID として使用されます。- コンパイルずみのリソース データタイプ:
String配列へのリソース ポインタ。- リソース リファレンス:
-
Java の場合:
R.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>
- エレメント:
- 例:
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>このアプリケーション コードは文字列配列を取得します。
Resources res =
getResources(); String[] planets = res.getStringArray(R.array.planets_array);
数量文字列(複数形)
言語が異なると、数量と文法を一致させるためのルールも異なります。たとえば、英語では、1 という数は特別なケースです。
1 冊の本は「1 book」と書きますが、その他の数の場合は「n books」と書きます。
この単数形と複数形の違いはごく一般的なものですが、もっと微妙な違いのある言語も存在します。
Android でサポートされているフル セットは、zero、one、two、few、many、other です。
特定の言語と数量で使用すべきケースを判断するためのルールは、非常に複雑になりかねないので、Android では getQuantityString() という、適切なリソースを選択するためのメソッドが用意されています。
以前から「数量文字列」と呼ばれていますが(API 内でもそう呼ばれています)、数量文字列は複数形にのみ使用します。
たとえば、Gmail の「Inbox」と、未読メッセージがある場合の「Inbox (12)」のような違いを実装するために数量文字列を使うのは誤りです。
if 文の代わりに数量文字列を使うのは便利に思えるかもしれませんが、一部の言語(中国語など)ではそうした文法上の区別をしないため、常に other 文字列を使うという点に注意が必要です。
使用する文字列の選択は、文法上の「必要性」にのみ基づいて行われます。英語では、zero の文字列は、数量が 0 の場合でも無視されます。0 は、1 以外の、2 やその他の数と文法上の違いはないからです(「zero books」、「one book」、「two books」などと表します)。
反対に韓国語では、other 文字列のみが使われます。
たとえば、two は 2 という数量にのみ適用できるように思えますが、誤解のないようにしてください。ある言語では、2、12、102 などの数はすべて同じように扱い、他の数とは区別する必要があるかもしれないからです。
各言語が実際にどのような区別を必要としているかを知るには、その言語の翻訳担当者に相談してください。
たとえば「Books: 1」のように、数量について中立的な表現を使うことで、数量文字列を使用せずに済む場合が多くあります。 それがアプリケーションと調和したスタイルであれば、デベロッパーや翻訳者の負担は減ります。
注: 複数形の集合は、name 属性(XML ファイルの名前ではありません)で提供された値を使って参照される、単純なリソースです。
そのため、複数形リソースと他の単純なリソースを、1 つの XML ファイル内の 1 つの <resources> 要素の中で組み合わせることが可能です。
- ファイルの場所:
res/values/filename.xml
ファイル名は任意です。<plurals>要素のnameはリソース ID として使用されます。- リソース リファレンス:
-
Java の場合:
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>
- エレメント:
- 例:
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>Java コード:
int count = getNumberOfsongsAvailable(); Resources res =
getResources(); String songsFound = res.getQuantityString(R.plurals.numberOfSongsAvailable, count, count);getQuantityString()メソッドを使う場合、文字列に数による文字列書式設定が含まれていれば、countを 2 回渡す必要があります。 たとえば、%d songs foundという文字列では、1 回目のcountパラメータが適切な複数形の文字列を選び、2 回目のcountパラメータが%dプレースホルダに挿入されます。 複数形の文字列に文字列書式設定が含まれていなければ、3 つ目のパラメータをgetQuantityStringに渡す必要はありません。
書式設定とスタイル設定
ここでは、文字列リソースの書式とスタイルを正しく設定するために理解しておくべき重要な点をいくつか説明します。
アポストロフィと引用符をエスケープする
文字列にアポストロフィ(')がある場合は、それをバックスラッシュ(\')でエスケープするか、文字列を二重引用符("")で囲む必要があります。
たとえば、以下は有効な文字列と無効な文字列の例です。
<string name="good_example">This\'ll work</string>
<string name="good_example_2">"This'll also work"</string>
<string name="bad_example">This doesn't work</string>
<!-- Causes a compile error -->
文字列に二重引用符がある場合は、それをエスケープする必要があります(\")。
文字列を単一引用符で囲んでも「無効」です。
<string name="good_example">This is a \"good string\".</string>
<string name="bad_example">This is a "bad string".</string>
<!-- Quotes are stripped; displays as: This is a bad string. -->
<string name="bad_example_2">'This is another "bad string".'</string>
<!-- Causes a compile error -->
文字列の書式を設定する
String.format(String, Object...) を使用して文字列の書式を設定する必要がある場合は、書式引数を文字列リソースに格納します。
たとえば、次のようなリソースがあるとします。
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
この例では、書式文字列には 2 つの引数があります。%1$s は文字列、%2$d は小数です。
このように、アプリケーションから引数で文字列の書式設定をすることが可能です。
Resources res = getResources();
String text = String.format(res.getString(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>テキストを斜体にします。<u>テキストにアンダーラインを引きます。
書式文字列としても使用する、スタイル設定済みテキスト リソースを作成したい場合があるかもしれません。
通常、これはうまくいきません。String.format(String, Object...) メソッドが文字列からすべてのスタイル情報を取り除くからです。
この回避策は、エスケープされたエンティティを使って HTML タグを書くことです。そうすると、書式設定が行われた後に、fromHtml(String) によって復元されます。
次に例を示します。
- スタイル設定をしたテキスト リソースを HTML のエスケープ処理をした文字列として格納します。
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
この書式設定済みの文字列には、
<b>要素が追加されています。左かっこは、<記号を使って HTML をエスケープしていることに注意してください。 - 次に、通常の方法で文字列の書式を設定しますが、さらに
fromHtml(String)を呼び出して、HTML テキストをスタイル設定済みのテキストに変換します。Resources res =
getResources(); String text = String.format(res.getString(R.string.welcome_messages), username, mailCount); CharSequence styledText = Html.fromHtml(text);
fromHtml(String) メソッドでは、すべての HTML エンティティの書式を設定します。そのため、htmlEncode(String) を使用して、書式設定済みのテキストで使用している文字列中の HTML 文字をできる限りエスケープするようにします。
たとえば、文字列の引数を、「<」や「&」のような文字を含む String.format() に渡そうとする場合には、書式を設定する前にそうした文字をエスケープする必要があります。そうすると、書式設定済みの文字列が fromHtml(String) によって渡されたときに、その文字は本来書かれていたとおりに表示されます。
次に例を示します。
String escapedUsername = TextUtil.htmlEncode(username); Resources res =getResources(); String text = String.format(res.getString(R.string.welcome_messages), escapedUsername, mailCount); CharSequence styledText = Html.fromHtml(text);
Spannable でスタイル設定をする
Spannable は、色やフォント ウェイトといった書体プロパティでスタイルを設定できるテキスト オブジェクトです。
SpannableStringBuilder を使ってテキストを作成してから、android.text.style パッケージで定義されたスタイルをテキストに適用します。
以下のヘルパー メソッドを使うと、Spannable テキストを作成する処理の大部分を構成できます。
/**
* Returns a CharSequence that concatenates the specified array of CharSequence
* objects and then applies a list of zero or more tags to the entire range.
*
* @param content an array of character sequences to apply a style to
* @param tags the styled span objects to apply to the content
* such as android.text.style.StyleSpan
*
*/
private static CharSequence apply(CharSequence[] content, Object... tags) {
SpannableStringBuilder text = new SpannableStringBuilder();
openTags(text, tags);
for (CharSequence item : content) {
text.append(item);
}
closeTags(text, tags);
return text;
}
/**
* Iterates over an array of tags and applies them to the beginning of the specified
* Spannable object so that future text appended to the text will have the styling
* applied to it. Do not call this method directly.
*/
private static void openTags(Spannable text, Object[] tags) {
for (Object tag : tags) {
text.setSpan(tag, 0, 0, Spannable.SPAN_MARK_MARK);
}
}
/**
* "Closes" the specified tags on a Spannable by updating the spans to be
* endpoint-exclusive so that future text appended to the end will not take
* on the same styling. Do not call this method directly.
*/
private static void closeTags(Spannable text, Object[] tags) {
int len = text.length();
for (Object tag : tags) {
if (len > 0) {
text.setSpan(tag, 0, len, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
text.removeSpan(tag);
}
}
}
以下の bold、italic、color のメソッドでは、ヘルパー メソッドを呼び出して、android.text.style パッケージで設定されたスタイルを適用する方法を示しています。
別の種類のテキスト スタイル設定を行う場合にも、同じメソッドを作成できます。
/**
* Returns a CharSequence that applies boldface to the concatenation
* of the specified CharSequence objects.
*/
public static CharSequence bold(CharSequence... content) {
return apply(content, new StyleSpan(Typeface.BOLD));
}
/**
* Returns a CharSequence that applies italics to the concatenation
* of the specified CharSequence objects.
*/
public static CharSequence italic(CharSequence... content) {
return apply(content, new StyleSpan(Typeface.ITALIC));
}
/**
* Returns a CharSequence that applies a foreground color to the
* concatenation of the specified CharSequence objects.
*/
public static CharSequence color(int color, CharSequence... content) {
return apply(content, new ForegroundColorSpan(color));
}
以下の例では、こうしたメソッドを連結させて、個々の単語に異なる種類のスタイルを適用した文字列の作成方法を示しています。
// Create an italic "hello, " a red "world",
// and bold the entire sequence.
CharSequence text = bold(italic(res.getString(R.string.hello)),
color(Color.RED, res.getString(R.string.world)));