یک منبع رشتهای، رشتههای متنی را برای برنامه شما با استایل و قالببندی متن اختیاری فراهم میکند. سه نوع منبع وجود دارد که میتوانند رشتهها را در اختیار برنامه شما قرار دهند:
- رشته
- منبع XML که یک رشته واحد ارائه میدهد.
- آرایه رشتهای
- منبع XML که آرایهای از رشتهها را ارائه میدهد.
- رشتههای مقداری (جمع)
- منبع XML که رشتههای مختلفی را برای جمعبندی حمل میکند.
همه رشتهها قابلیت اعمال برخی از آرگومانهای نشانهگذاری و قالببندی استایل را دارند. برای اطلاعات بیشتر در مورد استایلبندی و قالببندی رشتهها، به بخش مربوط به قالببندی و استایلبندی مراجعه کنید.
رشته
یک رشته واحد که میتواند از کد برنامه (مانند یک تابع قابل ترکیب) یا از سایر فایلهای منبع ارجاع داده شود.
- محل فایل:
-
res/values/ filename .xml
نام فایل دلخواه است.nameعنصر<string>به عنوان شناسه منبع استفاده میشود. - نوع داده منبع کامپایل شده:
- اشارهگر منبع به یک
String. - مرجع منابع:
- در کاتلین:
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>
این کد برنامه با استفاده از
stringResource()یک رشته را از داخل یک composable بازیابی میکند:@Composable fun Greeting() { Text(text = stringResource(R.string.hello)) }
نکته: برای بازیابی یک رشته خارج از یک تابع composable، از
همچنین میتوانید منابع رشتهای را از سایر فایلهای XML، مانندcontext.getString(R.string.hello)استفاده کنید.AndroidManifest.xmlخود، ارجاع دهید:<activity android:name=".MainActivity" android:label="@string/hello" />
آرایه رشتهای
آرایهای از رشتهها که میتوان از طریق برنامه به آنها ارجاع داد.
- محل فایل:
-
res/values/ filename .xml
نام فایل دلخواه است.nameعنصر<string-array>به عنوان شناسه منبع استفاده میشود. - نوع داده منبع کامپایل شده:
- اشارهگر منبع به آرایهای از
String. - مرجع منابع:
- در کاتلین:
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>
این کد برنامه یک آرایه رشتهای را از داخل یک composable با استفاده از
stringArrayResource()بازیابی میکند:@Composable fun PlanetList() { val planets: Array
= stringArrayResource(R.array.planets_array) // Render the array, e.g. inside a LazyColumn. } نکته: برای بازیابی یک آرایه رشتهای خارج از یک تابع composable، از
context.resources.getStringArray(R.array.planets_array)استفاده کنید.
رشتههای مقداری (جمع)
زبانهای مختلف، قوانین متفاوتی برای تطابق دستوری با کمیت دارند. برای مثال، در انگلیسی، کمیت ۱ یک مورد خاص است. ما مینویسیم "۱ کتاب"، اما برای هر کمیت دیگری مینویسیم " n کتاب". این تمایز بین مفرد و جمع بسیار رایج است، اما زبانهای دیگر تمایزات دقیقتری قائل میشوند. مجموعه کامل پشتیبانی شده توسط اندروید شامل zero ، one ، two ، few ، many و other است.
قوانین مربوط به تصمیمگیری در مورد اینکه از کدام حالت برای یک زبان و کمیت مشخص استفاده شود، میتواند بسیار پیچیده باشد، بنابراین اندروید متدهایی مانند pluralStringResource() را برای انتخاب منبع مناسب در اختیار شما قرار میدهد.
اگرچه از نظر تاریخی "رشتههای مقداری" نامیده میشوند (و هنوز هم در API به این نام خوانده میشوند)، رشتههای مقداری فقط باید برای جمعها استفاده شوند. استفاده از رشتههای مقداری برای پیادهسازی چیزی مانند "صندوق ورودی" جیمیل در مقابل "صندوق ورودی (12)" در مواردی که مثلاً پیامهای خوانده نشده وجود دارد، اشتباه خواهد بود. ممکن است استفاده از رشتههای مقداری به جای یک عبارت if راحت به نظر برسد، اما توجه به این نکته مهم است که برخی از زبانها (مانند چینی) اصلاً این تمایزات دستوری را قائل نمیشوند، بنابراین همیشه رشته other را دریافت خواهید کرد.
انتخاب رشتهای که باید استفاده شود صرفاً بر اساس ضرورت دستوری انجام میشود. در انگلیسی، رشتهای که برای zero است نادیده گرفته میشود، حتی اگر مقدار آن ۰ باشد، زیرا ۰ از نظر دستوری با ۲ یا هر عدد دیگری به جز ۱ ("کتابهای صفر"، "یک کتاب"، "دو کتاب" و غیره) تفاوتی ندارد. برعکس، در کرهای فقط از رشته other استفاده میشود.
همچنین با این واقعیت که مثلاً two صدا فقط میتوانند برای کمیت ۲ به کار روند، گمراه نشوید: یک زبان ممکن است الزام کند که ۲، ۱۲، ۱۰۲ (و غیره) همگی مانند یکدیگر اما متفاوت با سایر کمیتها در نظر گرفته شوند. برای دانستن اینکه زبان آنها واقعاً بر چه تمایزاتی تأکید دارد، به مترجم خود تکیه کنید.
اگر پیام شما شامل شماره کمیت نباشد، احتمالاً گزینه خوبی برای جمع بستن نیست. برای مثال، در زبان لیتوانیایی از شکل مفرد برای هر دو کلمه ۱ و ۱۰۱ استفاده میشود، بنابراین "۱ کتاب" به صورت "۱ knyga" و "۱۰۱ کتاب" به صورت "۱۰۱ knyga" ترجمه میشود. در همین حال، "یک کتاب" به صورت "knyga" و "کتابهای زیاد" به صورت "daug knygų" است. اگر یک پیام جمع انگلیسی شامل "یک کتاب" (مفرد) و "کتابهای زیاد" (جمع) بدون شماره واقعی باشد، میتوان آن را به صورت "knyga" (یک کتاب)/"daug knygų" (کتابهای زیاد) ترجمه کرد، اما طبق قوانین لیتوانیایی، وقتی عدد ۱۰۱ باشد، "knyga" (یک کتاب واحد) را نشان میدهد.
اغلب میتوان با استفاده از فرمولهای خنثی از نظر کمیت مانند "کتابها: ۱" از رشتههای کمیت اجتناب کرد. این کار، اگر سبکی قابل قبول برای درخواست شما باشد، زندگی شما و مترجمانتان را آسانتر میکند.
در API 24+ میتوانید به جای آن از کلاس بسیار قدرتمندتر ICU MessageFormat استفاده کنید.
- محل فایل:
-
res/values/ filename .xml
نام فایل دلخواه است.nameعنصر<plurals>به عنوان شناسه منبع استفاده میشود. - مرجع منابع:
- در کاتلین:
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>
این کد برنامه یک رشته جمع را از داخل یک composable با استفاده از
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، کاراکترها را escape کنید. اگر نیاز به escape کردن کاراکتری دارید که در اندروید معنای خاصی دارد، باید از یک بک اسلش قبل از آن استفاده کنید.
به طور پیشفرض، اندروید توالی کاراکترهای فاصله خالی را در یک فاصله واحد قرار میدهد. میتوانید با قرار دادن بخش مربوطه از رشته خود در داخل علامت نقل قول دوتایی از این امر جلوگیری کنید. در این حالت، تمام کاراکترهای فاصله خالی (از جمله خطوط جدید) در ناحیه نقل قول شده حفظ میشوند. علامت نقل قول دوتایی به شما این امکان را میدهد که از علامت نقل قول تکی معمولی و بدون پوشش نیز استفاده کنید.
| شخصیت | فرم(های) طفره رفته |
|---|---|
| @ | \@ |
| ? | \? |
| خط جدید | \n |
| تب | \t |
| کاراکتر یونیکد U+XXXX | \uXXXX |
نقل قول تکی ( ' ) | هر یک از موارد زیر:
|
نقل قول دوتایی ( " ) | \"توجه داشته باشید که قرار دادن رشته در داخل تک کوتیشن (') کار نمیکند. |
از بین رفتن فاصلههای خالی و گریز اندروید پس از تجزیه فایل منبع شما به عنوان XML اتفاق میافتد. این بدان معناست که <string>      </string> (فاصله، فاصله نقطهگذاری، فاصله یونیکد Em) همگی به یک فاصله ( " " ) تبدیل میشوند، زیرا همه آنها پس از تجزیه فایل به عنوان XML، فضاهای یونیکد هستند. برای حفظ این فاصلهها به همان شکلی که هستند، میتوانید آنها را در نقل قول قرار دهید ( <string>"      "</string> ) یا از گریز اندروید ( <string> \u0032 \u8200 \u8195</string> ) استفاده کنید.
قالببندی رشتهها
اگر نیاز به قالببندی رشتههای خود دارید، میتوانید این کار را با قرار دادن آرگومانهای قالببندی خود در منبع رشته انجام دهید، همانطور که در مثال منبع زیر نشان داده شده است.
<string name="welcome_messages">Hello, %1$s! You have %2$d new messages.</string>
این کد برنامه، رشته را از داخل یک composable با ارسال آرگومانها مستقیماً به 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 با موجودیتهای escape شده است که پس از قالببندی، با AnnotatedString.fromHtml() بازیابی میشوند. برای مثال:
- منبع متنی استایلدهی شده خود را به عنوان یک رشته HTML-escaped ذخیره کنید:
<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 است. با این حال، برای متن استایلبندیشدهای که نیاز به محلیسازی دارد، به رویکرد <annotation> 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) }
تگ <annotation> در XML شما بدون تغییر باقی میماند. فقط کد بازیابی متفاوت است. مترجمان همچنان تگ را جابجا میکنند تا کلمه صحیح را در هر زبان قرار دهند.
منابع اضافی
برای اطلاعات بیشتر در مورد منابع رشتهای، به منابع اضافی زیر مراجعه کنید: