Locale — یک کلاس Foundation در iOS و macOS است که قراردادهای زبانی و فرهنگی کاربر را کپسوله میکند: قالب تاریخها، اعداد، ارزها و واحدهای اندازهگیری. طبق Apple Developer Documentation, 2024، Locale تعیین میکند که DateFormatter چگونه ماه را نمایش میدهد (ژانویه یا January)، جداکننده دهم در عدد (کاما یا نقطه) و نماد ارز (ریال، دلار یا یورو). هر نمونه Locale به شناسهای مانند ru_RU یا en_US متصل است، که بخش اول کد زبان (ISO 639-1) و بخش دوم کد منطقه (ISO 3166-1) است. برخلاف TimeZone، Locale بر مقدار مطلق زمان تأثیر نمیگذارد، فقط بر نمایش رشتهای آن تأثیر میگذارد.
نکات اصلی
Locale — یک value-type در Swift (NSLocale در Objective-C) است که مجموعهای از قوانین قالببندی مشخص برای یک زبان و منطقه خاص را نشان میدهد. برخلاف TimeZone که انحراف مطلق زمان را تعیین میکند، Locale تعیین میکند که زمان، اعداد و ارز در نمایش رشتهای چگونه به نظر برسند. همان تاریخ 2024-07-21 به صورت «21 ژوئیه 2024» برای ru_RU و «July 21, 2024» برای en_US نمایش داده میشود.
هر نمونه Locale از دو مؤلفه تشکیل شده است: Language (زبان — نام ماهها، روزهای هفته، ترتیب کلمات را تعیین میکند) و Region (منطقه — قالب اعداد، ارز، تقویم را تعیین میکند). ترکیب این مؤلفهها در شناسه مطابق استاندارد BCP 47 کدگذاری میشود: ru_RU (زبان روسی، روسیه)، en_US (انگلیسی، ایالات متحده)، de_DE (آلمانی، آلمان).
طبق Unicode CLDR (2024)، لیست زبانهای محلی پشتیبانیشده در iOS بیش از 700 ترکیب زبان-منطقه است. Foundation از دادههای CLDR (Common Locale Data Repository) استفاده میکند — کاملترین مخزن دادههای محلیسازی که توسط Unicode Consortium پشتیبانی میشود. این یکپارچگی قالببندی را در تمام دستگاههای Apple تضمین میکند.
DateFormatter از Locale برای انتخاب نامهای صحیح ماهها و روزهای هفته، تعیین ترتیب اجزای تاریخ (روز/ماه/سال یا ماه/روز/سال) و جداکنندهها استفاده میکند. بدون تعیین صریح Locale، DateFormatter از محل دستگاه استفاده میکند — این برای UI صحیح است، اما برای دادههای سرور که قالب باید ثابت باشد خطرناک است.
| مؤلفه | ru_RU | en_US | de_DE |
|---|---|---|---|
| تاریخ (medium) | 21 ژوئیه 2024 | Jul 21, 2024 | 21.07.2024 |
| عدد (1000.5) | 1 000,5 | 1,000.5 | 1.000,5 |
| ارز (100) | 100,00 ₽ | $100.00 | 100,00 € |
| تقویم | میلادی | میلادی | میلادی |
| جداکننده لیست | ; | , | ; |
NumberFormatter از Locale برای تعیین جداکننده اعشاری (کاما یا نقطه)، جداکننده گروهبندی (فاصله، کاما، نقطه) و نماد ارز استفاده میکند. نادیده گرفتن Locale هنگام تجزیه اعداد یکی از دلایل رایج باگها در برنامههای بینالمللی است: عدد «1,5» برای ru_RU به معنای «یک و نیم» است، اما برای en_US تحلیلگر عددی آن را به عنوان «پنج» پس از کاملا میخواند.
مهم: Calendar ایجاد شده از طریق Calendar.current محل دستگاه را به ارث میبرد. Calendar(identifier: .gregorian) با locale به صراحت تعیین شده — روش توصیه شده برای قالببندی قابل پیشبینی. هنگام کار با تاریخهای ISO 8601 همیشه از Locale(identifier: "en_US_POSIX") استفاده کنید — یک محل ویژه برای قالببندی فنی که تحت تأثیر تنظیمات منطقهای قرار نمیگیرد.
شناسه Locale از کد زبان (ISO 639-1، دو کاراکتر) و کد منطقه (ISO 3166-1، دو کاراکتر) تشکیل شده است که با زیرخط از هم جدا شدهاند. مثالها: ru_RU، en_US، fr_FR، zh_Hans_CN (چینی، نوشتار سادهشده، چین). Foundation همچنین شناسههایی به فرمت BCP 47 را پشتیبانی میکند: ru-RU، en-US که در استانداردهای وب استفاده میشوند.
علاوه بر شناسههای کامل، Locale را میتوان فقط بر اساس زبان ایجاد کرد: Locale(identifier: "ru") یک محل با زبان روسی و منطقه پیشفرض برای این زبان (معمولاً روسیه) برمیگرداند. به طور مشابه برای انگلیسی: Locale(identifier: "en") از منطقه ایالات متحده استفاده میکند. این رویکرد برای تنظیم زبان قالببندی بدون وابستگی به منطقه خاص مفید است.
زبانهای محلی ویژه شامل en_US_POSIX — یک محل فنی برای قالببندی ماشینی تاریخ و اعداد است که قالب ثابتی را بدون توجه به تنظیمات کاربر تضمین میکند. این محل برای تجزیه تاریخهای API سرور، به ویژه برای فرمت ISO 8601 اجباری است. از تقویم میلادی، فرمت 24 ساعته و نقطه به عنوان جداکننده اعشاری استفاده میکند.
import Foundation
// شناسههای محل موجود
let available: [String] = Locale.availableIdentifiers
print("کل زبانهای محلی: \(available.count)")
// فیلتر زبانهای محلی روسی
let russianLocales = available.filter { $0.hasPrefix("ru") }
print("زبانهای محلی روسی: \(russianLocales)")
// اجزای محل
let locale = Locale(identifier: "de_DE")
print("زبان: \(locale.languageCode ?? "nil")")
print("منطقه: \(locale.regionCode ?? "nil")")
print("ارز: \(locale.currencyCode ?? "nil")")
print("تقویم: \(locale.calendar.identifier)")
بررسی زبانهای محلی موجود از طریق Locale.availableIdentifiers آرایهای از تمام شناسههای پشتیبانیشده توسط نسخه فعلی iOS را برمیگرداند. برای فیلتر بر اساس منطقه از Locale.availableIdentifiers.filter با بررسی regionCode استفاده کنید. این برای ساخت UI انتخاب منطقه بدون لیست کدگذاری شده مفید است.
Locale.current — راه اصلی برای دریافت محل فعلی دستگاه که توسط کاربر در تنظیمات iOS (Settings > General > Language & Region) تنظیم شده است. این ویژگی به طور خودکار با تغییر زبان یا منطقه در تنظیمات بدون راهاندازی مجدد برنامه بهروز میشود. با این حال، ممکن است با محل ترجیحی برای نمایش محتوا مطابقت نداشته باشد: کاربر میتواند زبان رابط را انگلیسی قرار دهد اما تاریخها را در قالب روسی مشاهده کند.
برای تعیین دقیقتر ترجیحات کاربر از Locale.preferredLanguages استفاده کنید — آرایهای از زبانها که بر اساس اولویت کاربر مرتب شدهاند. اولین عنصر زبان اصلی رابط است. این لیست با تنظیمات Language & Region مطابقت دارد، از جمله کشیدن و رها کردن زبانها به ترتیب اولویت. برنامههای ارتباطی (پیامرسانها، کلاینتهای ایمیل) باید این ترتیب را هنگام انتخاب زبان نمایش محتوا در نظر بگیرند.
import Foundation
// محل سیستم فعلی
let current = Locale.current
print("محل فعلی: \(current.identifier)")
print("زبان: \(current.language?.disjointName ?? "nil")")
// زبانهای ترجیحی کاربر
let preferred = Locale.preferredLanguages
print("زبانهای ترجیحی: \(preferred)")
// دریافت منطقه از محل فعلی
if let region = current.regionCode {
let regionLocale = Locale(identifier: "en_\(region)")
let countryName = regionLocale.localizedString(
forRegionCode: region
)
print("کشور: \(countryName ?? region)")
}
// بررسی فرمت 24 ساعته
let uses24h = current.uses24hClock(
for: .dateAndTime
)
print("استفاده از 24h: \(uses24h)")
محلیسازی در UI: برای نمایش نام ماهها و روزهای هفته به زبان رابط از Calendar با locale تنظیم شده استفاده کنید. Calendar.current.symbols(for: .month) نام ماهها را به زبان محل فعلی برمیگرداند. برای نمایش نام کشورها به زبان کاربر از Locale.current.localizedString(forRegionCode:) استفاده کنید.
قالببندی تاریخ با در نظر گرفتن محل — وظیفه کلیدی هنگام نمایش تاریخ به کاربر. DateFormatter با locale تنظیم شده به طور خودکار قالب صحیح تاریخ و زمان را برای منطقه کاربر انتخاب میکند. برای dateStyle و timeStyle با مقادیر .short، .medium، .long، .full، قالبدهنده از قوانین محل برای ترکیب اجزای تاریخ استفاده میکند.
import Foundation
let date = Date()
// قالببندی با زبانهای محلی مختلف
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.locale = Locale(identifier: "ru_RU")
print("روسی: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "en_US")
print("انگلیسی: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "ja_JP")
print("ژاپنی: \(formatter.string(from: date))")
// قالببندی ارز با محل
let numFormatter = NumberFormatter()
numFormatter.numberStyle = .currency
numFormatter.locale = Locale(identifier: "de_DE")
print("ارز آلمانی: \(numFormatter.string(from: 1234.56) ?? "nil")")
numFormatter.locale = Locale(identifier: "en_US")
print("ارز آمریکا: \(numFormatter.string(from: 1234.56) ?? "nil")")
تجزیه تاریخ از API سرور همیشه باید از Locale(identifier: "en_US_POSIX") برای قالب ثابت استفاده کند. سرورها معمولاً تاریخها را در فرمت ISO 8601 با نام ماههای انگلیسی ارسال میکنند و استفاده از محل فعلی دستگاه میتواند منجر به خطای تجزیه شود اگر کاربر در منطقهای با زبان غیر انگلیسی باشد. en_US_POSIX تضمین میکند که تجزیه به تنظیمات دستگاه وابسته نیست.
import Foundation
// تجزیه صحیح تاریخ سرور
let isoFormatter = DateFormatter()
isoFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ssZ"
isoFormatter.locale = Locale(identifier: "en_US_POSIX")
isoFormatter.timeZone = TimeZone(secondsFromGMT: 0)
let serverDate = "2024-07-21T14:30:00+0000"
if let parsed = isoFormatter.date(from: serverDate) {
print("تاریخ تجزیه شده: \(parsed)")
}
// نام ارز محلیسازی شده
let usLocale = Locale(identifier: "en_US")
let currencyName = usLocale.localizedString(
forCurrencyCode: "RUB"
)
print("روبل روسیه در محل آمریکا: \(currencyName ?? "nil")")
امکانات اضافی: Locale توضیحات محلیسازی شده اجزای خود را از طریق متدهای localizedString(forRegionCode:)، localizedString(forLanguageCode:)، localizedString(forCurrencyCode:) و localizedString(forCalendarIdentifier:) فراهم میکند. این متدها نامها را به زبان محلی که در آن فراخوانی شدهاند برمیگردانند. به عنوان مثال، Locale(identifier: "ru_RU").localizedString(forCountryCode: "DE") «آلمان» را برمیگرداند.
نادیده گرفتن Locale هنگام تجزیه اعداد — یک خطای بحرانی در برنامههای بینالمللی. NumberFormatter بدون محل صریح از محل فعلی دستگاه استفاده میکند. اگر کاربر در روسیه «1,5» را وارد کند، NumberFormatter.number(from: "1,5") به درستی 1.5 را برمیگرداند. اما اگر همین کد روی دستگاهی با محل en_US اجرا شود، تجزیه nil برمیگرداند زیرا برای en_US جداکننده اعشاری نقطه است.
عدم استفاده از en_US_POSIX برای تاریخهای سرور منجر به باگهای غیرقابل ردیابی میشود. DateFormatter با dateFormat و locale = Locale.current ممکن است برای کاربرانی از مناطقی که قالب تاریخ با آمریکایی متفاوت است خراب شود. به عنوان مثال، در آلمان DateFormatter ممکن است «21.07.2024» را انتظار داشته باشد در حالی که سرور «07/21/2024» را ارسال میکند. en_US_POSIX قالب ثابتی را برای تجزیه ماشینی بدون توجه به منطقه کاربر تضمین میکند.
مقایسه رشتههای تاریخ به جای استفاده از Date — یکی دیگر از خطاهای رایج. توسعهدهندگان گاهی نمایشهای رشتهای تاریخها را از زبانهای محلی مختلف مقایسه میکنند و نتایج نادرست دریافت میکنند. Locale فقط نمایش را تغییر میدهد، نه مقدار مطلق تاریخ را. همیشه اشیاء Date را مقایسه کنید، نه نمایشهای رشتهای آنها را. برای مقایسه اجزای تاریخ از Calendar با locale به صراحت تعیین شده استفاده کنید.
طبق WWDC 2023، حدود 30٪ از مشکلات بینالمللیسازی در برنامهها به تنظیم نادرست Locale مربوط میشود. Apple توصیه میکند همیشه locale را به صراحت برای DateFormatter و NumberFormatter هنگام کار با دادههای سرور تنظیم کنید و از Locale.current فقط برای نمایش در UI استفاده کنید. این روش ساده اکثر باگهای مربوط به تنظیمات منطقهای را برطرف میکند.
سوالات متداول
Locale — کلاس Foundation است که قوانین فرهنگی و زبانی قالببندی را نشان میدهد: قالب تاریخ، اعداد، ارز و واحدهای اندازهگیری. همراه با DateFormatter، NumberFormatter و Calendar برای نمایش محلیسازی شده دادهها استفاده میشود.
Locale قالب نمایش (زبان، قراردادهای منطقهای) را تعیین میکند، در حالی که TimeZone انحراف مطلق زمان نسبت به UTC را تعیین میکند. Locale بر نمایش رشتهای تأثیر میگذارد، TimeZone — بر مقدار عددی زمان. هر دو با هم برای قالببندی کامل تاریخ استفاده میشوند.
en_US_POSIX — یک محل ویژه برای قالببندی فنی است که قالب ثابتی را بدون توجه به تنظیمات کاربر تضمین میکند. برای تجزیه تاریخهای سرور (ISO 8601) و کار با APIهایی که قالب باید قابل پیشبینی باشد اجباری است.
Locale.availableIdentifiers آرایهای از رشتههای شناسه تمام زبانهای محلی پشتیبانیشده را برمیگرداند. برای فیلتر بر اساس زبان از filter با hasPrefix استفاده کنید، برای دریافت منطقه — Locale(identifier:).regionCode.
NumberFormatter از Locale برای تعیین جداکننده اعشاری (کاما یا نقطه)، نماد ارز و جداکننده گروهبندی استفاده میکند. برای قالب ثابت locale را روی en_US_POSIX تنظیم کنید یا ویژگیهای formatter را به صراحت تعیین کنید.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید