منابع رشته ای

یک منبع رشته‌ای، رشته‌های متنی را برای برنامه شما با استایل و قالب‌بندی متن اختیاری فراهم می‌کند. سه نوع منبع وجود دارد که می‌توانند رشته‌ها را در اختیار برنامه شما قرار دهند:

رشته
منبع 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>
عناصر:
<resources>
الزامی. این باید گره ریشه باشد.

بدون ویژگی.

<string>
یک رشته، که می‌تواند شامل تگ‌های استایل‌دهی باشد. توجه داشته باشید که باید از آپاستروف و علامت نقل قول استفاده کنید. برای اطلاعات بیشتر در مورد نحوه استایل‌دهی و قالب‌بندی صحیح رشته‌های خود، به بخش قالب‌بندی و استایل‌دهی در زیر مراجعه کنید.

ویژگی‌ها:

name
رشته . نامی برای رشته. این نام به عنوان شناسه منبع استفاده می‌شود.
مثال:
فایل 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، از context.getString(R.string.hello) استفاده کنید.

همچنین می‌توانید منابع رشته‌ای را از سایر فایل‌های XML، مانند 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>
عناصر:
<resources>
الزامی. این باید گره ریشه باشد.

بدون ویژگی.

<string-array>
آرایه‌ای از رشته‌ها را تعریف می‌کند. شامل یک یا چند عنصر <item> است.

ویژگی‌ها:

name
String . نامی برای آرایه. این نام به عنوان شناسه منبع برای ارجاع به آرایه استفاده می‌شود.
<item>
یک رشته، که می‌تواند شامل تگ‌های استایل‌بندی باشد. مقدار می‌تواند ارجاعی به یک منبع رشته‌ای دیگر باشد. باید فرزند یک عنصر <string-array> باشد. توجه داشته باشید که باید آپاستروف و علامت نقل قول را escape کنید. برای کسب اطلاعات در مورد نحوه استایل‌بندی و قالب‌بندی صحیح رشته‌های خود، به بخش قالب‌بندی و استایل‌بندی در زیر مراجعه کنید.

بدون ویژگی.

مثال:
فایل 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>
عناصر:
<resources>
الزامی. این باید گره ریشه باشد.

بدون ویژگی.

<plurals>
مجموعه‌ای از رشته‌ها که از بین آنها، یک رشته بسته به مقدار چیزی ارائه می‌شود. شامل یک یا چند عنصر <item> است.

ویژگی‌ها:

name
String . نامی برای جفت رشته‌ها. این نام به عنوان شناسه منبع استفاده می‌شود.
<item>
یک رشته جمع یا مفرد. مقدار می‌تواند ارجاعی به یک منبع رشته‌ای دیگر باشد. باید فرزند یک عنصر <plurals> باشد. توجه داشته باشید که باید آپاستروف و علامت نقل قول را escape کنید. برای کسب اطلاعات در مورد نحوه صحیح استایل‌بندی و قالب‌بندی رشته‌های خود، به بخش قالب‌بندی و استایل‌بندی در زیر مراجعه کنید.

ویژگی‌ها:

quantity
کلمه کلیدی . مقداری که نشان می‌دهد این رشته چه زمانی باید استفاده شود. مقادیر معتبر، با مثال‌های غیرجامع در داخل پرانتز:
ارزش توضیحات
zero وقتی زبان، رفتار خاصی با عدد ۰ (مانند عربی) می‌طلبد.
one وقتی زبان، رفتار خاصی با اعدادی مانند یک را می‌طلبد (مانند عدد ۱ در انگلیسی و اکثر زبان‌های دیگر؛ در روسی، هر عددی که به ۱ ختم می‌شود اما به ۱۱ ختم نمی‌شود، در این دسته قرار می‌گیرد).
two وقتی زبان، برخورد ویژه‌ای با اعدادی مانند دو را می‌طلبد (مثل عدد ۲ در زبان ولزی یا عدد ۱۰۲ در زبان اسلوونیایی).
few وقتی زبان، برخورد ویژه‌ای با اعداد «کوچک» را ایجاب می‌کند (مانند ۲، ۳ و ۴ در زبان چک؛ یا اعدادی که به ۲، ۳ یا ۴ ختم می‌شوند اما به ۱۲، ۱۳ یا ۱۴ ختم نمی‌شوند در زبان لهستانی).
many وقتی زبان، رفتار ویژه‌ای با اعداد «بزرگ» را ایجاب می‌کند (مانند اعدادی که در زبان مالتی به ۱۱ تا ۹۹ ختم می‌شوند).
other وقتی زبان مربوطه، رفتار خاصی با کمیت داده شده نداشته باشد (مانند همه اعداد در چینی یا ۴۲ در انگلیسی).
مثال:

فایل 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
نقل قول تکی ( ' )

هر یک از موارد زیر:

  • \'
  • کل رشته را داخل علامت نقل قول دوتایی قرار دهید (برای مثال، "This'll work" ).
نقل قول دوتایی ( " ) \"

توجه داشته باشید که قرار دادن رشته در داخل تک کوتیشن (') کار نمی‌کند.

از بین رفتن فاصله‌های خالی و گریز اندروید پس از تجزیه فایل منبع شما به عنوان XML اتفاق می‌افتد. این بدان معناست که <string> &#32; &#8200; &#8195;</string> (فاصله، فاصله نقطه‌گذاری، فاصله یونیکد Em) همگی به یک فاصله ( " " ) تبدیل می‌شوند، زیرا همه آنها پس از تجزیه فایل به عنوان XML، فضاهای یونیکد هستند. برای حفظ این فاصله‌ها به همان شکلی که هستند، می‌توانید آنها را در نقل قول قرار دهید ( <string>" &#32; &#8200; &#8195;"</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() بازیابی می‌شوند. برای مثال:

  1. منبع متنی استایل‌دهی شده خود را به عنوان یک رشته HTML-escaped ذخیره کنید:
    <resources>
      <string name="welcome_messages">Hello, %1$s! You have &lt;b>%2$d new messages&lt;/b>.</string>
    </resources>

    در این رشته‌ی قالب‌بندی‌شده، یک عنصر <b> اضافه شده است. توجه داشته باشید که براکت آغازین با استفاده از نمادگذاری &lt; از نوع HTML-escaped است.

  2. سپس رشته را طبق معمول قالب‌بندی کنید، اما همچنین 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 شما بدون تغییر باقی می‌ماند. فقط کد بازیابی متفاوت است. مترجمان همچنان تگ را جابجا می‌کنند تا کلمه صحیح را در هر زبان قرار دهند.

منابع اضافی

برای اطلاعات بیشتر در مورد منابع رشته‌ای، به منابع اضافی زیر مراجعه کنید:

مستندات

محتوا را مشاهده می‌کند