منبع رشتهای، رشتههای نوشتاری را با قالببندی و سبک نوشتاری اختیاری برای برنامهتان ارائه میدهد. سه نوع منبع وجود دارد که میتواند رشتهها را برای برنامه شما فراهم کند:
- رشته
- منبع XML که یک رشته ارائه میدهد.
- آرایه رشتهای
- منبع XML که آرایهای از رشتهها را ارائه میدهد.
- رشتههای کمیت (جمع)
- منبع 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>
- عناصر:
- مثال:
- فایل 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)) }
توجه: برای بازیابی رشتهای خارج از تابع ترکیبپذیر، از
همچنین میتوانید به منابع رشته از فایلهای 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>
- عناصر:
- مثال:
- فایل 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)استفاده کنید.
رشتههای کمیت (جمع)
زبانهای مختلف قوانین متفاوتی برای مطابقت دستوری با
کمیت دارند. برای مثال، در زبان انگلیسی، مقدار ۱ یک مورد خاص است. مینویسیم
«۱ کتاب»، اما برای هر تعداد دیگری مینویسیم «n کتاب». این تمایز بین مفرد و جمع بسیار رایج است، اما زبانهای دیگر تمایزهای دقیقتری قائل میشوند. مجموعه کاملی که Android پشتیبانی میکند عبارت است از zero، one، two، few،
many، و other.
قوانین تصمیمگیری درباره اینکه از کدام حالت برای زبان و کمیت مشخصی استفاده شود میتواند بسیار پیچیده باشد، بنابراین Android روشهایی مانند pluralStringResource() را برای انتخاب منبع مناسب برای شما ارائه میدهد.
اگرچه در گذشته به آنها «رشتههای کمیت» گفته میشد (و هنوز هم در میانای برنامهسازی کاربردی به این نام خوانده میشوند)،
رشتههای کمیت باید فقط برای جمعها استفاده شوند. استفاده از رشتههای کمیت برای پیادهسازی چیزی مانند «صندوق ورودی» Gmail درمقابل «صندوق ورودی (۱۲)» (مثلاً وقتی پیامهای خواندهنشده وجود دارد) اشتباه است. ممکن است استفاده از رشتههای کمیت بهجای عبارت if راحتتر بهنظر برسد، اما توجه به این نکته مهم است که برخی زبانها (مانند چینی) اصلاً این تمایزات دستوری را قائل نمیشوند، بنابراین همیشه رشته other را دریافت خواهید کرد.
انتخاب رشته مورداستفاده صرفاً براساس ضرورت دستوری انجام میشود. در زبان انگلیسی، رشته مربوط به zero نادیده گرفته میشود حتی اگر مقدار آن
۰ باشد، زیرا ۰ ازنظر دستوری با ۲ یا هر عدد دیگری بهجز ۱ تفاوتی ندارد
(«zero books»، «one book»، «two books»، و غیره). برعکس، در زبان کرهای
فقط رشته other استفاده میشود.
Don't be misled either by the fact that, say, two sounds like it could only
apply to the quantity 2: a language may require that 2, 12, 102 (and so on) are
all treated like one another but differently to other quantities. به مترجمتان اعتماد کنید تا بدانید زبان آنها واقعاً بر چه تفاوتهایی تأکید دارد.
اگر پیام شما حاوی عدد کمیت نیست، احتمالاً گزینه خوبی برای جمع نیست. برای مثال، در زبان لیتوانیایی، از شکل مفرد برای هر دو عدد ۱ و ۱۰۱ استفاده میشود، بنابراین «۱ کتاب» بهصورت «1 knyga» و «۱۰۱ کتاب» بهصورت «101 knyga» ترجمه میشود. درعینحال، «یک کتاب» میشود «knyga» و «کتابهای زیاد» میشود «daug knygų». اگر پیام جمع انگلیسی حاوی «a book» (مفرد) و «many books» (جمع) بدون عدد واقعی باشد، میتوان آن را بهصورت «knyga» (یک کتاب)/«daug knygų» (کتابهای زیاد) ترجمه کرد، اما با قوانین لیتوانیایی، وقتی عدد ۱۰۱ باشد، «knyga» (یک کتاب) را نشان میدهد.
اغلب میتوان بااستفاده از فرمولبندیهای خنثی ازنظر کمیت، مانند «کتابها: ۱»، از رشتههای کمیت اجتناب کرد. اگر این سبک برای برنامهتان قابلقبول باشد، کار شما و مترجمانتان را آسانتر میکند.
در 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>
- عناصر:
- مثال:
فایل 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 دارند، باید نویسهها را طبق قوانین استاندارد گریز XML/HTML گریز دهید. اگر باید از نویسهای که در Android معنای خاصی دارد استفاده کنید، باید از واکجخط قبلاز آن استفاده کنید.
بهطور پیشفرض، Android توالی نویسههای فاصله سفید را در یک فاصله تکی جمع میکند. با قرار دادن بخش مربوطه از رشته در گیومه دوتایی میتوانید از این مشکل جلوگیری کنید. در این حالت، همه نویسههای فاصله سفید (ازجمله خطوط جدید) در منطقه نقلقولشده حفظ خواهند شد. علامت نقلقول دوتایی به شما امکان میدهد از علامت نقلقول تکی معمولی بدون گریز هم استفاده کنید.
| نویسه | فرم(های) گریز |
|---|---|
| @ | \@ |
| ؟ | \? |
| خط جدید | \n |
| زبانه | \t |
| نویسه یونیکد U+XXXX | \uXXXX |
علامت نقل قول تکی (') |
هرکدام از موارد زیر:
|
علامت نقل قول (") |
\"
توجه داشته باشید که قرار دادن رشته در گیومه تکی کار نمیکند. |
فشردهسازی فضای خالی و گریز Android پساز تجزیه فایل منبع شما بهعنوان XML اتفاق میافتد. این یعنی <string>      </string>
(فاصله، فاصله نقطهگذاری، فاصله Unicode Em) همگی به یک فاصله واحد (" ") تبدیل میشوند، زیرا پساز تجزیه فایل بهعنوان 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> - نوشتار ۲۵٪ بزرگتر:
<big> - نوشتار ۲۰٪ کوچکتر:
<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>اضافه شده است. توجه داشته باشید که براکت باز بااستفاده از نماد<، HTML-escaped است. - سپس رشته را طبق معمول قالببندی کنید، اما
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 شما تغییر نکرده است. فقط کد بازیابی
متفاوت است. مترجمان همچنان برچسب را جابهجا میکنند تا کلمه صحیح را در هر زبان دربرگیرد.
منابع بیشتر
برای اطلاعات بیشتر درباره منابع رشته، منابع اضافی زیر را ببینید: