Skip to main content

الدليل الشامل لتوطين تطبيقات Android

من strings.xml إلى بيانات Play Store الوصفية: وطّن تطبيق Android باستخدام Kotlin وJetpack Compose وFastlane والترجمة الآلية بالذكاء الاصطناعي.

1

إعداد مشروع Android لديك للتوطين

يعتمد Android اصطلاحاً قائماً على المجلدات للتوطين. توجد سلاسك الافتراضية في res/values/strings.xml، وتوضع السلاسل المترجمة في مجلدات خاصة بالإعدادات المحلية مثل res/values-de/ وres/values-ja/، إلخ.

Android Project Structure
// Android project structure for localization:
// res/
// ├── values/              ← Default (fallback) locale
// │   └── strings.xml
// ├── values-de/           ← German
// │   └── strings.xml
// ├── values-ja/           ← Japanese
// │   └── strings.xml
// └── values-es/           ← Spanish
//     └── strings.xml
//
// Folder naming: values-{language} or values-{language}-r{Region}
// Examples: values-pt-rBR, values-zh-rCN, values-zh-rTW
يُعد مجلد res/values/ الإعدادات المحلية الاحتياطية لديك. إذا كانت سلسلة مفقودة من مجلد خاص بإعدادات محلية، يحمّلها Android من الافتراضي. لكن إذا كانت سلسلة مفقودة من الافتراضي، فسيتعطل تطبيقك في الإعدادات المحلية غير المدعومة.
2

إنشاء strings.xml

تستخدم موارد السلاسل في Android تنسيق XML مع عناصر '<string>' داخل الجذر '<resources>'. استخدم %s للعناصر النائبة النصية، و%d للأعداد الصحيحة، و%1$s/%2$s للوسائط الموضعية التي يمكن للمترجمين إعادة ترتيبها.

res/values/strings.xml
<!-- res/values/strings.xml -->
<resources>
    <string name="welcome_title">Welcome to MyApp</string>
    <string name="login_button">Sign In</string>
    <string name="settings_label">Settings</string>
    <string name="greeting">Hello, %s!</string>        <!-- %s = string -->
    <string name="item_count">%d items</string>          <!-- %d = integer -->
    <string name="app_name" translatable="false">MyApp</string>
</resources>
تؤدي الفواصل العليا غير المُهربة إلى إسقاط محلل XML بصمت. استخدم \' أو أحط القيمة بعلامات اقتباس مزدوجة. كذلك: إن فقدت سلسلة في ملف res/values/strings.xml الافتراضي، فسيحدث تعطل حاد، وليس رجوعاً سلساً كما في iOS.
Common strings.xml Mistakes
<!-- ❌ Common mistakes in strings.xml: -->

<!-- Unescaped apostrophe — crashes XML parser silently -->
<string name="message">It's a great day</string>

<!-- Missing from default values/strings.xml — app crashes -->
<!-- (only exists in values-de/strings.xml) -->

<!-- ✅ Correct versions: -->
<string name="message">It\'s a great day</string>
<!-- Or wrap in double quotes: -->
<string name="message">"It's a great day"</string>
3

التعامل مع صيغ الجمع

يستخدم Android عناصر '&lt;plurals&gt;' مع سمات quantity: zero وone وtwo وfew وmany وother. قد تحتاج كل لغة مستهدفة فئات مختلفة؛ العربية تستخدم الفئات الست كلها، والروسية تحتاج few/many، واليابانية تستخدم other فقط.

res/values/strings.xml
<!-- res/values/strings.xml -->
<resources>
    <plurals name="items_count">
        <item quantity="zero">No items</item>
        <item quantity="one">%d item</item>
        <item quantity="other">%d items</item>
    </plurals>
</resources>

<!-- Usage in Kotlin: -->
<!-- val text = resources.getQuantityString(
    R.plurals.items_count,
    count,    // selects plural form
    count     // format argument
) -->
تحدد سمة quantity صيغة الجمع استناداً إلى قواعد CLDR لإعدادات الجهاز المحلية. احرص دائماً على تضمين 'other' بوصفها صيغة احتياطية؛ فهي الفئة الوحيدة المضمونة في كل لغة.
4

الاستخدام في الشيفرة: Kotlin وJetpack Compose

يستخدم Android التقليدي getString(R.string.key) وresources.getQuantityString(). ويستخدم Jetpack Compose الدالتين stringResource(R.string.key) وpluralStringResource(). كلاهما يحل الترجمة الصحيحة وفق إعدادات الجهاز المحلية أثناء وقت التشغيل.

WelcomeScreen.kt
// Traditional Android (Activity/Fragment)
val title = getString(R.string.welcome_title)
val greeting = getString(R.string.greeting, userName)
val items = resources.getQuantityString(
    R.plurals.items_count, count, count
)

// Jetpack Compose
@Composable
fun WelcomeScreen(userName: String, itemCount: Int) {
    // ✅ stringResource — Compose-aware, triggers recomposition
    Text(text = stringResource(R.string.welcome_title))

    // ✅ With format arguments
    Text(text = stringResource(R.string.greeting, userName))

    // ✅ Plurals — count passed TWICE
    Text(text = pluralStringResource(
        R.plurals.items_count,
        itemCount,    // selects plural form
        itemCount     // format argument
    ))
}
pluralStringResource(R.plurals.items, count, count) — يُمرَّر المعامل count مرتين: الأولى لاختيار صيغة الجمع، والثانية بوصفه وسيط التنسيق. إن نسيان count الثانية هو الخطأ رقم 1 في جمع Compose.
5

مصفوفات السلاسل والسلاسل المنسّقة

استخدم '&lt;string-array&gt;' للقوائم المرتبة (مثل خيارات القوائم المنسدلة وخطوات الإعداد). استخدم وسائط تنسيق موضعية (%1$s، %2$d) في السلاسل المنسّقة كي يتمكن المترجمون من إعادة ترتيب الكلمات من دون كسر بنية الجملة.

res/values/strings.xml
<!-- res/values/strings.xml -->
<resources>
    <!-- String array for dropdown/list -->
    <string-array name="sort_options">
        <item>Most Recent</item>
        <item>Most Popular</item>
        <item>Price: Low to High</item>
        <item>Price: High to Low</item>
    </string-array>

    <!-- Positional format args for reordering -->
    <string name="welcome_message">
        Hello %1$s, you have %2$d new messages
    </string>
    <!-- Translators can reorder: -->
    <!-- %2$d neue Nachrichten für %1$s -->
</resources>
تتيح الوسائط الموضعية مثل %1$s للمترجمين إعادة ترتيب المعاملات بحرية. يمكن أن تتحول 'Hello %1$s, you have %2$d items' إلى '%2$d items for %1$s' في اللغات ذات ترتيب كلمات مختلف؛ من دون أي تغييرات في الشيفرة.
6

توطين بيانات Google Play الوصفية باستخدام Fastlane

استخدم أمر supply في Fastlane لإدارة بيانات Play Store الوصفية؛ العنوان، والوصف القصير، والوصف الكامل، وسجلات التغيير؛ على هيئة ملفات نصية عادية منظمة حسب الإعدادات المحلية داخل مستودعك.

Terminal
# Install Fastlane
$ gem install fastlane

# Initialize supply for Play Store metadata
$ fastlane supply init

# Directory structure created:
# fastlane/metadata/android/
# ├── en-US/
# │   ├── title.txt              # App name (50 chars)
# │   ├── short_description.txt  # Short desc (80 chars)
# │   ├── full_description.txt   # Full desc (4000 chars)
# │   └── changelogs/
# │       └── default.txt        # What's New
# ├── de-DE/
# │   └── ...
# └── ja-JP/
#     └── ...

# Push metadata to Play Store:
$ fastlane supply
يؤدي توطين صفحة تطبيقك في Play Store إلى زيادة التنزيلات بنسبة 30%+ في الأسواق غير الإنجليزية. يُفهرس العنوان والوصف القصير والوصف الكامل في البحث؛ وترجمتها هي أعلى توطين من حيث العائد على الاستثمار يمكنك القيام به.
Google Play

أتمتة توطين صفحة تطبيقك في Play Store

تخطَّ النسخ واللصق اليدوي. ترجم عنوان Play Store والوصف وملاحظات الإصدار عبر أكثر من 175 إعداداً محلياً مع مراعاة حدود عدد الأحرف.

استكشف تكامل Google Play
7

اختبار التوطين لديك

اختبر عبر تبديل الإعدادات المحلية في المحاكي، ومعاينات Compose باستخدام LocaleList مخصصة، وpseudolocales ضمن Developer Options. استخدم resConfigs في Gradle لإزالة موارد الإعدادات المحلية غير المرغوب فيها من مكتبات الطرف الثالث.

Testing Localization
// 1. Emulator: Settings > System > Language > Add language

// 2. Compose Preview with locale:
@Preview
@Composable
fun WelcomePreview() {
    val config = Configuration(resources.configuration).apply {
        setLocale(Locale("de"))
    }
    val localContext = LocalContext.current
    val localizedContext = localContext.createConfigurationContext(config)
    CompositionLocalProvider(
        LocalContext provides localizedContext
    ) {
        WelcomeScreen()
    }
}

// 3. Restrict library locales in build.gradle.kts:
android {
    defaultConfig {
        // Only include locales you actually translate
        resourceConfigurations += listOf("en", "de", "ja", "es", "fr")
    }
}

// 4. Enable pseudolocales in Developer Options:
// en-XA (accented) — detects hardcoded strings
// ar-XB (RTL) — tests layout mirroring
اختبر بالألمانية (يتمدد النص بنحو 30%) وباليابانية (ينكمش بنحو 50%) لاكتشاف مشكلات التخطيط. فعّل pseudolocales (en-XA للأحرف المُشكّلة، وar-XB للـ RTL) في Developer Options لاختبار التحمّل من دون ترجمات حقيقية.

أتمتة جودة الترجمة

التقط المفاتيح المفقودة، والعناصر النائبة المكسورة، ومشكلات الجمع قبل وصولها إلى المستخدمين باستخدام i18n-validate. اختبر واجهتك بترجمات زائفة باستخدام i18n-pseudo قبل وصول الترجمات الحقيقية.
8

أتمتة الترجمات

ترجم strings.xml وصيغ الجمع ومصفوفات السلاسل وبيانات Fastlane Supply الوصفية باستخدام الذكاء الاصطناعي. أتمت ترجمة سلاسل داخل التطبيق وبيانات Play Store الوصفية معاً للحصول على حضور محلي كامل.

Terminal
# Translate strings.xml files
> Translate res/values/strings.xml
  to Japanese, German, and Spanish

# Translate Play Store metadata too
> Translate fastlane/metadata/android/en-US/
  to de-DE, ja-JP, es-ES

✓ 6 files translated in 3.2s
يتعامل i18n Agent مع هروب XML في Android، ويحافظ على وسم translatable="false"، ويحترم فئات الجمع وفق CLDR لكل لغة مستهدفة، ويحافظ على وسائط التنسيق الموضعية كما هي.
JetBrains

يتوفر ملحق لـ Android Studio

ترجم موارد Android XML مباشرة من بيئة التطوير المتكاملة لديك باستخدام ملحق i18n Agent لـ IntelliJ / Android Studio.

Install
+

مكافأة: رجوع ذكي للإعدادات المحلية باستخدام LocaleChain

يتحكم نظام التشغيل في رجوع موارد Android. عند غياب ترجمات pt-BR، يتجاوز Android pt-PT بالكامل ويعرض الإنجليزية. يعترض LocaleChain عمليات البحث عن السلاسل ويتتبع سلسلة رجوع قابلة للتهيئة، بحيث يرى المستخدمون الإقليميون أقرب ترجمة متاحة.

LocaleChain for Android مكتبة Kotlin مفتوحة المصدر. عرض على GitHub

build.gradle.kts
// build.gradle.kts (app module)
dependencies {
    implementation("com.i18nagent:locale-chain-android:0.1.0")
}
MyApp.kt / BaseActivity.kt
// 1. Application.onCreate() — configure chains once
class MyApp : Application() {
    override fun onCreate() {
        super.onCreate()
        LocaleChain.configure()
    }
}

// 2. BaseActivity — wrap context per Activity
open class BaseActivity : AppCompatActivity() {
    override fun attachBaseContext(newBase: Context) {
        super.attachBaseContext(LocaleChain.wrap(newBase))
    }
}

// pt-BR user with only pt-PT translations?
// → Shows Portuguese instead of falling back to English

// Custom overrides for your specific locales:
LocaleChain.configure(
    overrides = mapOf("es-MX" to listOf("es-419", "es"))
)

مواطن الخلل الشائعة

غياب السلاسل الافتراضية يسبب أعطالاً

على خلاف iOS الذي يعرض المفتاح الخام، يتعطل Android مع ResourceNotFoundException إذا كانت سلسلة مفقودة من ملف res/values/strings.xml الافتراضي. احرص دائماً على وجود كل مفتاح في الملف الافتراضي.

تقسيمات لغة App Bundle تكسر تبديل اللغة داخل التطبيق

تقسّم Google Play App Bundles حزم APK حسب اللغة؛ لذلك لا يتلقى المستخدمون إلا سلاسل لغة جهازهم. إذا كنت توفر تبديل اللغة داخل التطبيق، فأضف bundle '{ language { enableSplit = false } }' إلى build.gradle.kts الخاص بك.

تعطل تخطيطات RTL

يحدث ذلك عند استخدام left/right بدلاً من start/end في التخطيطات، أو عند غياب android:supportsRtl="true" في AndroidManifest.xml. استخدم Refactor > Add RTL Support في Android Studio لتحويل التخطيطات الحالية تلقائياً.

تلوث موارد المكتبات

تُضمّن مكتبات الطرف الثالث ملفات values-XX/strings.xml الخاصة بها، ما يجعل Android يظن أن تطبيقك يدعم لغات لا تدعمها. استخدم resConfigs في build.gradle.kts لتقييد الإعدادات المحلية المضمّنة على تلك التي تترجمها فعلياً.

هيكل الملفات الموصى به

Project Structure
MyApp/
├── app/
│   └── src/main/
│       ├── res/
│       │   ├── values/
│       │   │   ├── strings.xml          # Default (source) strings
│       │   │   └── plurals.xml          # Plural rules
│       │   ├── values-de/
│       │   │   └── strings.xml
│       │   ├── values-ja/
│       │   │   └── strings.xml
│       │   └── values-es/
│       │       └── strings.xml
│       ├── java/com/example/myapp/
│       └── AndroidManifest.xml
├── fastlane/
│   └── metadata/android/
│       ├── en-US/
│       │   ├── title.txt
│       │   ├── short_description.txt
│       │   ├── full_description.txt
│       │   └── changelogs/default.txt
│       ├── de-DE/
│       └── ja-JP/
├── build.gradle.kts
└── settings.gradle.kts

جرّب i18n Agent الآن

أفلت ملف الترجمة هنا

JSON, YAML, PO, XML, CSV, Markdown, Properties

أو انقر للاستعراض

اللغات المستهدفة

لا حاجة إلى التسجيلتقدير فوري

الرجوع إلى إعدادات محلية بديلة باستخدام locale-chain-android

عندما يكون مفتاح الترجمة مفقوداً في إعدادات محلية إقليمية مثل pt-BR، ينتقل Android مباشرة إلى مجلد الموارد الافتراضي بدلاً من التحقق أولاً من الإعدادات المحلية الأصلية pt.

Terminal
implementation("com.i18nagent:locale-chain-android:0.1.0")
Configuration
import com.i18nagent.localechain.LocaleChain

LocaleChain.configure(
    overrides = mapOf(
        "pt-BR" to listOf("pt", "en"),
        "zh-Hant-HK" to listOf("zh-Hant", "zh", "en"),
    )
)

اطّلع على دليل الرجوع إلى إعدادات محلية بديلة للاطّلاع على القائمة الكاملة للأطر المدعومة و75 سلسلة مدمجة. Learn more →

الأسئلة الشائعة حول توطين Android