Locale — to klasa Foundation w iOS i macOS, która hermetyzuje lingwistyczne i kulturowe konwencje użytkownika: format dat, liczb, walut i jednostek miar. Według Apple Developer Documentation, 2024, Locale określa, jak DateFormatter wyświetla miesiąc (styczeń lub January), separator dziesiętny w liczbie (przecinek lub kropka) oraz symbol waluty (złoty, dolar lub euro). Każda instancja Locale jest powiązana z identyfikatorem typu ru_RU lub en_US, gdzie pierwsza część to kod języka (ISO 639-1), a druga to kod regionu (ISO 3166-1). W przeciwieństwie do TimeZone, Locale nie wpływa na absolutną wartość czasu, tylko na jego reprezentację tekstową.
Najważniejsze
Locale — to value-typ w Swift (NSLocale w Objective-C), reprezentujący zestaw reguł formatowania charakterystycznych dla konkretnego języka i regionu. W przeciwieństwie do TimeZone, który określa absolutne przesunięcie czasu, Locale określa, jak czas, liczby i waluta wyglądają w reprezentacji tekstowej. Ta sama data 2024-07-21 zostanie wyświetlona jako „21 lipca 2024 r.„ dla ru_RU i „July 21, 2024„ dla en_US.
Każda instancja Locale składa się z dwóch komponentów: Language (język — określa nazwy miesięcy, dni tygodnia, kolejność słów) i Region (region — określa format liczb, walutę, kalendarz). Kombinacja tych komponentów jest kodowana w identyfikatorze według standardu BCP 47: ru_RU (język rosyjski, Rosja), en_US (angielski, USA), de_DE (niemiecki, Niemcy).
Według Unicode CLDR (2024), lista obsługiwanych lokalizacji w iOS przekracza 700 kombinacji język-region. Foundation wykorzystuje dane z CLDR (Common Locale Data Repository) — najpełniejszego repozytorium danych lokalizacyjnych, wspieranego przez Unicode Consortium. Gwarantuje to jednolitość formatowania na wszystkich urządzeniach Apple.
DateFormatter używa Locale do wyboru prawidłowych nazw miesięcy i dni tygodnia, określenia kolejności komponentów daty (dzień/miesiąc/rok lub miesiąc/dzień/rok) oraz separatorów. Bez jawnego określenia Locale DateFormatter używa lokalizacji urządzenia — jest to poprawne dla UI, ale niebezpieczne dla danych serwerowych, gdzie format musi być stały.
| Komponent | ru_RU | en_US | de_DE |
|---|---|---|---|
| Data (medium) | 21 lipca 2024 r. | Jul 21, 2024 | 21.07.2024 |
| Liczba (1000.5) | 1 000,5 | 1,000.5 | 1.000,5 |
| Waluta (100) | 100,00 ₽ | $100.00 | 100,00 € |
| Kalendarz | Gregoriański | Gregoriański | Gregoriański |
| Separator listy | ; | , | ; |
NumberFormatter używa Locale do określenia separatora dziesiętnego (przecinek lub kropka), separatora grupującego (spacja, przecinek, kropka) i symbolu waluty. Ignorowanie Locale podczas parsowania liczb — jedna z częstych przyczyn błędów w aplikacjach międzynarodowych: liczba „1,5„ oznacza „półtora„ dla ru_RU, ale dla en_US analizator cyfrowy odczyta ją jako „pięć„ po przecinku.
Ważne: Calendar utworzony przez Calendar.current dziedziczy lokalizację urządzenia. Calendar(identifier: .gregorian) z jawnie ustawioną locale — zalecany sposób dla przewidywalnego formatowania. Podczas pracy z datami ISO 8601 zawsze używaj Locale(identifier: "en_US_POSIX") — specjalnej lokalizacji do formatowania technicznego, niepodlegającej wpływom ustawień regionalnych.
Identyfikator Locale składa się z kodu języka (ISO 639-1, dwa znaki) i kodu regionu (ISO 3166-1, dwa znaki), rozdzielonych podkreślnikiem. Przykłady: ru_RU, en_US, fr_FR, zh_Hans_CN (chiński, uproszczone pismo, Chiny). Foundation obsługuje również identyfikatory w formacie BCP 47: ru-RU, en-US, używane w standardach internetowych.
Oprócz pełnych identyfikatorów, Locale można utworzyć tylko na podstawie języka: Locale(identifier: "ru") zwróci lokalizację z językiem rosyjskim i domyślnym regionem dla tego języka (zwykle Rosja). Podobnie dla angielskiego: Locale(identifier: "en") używa regionu USA. Takie podejście jest przydatne do ustawienia języka formatowania bez wiązania z konkretnym regionem.
Specjalne lokalizacje obejmują en_US_POSIX — techniczną lokalizację do maszynowego formatowania dat i liczb, gwarantującą stabilny format niezależnie od ustawień użytkownika. Ta lokalizacja jest obowiązkowa do parsowania dat z API serwerowych, szczególnie dla formatu ISO 8601. Używa kalendarza gregoriańskiego, 24-godzinnego formatu czasu i kropki jako separatora dziesiętnego.
import Foundation
// Dostępne identyfikatory lokalizacji
let available: [String] = Locale.availableIdentifiers
print("Łączna liczba lokalizacji: \(available.count)")
// Filtruj rosyjskie lokalizacje
let russianLocales = available.filter { $0.hasPrefix("ru") }
print("Rosyjskie lokalizacje: \(russianLocales)")
// Składniki lokalizacji
let locale = Locale(identifier: "de_DE")
print("Język: \(locale.languageCode ?? "nil")")
print("Region: \(locale.regionCode ?? "nil")")
print("Waluta: \(locale.currencyCode ?? "nil")")
print("Kalendarz: \(locale.calendar.identifier)")
Sprawdzanie dostępnych lokalizacji przez Locale.availableIdentifiers zwraca tablicę wszystkich identyfikatorów obsługiwanych przez bieżącą wersję iOS. Do filtrowania według regionu użyj Locale.availableIdentifiers.filter z sprawdzeniem regionCode. Jest to przydatne do budowania UI wyboru regionu bez sztywno zakodowanej listy.
Locale.current — podstawowy sposób uzyskania bieżącej lokalizacji urządzenia, ustawionej przez użytkownika w ustawieniach iOS (Settings > General > Language & Region). Ta właściwość automatycznie aktualizuje się przy zmianie języka lub regionu w ustawieniach bez restartu aplikacji. Może jednak nie pokrywać się z lokalizacją preferowaną do wyświetlania treści: użytkownik może ustawić język interfejsu na angielski, ale przeglądać daty w formacie rosyjskim.
Do dokładniejszego określenia preferencji użytkownika użyj Locale.preferredLanguages — tablicy języków uporządkowanych według priorytetu użytkownika. Pierwszy element to główny język interfejsu. Ta lista odpowiada ustawieniom w Language & Region, w tym przeciąganiu języków w kolejności preferencji. Aplikacje komunikacyjne (komunikatory, klienty email) powinny uwzględniać tę kolejność przy wyborze języka wyświetlania treści.
import Foundation
// Bieżąca lokalizacja systemowa
let current = Locale.current
print("Bieżąca lokalizacja: \(current.identifier)")
print("Język: \(current.language?.disjointName ?? "nil")")
// Preferowane języki użytkownika
let preferred = Locale.preferredLanguages
print("Preferowane języki: \(preferred)")
// Pobierz region z bieżącej lokalizacji
if let region = current.regionCode {
let regionLocale = Locale(identifier: "en_\(region)")
let countryName = regionLocale.localizedString(
forRegionCode: region
)
print("Kraj: \(countryName ?? region)")
}
// Sprawdź format 24h
let uses24h = current.uses24hClock(
for: .dateAndTime
)
print("Używa 24h: \(uses24h)")
Lokalizacja w UI: do wyświetlania nazw miesięcy i dni tygodnia w języku interfejsu użyj Calendar z ustawioną locale. Calendar.current.symbols(for: .month) zwróci nazwy miesięcy w języku bieżącej lokalizacji. Do wyświetlania nazw krajów w języku użytkownika użyj Locale.current.localizedString(forRegionCode:).
Formatowanie daty z uwzględnieniem lokalizacji — kluczowe zadanie przy wyświetlaniu dat użytkownikowi. DateFormatter z ustawioną locale automatycznie wybiera prawidłowy format daty i czasu dla regionu użytkownika. Dla dateStyle i timeStyle z wartościami .short, .medium, .long, .full formatter używa reguł lokalizacji do komponowania składników daty.
import Foundation
let date = Date()
// Formatowanie z różnymi lokalizacjami
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.locale = Locale(identifier: "ru_RU")
print("Rosyjski: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "en_US")
print("Angielski: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "ja_JP")
print("Japoński: \(formatter.string(from: date))")
// Formatowanie walut z lokalizacją
let numFormatter = NumberFormatter()
numFormatter.numberStyle = .currency
numFormatter.locale = Locale(identifier: "de_DE")
print("Waluta niemiecka: \(numFormatter.string(from: 1234.56) ?? "nil")")
numFormatter.locale = Locale(identifier: "en_US")
print("Waluta amerykańska: \(numFormatter.string(from: 1234.56) ?? "nil")")
Parsowanie dat z API serwerowych zawsze powinno używać Locale(identifier: "en_US_POSIX") dla stałego formatu. Serwery zazwyczaj wysyłają daty w formacie ISO 8601 z angielskimi nazwami miesięcy, a użycie bieżącej lokalizacji urządzenia może prowadzić do błędu parsowania, jeśli użytkownik znajduje się w regionie z nieangielskim językiem. en_US_POSIX gwarantuje, że parsowanie nie zależy od ustawień urządzenia.
import Foundation
// Poprawne parsowanie dat serwerowych
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("Data po parsowaniu: \(parsed)")
}
// Zlokalizowana nazwa waluty
let usLocale = Locale(identifier: "en_US")
let currencyName = usLocale.localizedString(
forCurrencyCode: "RUB"
)
print("Rubel rosyjski w lokalizacji amerykańskiej: \(currencyName ?? "nil")")
Dodatkowe możliwości: Locale udostępnia lokalizowany opis swoich komponentów poprzez metody localizedString(forRegionCode:), localizedString(forLanguageCode:), localizedString(forCurrencyCode:) i localizedString(forCalendarIdentifier:). Te metody zwracają nazwy w języku tej lokalizacji, w której zostały wywołane. Na przykład Locale(identifier: "ru_RU").localizedString(forCountryCode: "DE") zwróci „Niemcy„.
Ignorowanie Locale podczas parsowania liczb — krytyczny błąd w aplikacjach międzynarodowych. NumberFormatter bez jawnej lokalizacji używa bieżącej lokalizacji urządzenia. Jeśli użytkownik w Rosji wprowadza „1,5„, NumberFormatter.number(from: "1,5") poprawnie zwróci 1.5. Ale jeśli ten sam kod jest wykonywany na urządzeniu z lokalizacją en_US, parsowanie zwróci nil, ponieważ dla en_US separatorem dziesiętnym jest kropka.
Brak en_US_POSIX dla dat serwerowych prowadzi do trudnych do wykrycia błędów. DateFormatter z dateFormat i locale = Locale.current może się zepsuć u użytkowników z regionów, gdzie format daty różni się od amerykańskiego. Na przykład w Niemczech DateFormatter może oczekiwać „21.07.2024„, a serwer przysyła „07/21/2024„. en_US_POSIX gwarantuje stały format dla maszynowego parsowania niezależnie od regionu użytkownika.
Porównywanie tekstowych reprezentacji dat zamiast używania Date — kolejny częsty błąd. Programiści czasami porównują tekstowe reprezentacje dat z różnych lokalizacji, otrzymując nieprawidłowe wyniki. Locale zmienia tylko wyświetlanie, ale nie absolutną wartość daty. Zawsze porównuj obiekty Date, a nie ich reprezentacje tekstowe. Do porównywania składników daty używaj Calendar z jawnie ustawioną locale.
Według WWDC 2023, około 30% problemów z internacjonalizacją w aplikacjach jest związanych z nieprawidłową konfiguracją Locale. Apple zaleca zawsze jawne ustawianie locale dla DateFormatter i NumberFormatter podczas pracy z danymi serwerowymi i używanie Locale.current tylko przy wyświetlaniu w UI. Ta prosta praktyka eliminuje większość błędów związanych z ustawieniami regionalnymi.
Często zadawane pytania
Locale — klasa Foundation reprezentująca kulturowe i lingwistyczne reguły formatowania: format daty, liczb, waluty i jednostek miar. Używana razem z DateFormatter, NumberFormatter i Calendar do lokalizowanego wyświetlania danych.
Locale określa format wyświetlania (język, konwencje regionalne), a TimeZone — absolutne przesunięcie czasu względem UTC. Locale wpływa na reprezentację tekstową, TimeZone — na numeryczną wartość czasu. Oba są używane razem do pełnego formatowania daty.
en_US_POSIX — specjalna lokalizacja do formatowania technicznego, gwarantująca stabilny format niezależnie od ustawień użytkownika. Obowiązkowa do parsowania dat serwerowych (ISO 8601) i pracy z API, gdzie format musi być przewidywalny.
Locale.availableIdentifiers zwraca tablicę ciągów z identyfikatorami wszystkich obsługiwanych lokalizacji. Do filtrowania według języka użyj filter z hasPrefix, a do uzyskania regionu — Locale(identifier:).regionCode.
NumberFormatter używa Locale do określenia separatora dziesiętnego (przecinek lub kropka), symbolu waluty i separatora grupującego. Dla stałego formatu ustawiaj locale na en_US_POSIX lub jawnie określaj właściwości formattera.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również