موارد السلسلة

يوفر مصدر السلاسل النصية سلاسل نصية لتطبيقك مع خيارات لتنسيق النص وتصميمه. هناك ثلاثة أنواع من الموارد التي يمكن أن توفّر لتطبيقك السلاسل:

String
ملف 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>
العناصر:
<resources>
مطلوبة. يجب أن تكون هذه هي العقدة الجذرية.

ما مِن سمات.

<string>
سلسلة يمكن أن تتضمّن علامات تنسيق يُرجى العلم أنّه يجب إلغاء علامات الاقتباس المفردة والمزدوجة. لمزيد من المعلومات حول كيفية تحديد نمط السلاسل وتنسيقها بشكل صحيح، يُرجى الاطّلاع على التنسيق وتحديد النمط أدناه.

السمات:

name
String. اسم السلسلة. يُستخدَم هذا الاسم كمعرّف المورد.
مثلا:
تم حفظ ملف 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))
}

ملاحظة: لاسترداد سلسلة خارج دالة مركّبة، استخدِم context.getString(R.string.hello).

يمكنك أيضًا الإشارة إلى موارد السلاسل من ملفات XML أخرى، مثل 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>
العناصر:
<resources>
مطلوبة. يجب أن تكون هذه هي العقدة الجذرية.

ما مِن سمات.

<string-array>
تحدّد هذه السمة مصفوفة من السلاسل. يحتوي على عنصر واحد أو أكثر من عناصر <item>.

السمات:

name
String. اسم المصفوفة. يُستخدَم هذا الاسم كمعرّف المورد للإشارة إلى الصفيف.
<item>
سلسلة يمكن أن تتضمّن علامات تنسيق يمكن أن تكون القيمة مرجعًا إلى مورد سلسلة آخر. يجب أن يكون عنصرًا فرعيًا من عنصر <string-array>. يُرجى العِلم أنّه يجب إلغاء علامات الاقتباس المفردة والمزدوجة. راجِع القسم التنسيق والأسلوب أدناه للحصول على معلومات حول كيفية تنسيق السلاسل وتحديد أسلوبها بشكلٍ سليم.

ما مِن سمات.

مثلا:
تم حفظ ملف 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()، لاختيار المورد المناسب لك.

على الرغم من أنّها كانت تُعرف سابقًا باسم "سلاسل الكمية" (ولا تزال تُعرف بهذا الاسم في واجهة برمجة التطبيقات)، يجب فقط استخدام سلاسل الكمية مع صيغ الجمع. من الخطأ استخدام سلاسل الكمية لتنفيذ شيء مثل "البريد الوارد" في Gmail مقابل "البريد الوارد (12)" عندما تكون هناك رسائل غير مقروءة، على سبيل المثال. قد يبدو من الملائم استخدام سلاسل الكمية بدلاً من عبارة 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ų". إذا كانت رسالة الجمع باللغة الإنجليزية تتضمّن "كتابًا" (مفرد) و"العديد من الكتب" (جمع) بدون العدد الفعلي، يمكن ترجمتها إلى "knyga" (كتاب) أو "daug knygų" (العديد من الكتب)، ولكن وفقًا لقواعد اللغة الليتوانية، سيتم عرض "knyga" (كتاب واحد) عندما يكون العدد 101.

يمكن في كثير من الأحيان تجنُّب سلاسل الكميات باستخدام صيغ محايدة للكمية، مثل "الكتب: 1". سيؤدي ذلك إلى تسهيل حياتك وحياة المترجمين إذا كان هذا الأسلوب مقبولاً لتطبيقك.

في الإصدار 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>
العناصر:
<resources>
مطلوبة. يجب أن تكون هذه هي العقدة الجذرية.

ما مِن سمات.

<plurals>
مجموعة من السلاسل، يتم توفير إحدى السلاسل منها استنادًا إلى مقدار شيء ما. يحتوي على عنصر واحد أو أكثر من عناصر <item>.

السمات:

name
String. اسم لزوج السلاسل. يُستخدَم هذا الاسم كمعرّف للمورد.
<item>
سلسلة مفرد أو جمع يمكن أن تكون القيمة مرجعًا إلى مورد سلسلة آخر. يجب أن يكون عنصرًا فرعيًا من عنصر <plurals>. يُرجى العِلم أنّه يجب تخطّي علامات الاقتباس المفردة والمزدوجة. راجِع القسم التنسيق والتصميم أدناه للحصول على معلومات حول كيفية تصميم السلاسل وتنسيقها بشكل صحيح.

السمات:

quantity
الكلمة الرئيسية: قيمة تشير إلى وقت استخدام هذه السلسلة. القيم الصالحة، مع أمثلة غير شاملة بين قوسين:
القيمةالوصف
zeroعندما تتطلّب اللغة معاملة خاصة للرقم 0 (كما هو الحال في اللغة العربية)
oneعندما تتطلّب اللغة معاملة خاصة للأرقام، مثل الرقم واحد (كما هو الحال مع الرقم 1 في الإنجليزية ومعظم اللغات الأخرى؛ في الروسية، أي رقم ينتهي بالرقم 1 ولكن لا ينتهي بالرقم 11 يندرج في هذه الفئة).
twoعندما تتطلّب اللغة طريقة تعامل خاصة مع الأرقام، مثل الرقم 2 (كما هو الحال في اللغة الويلزية، أو الرقم 102 في اللغة السلوفينية).
fewعندما تتطلّب اللغة معاملة خاصة للأرقام "الصغيرة" (كما هو الحال مع الأرقام 2 و3 و4 في التشيكية، أو الأرقام التي تنتهي بـ 2 أو 3 أو 4 ولكن ليس 12 أو 13 أو 14 في البولندية)
manyعندما تتطلّب اللغة معاملة خاصة للأعداد "الكبيرة" (كما هو الحال مع الأعداد التي تنتهي من 11 إلى 99 في اللغة المالطية)
otherعندما لا تتطلّب اللغة معاملة خاصة للكمية المحدّدة (كما هو الحال مع جميع الأرقام باللغة الصينية، أو الرقم 42 باللغة الإنجليزية)
مثلا:

تم حفظ ملف 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
حرف Unicode U+XXXX \uXXXX
علامة اقتباس مفردة (')

أيّ مما يلي:

  • \'
  • ضَع السلسلة بأكملها بين علامتَي اقتباس مزدوجتَين ("This'll work"، على سبيل المثال)
علامة الاقتباس المزدوجة (") \"

يُرجى العِلم أنّ وضع السلسلة بين علامتَي اقتباس مفردتَين لن ينجح.

يحدث تصغير المسافات البيضاء وإلغاء تسلسل Android بعد تحليل ملف الموارد بتنسيق XML. هذا يعني أنّ <string> &#32; &#8200; &#8195;</string> (مسافة، مسافة علامات ترقيم، مسافة Unicode Em) يتم تصغيرها كلها إلى مسافة واحدة (" ")، لأنّها كلها مسافات Unicode بعد تحليل الملف بتنسيق XML. للحفاظ على هذه المسافات كما هي، يمكنك إما وضعها بين علامتَي اقتباس (<string>" &#32; &#8200; &#8195;"</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 باستخدام كيانات تم تجاهل تنسيقها، ثم استردادها باستخدام AnnotatedString.fromHtml() بعد إجراء التنسيق. على سبيل المثال:

  1. خزِّن مورد النص المنسّق كسلسلة تم تجاهل أحرف HTML الخاصة فيها:
    <resources>
      <string name="welcome_messages">Hello, %1$s! You have &lt;b>%2$d new messages&lt;/b>.</string>
    </resources>

    في هذه السلسلة المنسَّقة، تتم إضافة عنصر <b>. لاحظ أنّ قوس الفتح تم تحويله إلى تنسيق HTML باستخدام الترميز &lt;.

  2. بعد ذلك، يمكنك تنسيق السلسلة كالمعتاد، ولكن عليك أيضًا استدعاء 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. ومع ذلك، بالنسبة إلى النصوص المنسّقة التي تتطلّب ترجمة، يُرجى الاطّلاع على طريقة <annotation> XML المفصّلة في القسم التالي.

تنسيق السلاسل المترجَمة باستخدام التعليقات التوضيحية

بالنسبة إلى السلاسل التي تحتاج إلى تنسيق مخصّص وترجمة، حدِّد العلامة <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. ويختلف فقط رمز الاسترداد. سيظل بإمكان المترجمين نقل العلامة لتضمين الكلمة الصحيحة في كل لغة.

مصادر إضافية

لمزيد من المعلومات حول موارد السلاسل، يُرجى الاطّلاع على المراجع الإضافية التالية:

الوثائق

مشاهدة المحتوى