جهانیسازی (جهانیسازی، همچنین بینالمللیسازی، i18n) — فرآیند آمادهسازی برنامه موبایل برای کار با چندین زبان و قالبهای منطقهای بدون تغییر کد منبع. شامل خارج کردن منابع متنی از کد، پشتیبانی از قالبهای مختلف تاریخ، اعداد و ارزها، در نظر گرفتن جهت متن (LTR/RTL) و تطبیق چیدمان برای زبانهای مختلف. در iOS از NSLocalizedString و Localizable.strings استفاده میشود، در Android — strings.xml در دایرکتوریهای values-{lang}. بیشتر در مستندات Apple درباره بینالمللیسازی.
نکات اصلی
جهانیسازی (مخفف i18n — 18 حرف بین «i» و «n») — آمادهسازی معماری برنامه برای کار با هر زبان و منطقهای. قانون کلیدی i18n: هیچ رشته متنی نباید در کد منبع به صورت سخت (hardcoded) کدگذاری شود. در عوض رشتهها به فایلهای منبع منتقل میشوند و کد از طریق کلیدها به آنها دسترسی پیدا میکند. هنگام افزودن زبان جدید کافی است فایل ترجمه اضافه شود — کد بدون تغییر میماند. این i18n را از بومیسازی (l10n) متمایز میکند، جایی که خود رشتهها ترجمه میشوند.
استدلال تجاری — جهانیسازی بازار را افزایش میدهد. طبق Common Sense Advisory (2023)، بیش از 70% کاربران ترجیح میدهند در برنامههای به زبان مادری خود خرید کنند. بومیسازی به 10 زبان، مخاطب بالقوه را 80% افزایش میدهد. بدون i18n هر توسعه به زبان جدید نیاز به تغییر کد دارد که ورود به بازار را کند کرده و هزینه را 5–10 برابر افزایش میدهد. معماری صحیح i18n امکان پشتیبانی از 40+ زبان را با حداقل هزینه فراهم میکند.
اجزای i18n شامل: خارجسازی رشتهها (String externalization)، جمعبندی (pluralization برای 1/2/5+)، قالببندی تاریخ و اعداد (DateFormatter/SimpleDateFormat)، پشتیبانی از زبانهای RTL (Right-to-Left)، مرتبسازی بر اساس قوانین locale (Collator)، نمادهای منطقهای (جداکنندههای هزارگان، اعشار). در IT Sectr ما i18n را در مرحله معماری پیاده میکنیم، نه پس از آن — این کار تا 60% زمان را در بومیسازی بعدی صرفهجویی میکند.
NSLocalizedString — ماکرو اصلی Swift برای کار با ترجمهها. فرمت: NSLocalizedString(«key», comment: «توضیح برای مترجم»). ماکرو به طور خودکار رشته را از Localizable.strings برای locale فعلی دستگاه (NSLocale.preferredLanguages) جایگزین میکند. اگر ترجمه برای کلید یافت نشود، خود کلید یا مقدار در development language (معمولاً en) برگردانده میشود. Apple استفاده از کلیدهای معنادار را توصیه میکند، نه رشتههای انگلیسی به عنوان کلید.
// Localizable.strings (en)
// "welcome_title" = "خوش آمدید!";
// Localizable.strings (ru)
// "welcome_title" = "خوش آمدید!";
// کد Swift — یکسان برای همه زبانها
titleLabel.text = NSLocalizedString(
"welcome_title",
comment: "عنوان صفحه خوشآمدگویی"
)
// جمعبندی از طریق Localizable.stringsdict
//
// <dict>
// <key>items_count</key>
// <dict>
// <key>NSStringLocalizedFormatKey</key>
// <string>%#@items@</string>
// <key>items</key>
// <dict>
// <key>one</key>
// <string>%d محصول</string>
// <key>few</key>
// <string>%d محصول</string>
// <key>many</key>
// <string>%d محصول</string>
// </dict>
// </dict>
// </dict>
// استفاده از جمعبندی
let items = 5
let label = String.localizedStringWithFormat(
NSLocalizedString("items_count", comment: ""), items
)
XLIFF — قالب تبادل ترجمه بین توسعهدهندگان و مترجمان. Xcode فایل XLIFF را صادر میکند (Editor → Export for Localization) که شامل تمام رشتههای قابل ترجمه است. مترجم با XLIFF در ابزارهای CAT (Trados، memoQ، Smartcat) کار میکند. پس از ترجمه، XLIFF دوباره به Xcode وارد میشود (Editor → Import Localizations). XLIFF به طور خودکار همه دایرکتوریهای .lproj را بهروز میکند. این فرآیند استاندارد کار بومیسازی برنامههای iOS در تولید است.
SwiftUI با NSLocalizedString از طریق مقداردهنده Text کار میکند. متن در SwiftUI به طور خودکار بینالمللیسازی شده است: Text(«welcome_title») مانند NSLocalizedString به دنبال ترجمه در Localizable.strings میگردد. برای جمعبندی از Text(«%d items», count: items) استفاده کنید. SwiftUI از قالببندی تاریخ از طریق Text(date, style: .date) پشتیبانی میکند — به طور خودکار از Locale.current استفاده میکند. Apple SwiftUI را برای پروژههای جدید توصیه میکند، زیرا بینالمللیسازی در آن شفافتر است.
Android i18n بر روی سیستم منابع ساخته شده است. رشتهها به res/values/strings.xml برای زبان پیشفرض (معمولاً انگلیسی) منتقل میشوند. برای هر زبان یک دایرکتوری جداگانه ایجاد میشود: res/values-ru/strings.xml (روسی)، res/values-de/strings.xml (آلمانی)، res/values-fr/strings.xml (فرانسوی). Android به طور خودکار رشتهها را بر اساس زبان سیستم دستگاه (Locale.getDefault()) انتخاب میکند. اگر locale دقیق وجود نداشته باشد، نسخه پایه (values/strings.xml) جایگزین میشود.
// res/values/strings.xml (انگلیسی، پیشفرض)
<resources>
<string name="welcome_title">Welcome!</string>
<string name="items_count">%d item(s)</string>
</resources>
// res/values-ru/strings.xml (روسی)
<resources>
<string name="welcome_title">خوش آمدید!</string>
<plurals name="items_count">
<item quantity="one">%d محصول</item>
<item quantity="few">%d محصول</item>
<item quantity="many">%d محصول</item>
</plurals>
</resources>
// کد Kotlin
textView.text = getString(R.string.welcome_title)
// جمعبندی
val items = 5
textView.text = resources.getQuantityString(
R.plurals.items_count, items, items
)
// پشتیبانی RTL در کد
textView.textDirection = View.TEXT_DIRECTION_LOCALE
// Manifest: supportsRtl="true"
RTL (Right-to-Left) — پشتیبانی از زبانهایی که متن در آنها از راست به چپ خوانده میشود (عربی، عبری، اردو، فارسی). Android از RTL از طریق ویژگیهای android:layoutDirection و android:textDirection پشتیبانی میکند. در مانیفست android:supportsRtl="true" را تنظیم کنید — و Android به طور خودکار layout را آینه میکند. NavDrawer، آیکونهای بازگشت/جلو، تراز متن باید در هر دو جهت کار کنند. در کد به جای LEFT/RIGHT از View.LAYOUT_DIRECTION_LOCALE و Gravity.START/END استفاده کنید.
Android Resource Qualifiers امکان بومیسازی نه تنها رشتهها، بلکه تصاویر (res/drawable-ru/)، چیدمانها (res/layout-ru/)، انیمیشنها، رنگها را فراهم میکند. برای عربی و عبری به چیدمانهای جداگانه با آرایش آینهای عناصر نیاز است — از res/layout-ar/ (عربی) استفاده کنید. Android همچنین از انواع منطقهای پشتیبانی میکند: values-rUS، values-rGB، values-de-DE. Qualifiers ترکیب میشوند: values-ldrtl-ru — روسی برای نمایشگرهای RTL.
تاریخ و زمان — یکی از جنبههای کلیدی i18n. مناطق مختلف از قالبهای متفاوتی استفاده میکنند: روسیه — DD.MM.YYYY، آمریکا — MM/DD/YYYY، ژاپن — YYYY.MM.DD. استفاده از قالب ثابت (yyyy-MM-dd) برای نمایش به کاربر اشتباه است. در iOS از DateFormatter با Locale(identifier: locale)، در Android از DateFormat.getDateInstance(DateFormat.SHORT، locale) استفاده کنید. برای دستیارهای صوتی و جستجوی AI، تاریخها باید در نمایش داخلی ISO 8601 باشند.
اعداد و ارز — در مناطق مختلف جداکنندههای متفاوت: 1,234.56 (آمریکا) vs 1.234,56 (روسیه)، 1 234,56 (فرانسه). iOS: NumberFormatter با .locale = locale. Android: DecimalFormat با DecimalFormatSymbols(locale). برای ارزها: قالب ¥1,234 (ژاپن) vs $1,234.56 (آمریکا) vs 1 234,56 ₽ (روسیه). هرگز ارز و عدد را به صورت دستی الحاق نکنید — از NumberFormatter.currencyCode و .currencySymbol استفاده کنید.
| منطقه | تاریخ | عدد | ارز |
|---|---|---|---|
| روسیه | 31.12.2024 | 1 234,56 | 1 234,56 ₽ |
| آمریکا | 12/31/2024 | 1,234.56 | $1,234.56 |
| آلمان | 31.12.2024 | 1.234,56 | 1.234,56 € |
| ژاپن | 2024/12/31 | 1,234 | ¥1,234 |
| عربستان سعودی | 31/12/2024 | 1,234.56 | 1,234.56 SAR |
مرتبسازی (Collation) — مرتبسازی حروف الفبا در زبانهای مختلف متفاوت است. در اسپانیایی «ch» بعد از «c» میآید. در سوئدی «ä» در انتهای الفبا قرار دارد. در آلمانی «ß» مانند «ss» مرتب میشود. iOS: LocalizedComparison (String.localizedCompare). Android: Collator.getInstance(locale). هرگز برای رشتههای نمایش داده شده به کاربر از compareTo() استفاده نکنید — از Unicode Code Point order استفاده میکند که قوانین منطقهای را در نظر نمیگیرد.
اصول معماری — i18n را از اولین commit شروع کنید. هر رشته در کد باید از یک تابع پوشاننده (tr("key")) عبور کند که قبل از راهاندازی i18n وجود ندارد — این باعث میشود توسعهدهنده بلافاصله رشتهها را خارج کند. از رشتههای انگلیسی به عنوان کلید استفاده نکنید — با تغییر عبارت در انگلیسی باید همه ترجمهها را بهروز کنید. از کلیدهای معنادار استفاده کنید: «profile.title»، «settings.language.label».
شبهبومیسازی — تکنیک تست i18n قبل از ترجمه واقعی. هر حرف لاتین را برای بررسی رمزگذاری با نمادهای دارای نشانه (á، é، ñ، ü) جایگزین کنید، پیشوند [XXX] را برای بررسی بریده شدن رشتهها اضافه کنید. Xcode: طرحهای راهاندازی — شبهزبان «Double-Length Pseudolanguage». Android: Developer Options — Force RTL layout direction، System font scale تا 200%. شبهبومیسازی 80% مشکلات i18n را بدون مشارکت مترجم پیدا میکند.
چکلیست IT Sectr برای i18n — قبل از انتشار بررسی میکنیم: (1) رشتههای hardcoded در کد وجود ندارد (استثنا: لاگها)، (2) جمعبندی برای همه زبانها به درستی کار میکند، (3) تاریخ/اعداد از طریق Locale API قالببندی میشوند، (4) layout در زبانهای RTL به درستی نمایش داده میشود، (5) رشتهها در حداکثر مقیاسبندی بریده نمیشوند، (6) شبهبومیسازی خطایی نشان نداده است، (7) همه زبانهای اعلام شده در فروشگاهها مجموعه کاملی از ترجمهها را دارند.
سوالات متداول
i18n (بینالمللیسازی) — آمادهسازی کد: خارجسازی رشتهها، پشتیبانی RTL، قالببندی. یک بار توسط توسعهدهنده انجام میشود. l10n (بومیسازی) — ترجمه رشتهها به زبان خاص.多次 توسط مترجم برای هر زبان انجام میشود. i18n — معماری، l10n — محتوا. بدون i18n بومیسازی اصولاً غیرممکن است.
NSLocalizedString — ماکرویی که مقدار را بر اساس کلید در Localizable.strings برای locale فعلی دستگاه جستجو میکند. اگر ترجمه پیدا شود — آن را برمیگرداند. اگر نه — کلید را برمیگرداند. فرمت: NSLocalizedString(«key»، comment: «توضیح»). برای قالببندی با پارامترها از String.localizedStringWithFormat() استفاده کنید.
strings.xml — فایل با ترجمهها در دایرکتوری res/values/{lang}/. نسخه پایه در values/strings.xml، ترجمهها — در values-ru/strings.xml. کد از طریق getString(R.string.key) دسترسی پیدا میکند. Android خود فایل مناسب را بر اساس زبان سیستم انتخاب میکند. برای جمعبندی از منبع <plurals> با مشخصکنندههای zero/one/few/many/other استفاده میشود.
RTL (Right-to-Left) — جهت نوشتار برای عربی، عبری، اردو، فارسی. Android: supportsRtl="true" در مانیفست، android:layoutDirection، Gravity.START/END. iOS: UISemanticContentAttribute.forceLeftToRight برای RTL اجباری. Layout باید به صورت آینهای منعکس شود: منو در راست، متن — از راست به چپ، آیکونهای ناوبری — برعکس.
برای انتشار جهانی حداقل مجموعه: انگلیسی، اسپانیایی، فرانسوی، آلمانی، ژاپنی، چینی، کرهای، پرتغالی، روسی، ایتالیایی. App Store حداقل بومیسازی انگلیسی را الزامی میکند. هر بومیسازی اضافی مخاطب بالقوه را افزایش میدهد. برای بازار محلی 1–2 زبان کافی است.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید