Locale — je třída Foundation v iOS a macOS, která zapouzdřuje jazykové a kulturní konvence uživatele: formát dat, čísel, měn a jednotek měření. Podle Apple Developer Documentation, 2024 určuje Locale, jak DateFormatter zobrazuje měsíc (leden nebo January), desetinný oddělovač v čísle (čárka nebo tečka) a symbol měny (koruna, dolar nebo euro). Každá instance Locale je vázána na identifikátor typu ru_RU nebo en_US, kde první část je kód jazyka (ISO 639-1) a druhá část je kód regionu (ISO 3166-1). Na rozdíl od TimeZone, Locale neovlivňuje absolutní hodnotu času, pouze jeho textovou reprezentaci.
Hlavní body
Locale — je value-type ve Swift (NSLocale v Objective-C), který představuje soubor pravidel formátování charakteristických pro konkrétní jazyk a region. Na rozdíl od TimeZone, který určuje absolutní posun času, Locale určuje, jak čas, čísla a měna vypadají v textové reprezentaci. Stejné datum 2024-07-21 bude zobrazeno jako „21. července 2024„ pro ru_RU a „July 21, 2024„ pro en_US.
Každá instance Locale se skládá ze dvou komponent: Language (jazyk — určuje názvy měsíců, dnů v týdnu, pořadí slov) a Region (region — určuje formát čísel, měnu, kalendář). Kombinace těchto komponent je kódována v identifikátoru podle standardu BCP 47: ru_RU (ruština, Rusko), en_US (angličtina, USA), de_DE (němčina, Německo).
Podle Unicode CLDR (2024) přesahuje seznam podporovaných lokalizací v iOS 700 kombinací jazyk-region. Foundation používá data z CLDR (Common Locale Data Repository) — nejúplnějšího úložiště lokalizačních dat podporovaného Unicode Consortium. To zaručuje jednotnost formátování na všech zařízeních Apple.
DateFormatter používá Locale pro výběr správných názvů měsíců a dnů v týdnu, určení pořadí komponent data (den/měsíc/rok nebo měsíc/den/rok) a oddělovačů. Bez explicitního určení Locale používá DateFormatter místní nastavení zařízení — to je správné pro UI, ale nebezpečné pro serverová data, kde musí být formát pevný.
| Komponenta | ru_RU | en_US | de_DE |
|---|---|---|---|
| Datum (medium) | 21. července 2024 | Jul 21, 2024 | 21.07.2024 |
| Číslo (1000.5) | 1 000,5 | 1,000.5 | 1.000,5 |
| Měna (100) | 100,00 ₽ | $100.00 | 100,00 € |
| Kalendář | Gregoriánský | Gregoriánský | Gregoriánský |
| Oddělovač seznamu | ; | , | ; |
NumberFormatter používá Locale k určení desetinného oddělovače (čárka nebo tečka), seskupovacího oddělovače (mezera, čárka, tečka) a symbolu měny. Ignorování Locale při parsování čísel je jednou z častých příčin chyb v mezinárodních aplikacích: číslo „1,5„ znamená „jeden a půl„ pro ru_RU, ale pro en_US bude číselný analyzátor číst jako „pět„ za čárkou.
Důležité: Calendar vytvořený přes Calendar.current dědí místní nastavení zařízení. Calendar(identifier: .gregorian) s explicitně nastaveným locale — doporučený způsob pro předvídatelné formátování. Při práci s daty ISO 8601 vždy používejte Locale(identifier: "en_US_POSIX") — speciální místní nastavení pro technické formátování, které nepodléhá vlivu regionálních nastavení.
Identifikátor Locale se skládá z kódu jazyka (ISO 639-1, dva znaky) a kódu regionu (ISO 3166-1, dva znaky), oddělených podtržítkem. Příklady: ru_RU, en_US, fr_FR, zh_Hans_CN (čínština, zjednodušené písmo, Čína). Foundation také podporuje identifikátory ve formátu BCP 47: ru-RU, en-US, používané ve webových standardech.
Kromě úplných identifikátorů lze Locale vytvořit pouze na základě jazyka: Locale(identifier: "ru") vrátí místní nastavení s ruštinou a výchozím regionem pro tento jazyk (obvykle Rusko). Podobně pro angličtinu: Locale(identifier: "en") používá region USA. Tento přístup je užitečný pro nastavení jazyka formátování bez vazby na konkrétní region.
Speciální místní nastavení zahrnují en_US_POSIX — technické místní nastavení pro strojové formátování dat a čísel, které zaručuje stabilní formát nezávisle na uživatelském nastavení. Toto místní nastavení je povinné pro parsování dat z API serverů, zejména pro formát ISO 8601. Používá gregoriánský kalendář, 24hodinový formát času a tečku jako desetinný oddělovač.
import Foundation
// Dostupné identifikátory místních nastavení
let available: [String] = Locale.availableIdentifiers
print("Celkem místních nastavení: \(available.count)")
// Filtrovat ruská místní nastavení
let russianLocales = available.filter { $0.hasPrefix("ru") }
print("Ruská místní nastavení: \(russianLocales)")
// Komponenty místního nastavení
let locale = Locale(identifier: "de_DE")
print("Jazyk: \(locale.languageCode ?? "nil")")
print("Region: \(locale.regionCode ?? "nil")")
print("Měna: \(locale.currencyCode ?? "nil")")
print("Kalendář: \(locale.calendar.identifier)")
Kontrola dostupných místních nastavení přes Locale.availableIdentifiers vrací pole všech identifikátorů podporovaných aktuální verzí iOS. Pro filtrování podle regionu použijte Locale.availableIdentifiers.filter s kontrolou regionCode. To je užitečné pro vytvoření UI výběru regionu bez pevně zakódovaného seznamu.
Locale.current — hlavní způsob získání aktuálního místního nastavení zařízení nastaveného uživatelem v iOS (Settings > General > Language & Region). Tato vlastnost se automaticky aktualizuje při změně jazyka nebo regionu v nastavení bez restartu aplikace. Může se však neshodovat s místním nastavením preferovaným pro zobrazení obsahu: uživatel může nastavit jazyk rozhraní na angličtinu, ale prohlížet data v ruském formátu.
Pro přesnější určení preferencí uživatele použijte Locale.preferredLanguages — pole jazyků seřazených podle priority uživatele. První prvek je hlavní jazyk rozhraní. Tento seznam odpovídá nastavení v Language & Region, včetně přetahování jazyků v pořadí preferencí. Komunikační aplikace (messengery, e-mailoví klienti) by měly tento pořadí zohlednit při výběru jazyka zobrazení obsahu.
import Foundation
// Aktuální systémové místní nastavení
let current = Locale.current
print("Aktuální místní nastavení: \(current.identifier)")
print("Jazyk: \(current.language?.disjointName ?? "nil")")
// Preferované jazyky uživatele
let preferred = Locale.preferredLanguages
print("Preferované jazyky: \(preferred)")
// Získat region z aktuálního místního nastavení
if let region = current.regionCode {
let regionLocale = Locale(identifier: "en_\(region)")
let countryName = regionLocale.localizedString(
forRegionCode: region
)
print("Země: \(countryName ?? region)")
}
// Zkontrolovat 24h formát
let uses24h = current.uses24hClock(
for: .dateAndTime
)
print("Používá 24h: \(uses24h)")
Lokalizace v UI: pro zobrazení názvů měsíců a dnů v týdnu v jazyce rozhraní použijte Calendar s nastaveným locale. Calendar.current.symbols(for: .month) vrátí názvy měsíců v jazyce aktuálního místního nastavení. Pro zobrazení názvů zemí v jazyce uživatele použijte Locale.current.localizedString(forRegionCode:).
Formátování data s ohledem na místní nastavení — klíčový úkol při zobrazování dat uživateli. DateFormatter s nastaveným locale automaticky vybírá správný formát data a času pro region uživatele. Pro dateStyle a timeStyle s hodnotami .short, .medium, .long, .full používá formátovač pravidla místního nastavení pro sestavení komponent data.
import Foundation
let date = Date()
// Formátování s různými místními nastaveními
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.locale = Locale(identifier: "ru_RU")
print("Rusky: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "en_US")
print("Anglicky: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "ja_JP")
print("Japonsky: \(formatter.string(from: date))")
// Formátování měny s místním nastavením
let numFormatter = NumberFormatter()
numFormatter.numberStyle = .currency
numFormatter.locale = Locale(identifier: "de_DE")
print("Německá měna: \(numFormatter.string(from: 1234.56) ?? "nil")")
numFormatter.locale = Locale(identifier: "en_US")
print("Americká měna: \(numFormatter.string(from: 1234.56) ?? "nil")")
Parsování dat z API serverů by mělo vždy používat Locale(identifier: "en_US_POSIX") pro pevný formát. Servery obvykle odesílají data ve formátu ISO 8601 s anglickými názvy měsíců a použití aktuálního místního nastavení zařízení může vést k chybě parsování, pokud je uživatel v regionu s neanglickým jazykem. en_US_POSIX zaručuje, že parsování nezávisí na nastavení zařízení.
import Foundation
// Správné parsování serverových dat
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("Parsované datum: \(parsed)")
}
// Lokalizovaný název měny
let usLocale = Locale(identifier: "en_US")
let currencyName = usLocale.localizedString(
forCurrencyCode: "RUB"
)
print("Ruský rubl v americkém místním nastavení: \(currencyName ?? "nil")")
Další možnosti: Locale poskytuje lokalizovaný popis svých komponent prostřednictvím metod localizedString(forRegionCode:), localizedString(forLanguageCode:), localizedString(forCurrencyCode:) a localizedString(forCalendarIdentifier:). Tyto metody vracejí názvy v jazyce místního nastavení, ve kterém byly volány. Například Locale(identifier: "ru_RU").localizedString(forCountryCode: "DE") vrátí „Německo„.
Ignorování Locale při parsování čísel — kritická chyba v mezinárodních aplikacích. NumberFormatter bez explicitního místního nastavení používá aktuální místní nastavení zařízení. Pokud uživatel v Rusku zadá „1,5„, NumberFormatter.number(from: "1,5") správně vrátí 1.5. Ale pokud je stejný kód spuštěn na zařízení s en_US místním nastavením, parsování vrátí nil, protože pro en_US je desetinný oddělovač tečka.
Chybějící en_US_POSIX pro serverová data vede k obtížně odhalitelným chybám. DateFormatter s dateFormat a locale = Locale.current se může rozbít u uživatelů z regionů, kde se formát data liší od amerického. Například v Německu může DateFormatter očekávat „21.07.2024„, zatímco server posílá „07/21/2024„. en_US_POSIX zaručuje pevný formát pro strojové parsování bez ohledu na region uživatele.
Porovnávání řetězců dat místo použití Date — další častá chyba. Vývojáři někdy porovnávají textové reprezentace dat z různých místních nastavení a získávají nesprávné výsledky. Locale mění pouze zobrazení, nikoli absolutní hodnotu data. Vždy porovnávejte objekty Date, nikoli jejich textové reprezentace. Pro porovnání komponent data použijte Calendar s explicitně nastaveným locale.
Podle WWDC 2023 je přibližně 30 % problémů s internacionalizací v aplikacích spojeno s nesprávnou konfigurací Locale. Apple doporučuje vždy explicitně nastavovat locale pro DateFormatter a NumberFormatter při práci s daty ze serveru a používat Locale.current pouze pro zobrazení v UI. Tato jednoduchá praxe odstraňuje většinu chyb souvisejících s regionálním nastavením.
Často kladené otázky
Locale — třída Foundation představující kulturní a jazyková pravidla formátování: formát data, čísel, měny a jednotek měření. Používá se společně s DateFormatter, NumberFormatter a Calendar pro lokalizované zobrazení dat.
Locale určuje formát zobrazení (jazyk, regionální konvence), zatímco TimeZone určuje absolutní posun času vůči UTC. Locale ovlivňuje textovou reprezentaci, TimeZone — číselnou hodnotu času. Oba se používají společně pro úplné formátování data.
en_US_POSIX — speciální místní nastavení pro technické formátování, které zaručuje stabilní formát nezávisle na uživatelském nastavení. Povinné pro parsování serverových dat (ISO 8601) a práci s API, kde musí být formát předvídatelný.
Locale.availableIdentifiers vrací pole řetězců s identifikátory všech podporovaných místních nastavení. Pro filtrování podle jazyka použijte filter s hasPrefix, pro získání regionu — Locale(identifier:).regionCode.
NumberFormatter používá Locale k určení desetinného oddělovače (čárka nebo tečka), symbolu měny a seskupovacího oddělovače. Pro pevný formát nastavte locale na en_US_POSIX nebo explicitně určete vlastnosti formatteru.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také