משאב מחרוזת מספק מחרוזות טקסט לאפליקציה עם עיצוב ופורמט טקסט אופציונליים. יש שלושה סוגים של מקורות שיכולים לספק מחרוזות לאפליקציה:
- מחרוזת
- משאב XML שמספק מחרוזת אחת.
- מערך מחרוזות
- משאב XML שמספק מערך של מחרוזות.
- Quantity Strings (Plurals)
- משאב XML שמכיל מחרוזות שונות לריבוי.
כל המחרוזות יכולות להחיל תגי עיצוב וארגומנטים של עיצוב. מידע על עיצוב מחרוזות זמין בקטע עיצוב.
מחרוזת
מחרוזת אחת שאפשר להפנות אליה מקוד אפליקציה (למשל פונקציה קומפוזבילית) או מקובצי משאבים אחרים.
- מיקום הקובץ:
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>
קוד האפליקציה הזה מאחזר מחרוזת מתוך פונקציה שאפשר להשתמש בה עם
stringResource():@Composable fun Greeting() { Text(text = stringResource(R.string.hello)) }
הערה: כדי לאחזר מחרוזת מחוץ לפונקציה קומפזבילית, משתמשים ב-
אפשר גם להפנות למשאבי מחרוזות מקובצי 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>
קוד האפליקציה הזה מאחזר מערך מחרוזות מתוך פונקציה שאפשר להשתמש בה עם
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 היא מקרה מיוחד. אנחנו כותבים 'ספר אחד', אבל אם מדובר בכמות אחרת, אנחנו כותבים '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 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>
קוד האפליקציה הזה מאחזר מחרוזת ברבים מתוך פונקציה שאפשר להשתמש בה שוב עם
pluralStringResource():@Composable fun SongCount(count: Int) { Text( text = pluralStringResource( R.plurals.numberOfSongsAvailable, count, count, ) ) }
כשמשתמשים בפונקציה
pluralStringResource(), צריך להעביר אתcountפעמיים אם המחרוזת כוללת עיצוב מחרוזת עם מספר. לדוגמה, במחרוזת%d songs found, הפרמטר הראשוןcountבוחר את מחרוזת הרבים המתאימה, והפרמטר השניcountמוכנס למחזיק המקום%d. אם מחרוזות הרבים לא כוללות עיצוב מחרוזות, אין צורך להעביר את הפרמטר השלישי אלpluralStringResource.הערה: כדי לאחזר מחרוזת ברבים מחוץ לפונקציה קומפזבילית, משתמשים ב-
context.resources.getQuantityString(R.plurals.numberOfSongsAvailable, count, count).
עיצוב וסגנון
ריכזנו כאן כמה דברים חשובים שכדאי לדעת על העיצוב והסגנון הנכונים של משאבי המחרוזות.
טיפול בתווים מיוחדים
כשמחרוזת מכילה תווים עם שימוש מיוחד ב-XML, צריך להוסיף לתווים escape בהתאם לכללי ה-escape הסטנדרטיים של XML/HTML. אם אתם צריכים להשתמש בתו בריחה לתו שיש לו משמעות מיוחדת ב-Android, אתם צריכים להוסיף לפניו קו נטוי הפוך.
כברירת מחדל, מערכת Android מכווצת רצפים של תווים שיוצרים רווח לרווח בודד. כדי להימנע מכך, צריך להוסיף מירכאות כפולות סביב החלק הרלוונטי במחרוזת. במקרה כזה, כל תווי הרווח הלבן (כולל שורות חדשות) יישמרו בתוך האזור שמוקף במירכאות. השימוש במירכאות כפולות מאפשר גם שימוש במירכאות רגילות בודדות שלא כוללות תווי escape.
| דמות | טפסים שהושלמו |
|---|---|
| @ | \@ |
| ? | \? |
| שורה חדשה | \n |
| Tab | \t |
| תו Unicode U+XXXX | \uXXXX |
גרש (') |
כל אחת מהאפשרויות הבאות:
|
מירכאות כפולות (") |
\"
שימו לב: אי אפשר להקיף את המחרוזת במירכאות בודדות. |
הצמצום של הרווחים הלבנים וההסרה של התווים המיוחדים ב-Android מתבצעים אחרי שקובץ המשאבים עובר ניתוח כ-XML. המשמעות היא שכל הערכים <string>      </string>
(רווח, רווח של סימן פיסוק, רווח Em של 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>
קוד האפליקציה הזה מעצב את המחרוזת מתוך פונקציה שאפשר להרכיב על ידי העברת ארגומנטים ישירות אל 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 עם ישויות שעברו escape, ואז לשחזר אותן באמצעות AnnotatedString.fromHtml() אחרי העיצוב. לדוגמה:
- מאחסנים את משאב הטקסט עם העיצוב כמחרוזת עם תווי escape של HTML:
<resources> <string name="welcome_messages">Hello, %1$s! You have <b>%2$d new messages</b>.</string> </resources>
במחרוזת המעוצבת הזו, נוסף רכיב
<b>. שימו לב שהסוגר הפותח הוא HTML-escaped, באמצעות הסימון<. - לאחר מכן מעצבים את המחרוזת כרגיל, אבל גם קוראים ל-
AnnotatedString.fromHtml()כדי להמיר את טקסט ה-HTML למחרוזת Compose עם סגנון.
הפונקציה fromHtml() מעצבת את כל ישויות ה-HTML, לכן חשוב להשתמש ב-TextUtils.htmlEncode() כדי להוסיף תווי בריחה לכל תווי ה-HTML האפשריים במחרוזות שבהן משתמשים עם הטקסט המעוצב.
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 לא משתנה. רק קוד האחזור שונה. המתרגמים עדיין מעבירים את התג כדי להקיף את המילה הנכונה בכל שפה.
מקורות מידע נוספים
למידע נוסף על משאבי מחרוזות, אפשר לעיין במקורות המידע הנוספים הבאים: