Locale é uma classe Foundation em iOS e macOS que encapsula as convenções linguísticas e culturais do usuário: formato de datas, números, moedas e unidades de medida. De acordo com Apple Developer Documentation, 2024, Locale determina como DateFormatter exibe um mês (janeiro ou January), o separador decimal em um número (vírgula ou ponto) e o símbolo da moeda (rublo, dólar ou euro). Cada instância de Locale está vinculada a um identificador como ru_RU ou en_US, onde a primeira parte é o código do idioma (ISO 639-1) e a segunda é o código da região (ISO 3166-1). Ao contrário de TimeZone, Locale não afeta o valor absoluto do tempo, apenas sua representação em string.
Pontos principais
Locale é um tipo de valor em Swift (NSLocale em Objective-C) que representa um conjunto de regras de formatação específicas para um determinado idioma e região. Ao contrário de TimeZone, que determina o deslocamento absoluto do tempo, Locale determina como o tempo, números e moeda aparecem na representação em string. A mesma data 2024-07-21 será exibida como “21 de julho de 2024” para ru_RU e “July 21, 2024” para en_US.
Cada instância de Locale consiste em dois componentes: Idioma (determina nomes de meses, dias da semana, ordem das palavras) e Região (determina formato numérico, moeda, calendário). A combinação desses componentes é codificada em um identificador de acordo com o padrão BCP 47: ru_RU (russo, Rússia), en_US (inglês, EUA), de_DE (alemão, Alemanha).
De acordo com Unicode CLDR (2024), o número de localidades suportadas em iOS excede 700 combinações idioma-região. Foundation usa dados do CLDR (Common Locale Data Repository) — o repositório mais abrangente de dados de localização mantido pelo Unicode Consortium. Isso garante formatação consistente em todos os dispositivos Apple.
DateFormatter usa Locale para selecionar os nomes corretos de meses e dias, determinar a ordem dos componentes da data (dia/mês/ano ou mês/dia/ano) e separadores. Sem especificar explicitamente Locale, DateFormatter usa a localidade do dispositivo — isso é correto para UI, mas perigoso para dados do servidor onde o formato deve ser fixo.
| Componente | ru_RU | en_US | de_DE |
|---|---|---|---|
| Data (medium) | 21 de julho de 2024 | Jul 21, 2024 | 21.07.2024 |
| Número (1000.5) | 1 000,5 | 1,000.5 | 1.000,5 |
| Moeda (100) | 100,00 ₽ | $100.00 | 100,00 € |
| Calendário | Gregoriano | Gregoriano | Gregoriano |
| Separador de lista | ; | , | ; |
NumberFormatter usa Locale para determinar o separador decimal (vírgula ou ponto), o separador de agrupamento (espaço, vírgula, ponto) e o símbolo da moeda. Ignorar Locale ao analisar números é uma das causas comuns de bugs em aplicações internacionais: o número “1,5” significa “um e meio” para ru_RU, mas para en_US o analisador digital o lerá como “cinco” após a vírgula.
Importante: Calendar criado via Calendar.current herda a localidade do dispositivo. Calendar(identifier: .gregorian) com uma localidade explicitamente definida é a abordagem recomendada para formatação previsível. Ao trabalhar com datas ISO 8601, use sempre Locale(identifier: “en_US_POSIX”) — uma localidade especial para formatação técnica que não é afetada pelas configurações regionais.
O identificador de Locale consiste em um código de idioma (ISO 639-1, dois caracteres) e um código de região (ISO 3166-1, dois caracteres), separados por um sublinhado. Exemplos: ru_RU, en_US, fr_FR, zh_Hans_CN (chinês, escrita simplificada, China). Foundation também suporta identificadores no formato BCP 47: ru-RU, en-US, usados em padrões web.
Além dos identificadores completos, Locale pode ser criado apenas pelo idioma: Locale(identifier: “ru”) retorna uma localidade com o idioma russo e a região padrão para esse idioma (geralmente Rússia). Da mesma forma para inglês: Locale(identifier: “en”) usa a região dos EUA. Essa abordagem é útil para definir o idioma de formatação sem vincular a uma região específica.
Localidades especiais incluem en_US_POSIX — uma localidade técnica para formatação automática de datas e números, garantindo um formato estável independentemente das configurações do usuário. Esta localidade é obrigatória para analisar datas de APIs de servidor, especialmente para o formato ISO 8601. Ela usa o calendário gregoriano, formato de 24 horas e ponto como separador decimal.
import Foundation
// Identificadores de localidade disponíveis
let available: [String] = Locale.availableIdentifiers
print("Total de localidades: \(available.count)")
// Filtrar localidades russas
let russianLocales = available.filter { $0.hasPrefix("ru") }
print("Localidades russas: \(russianLocales)")
// Componentes de localidade
let locale = Locale(identifier: "de_DE")
print("Idioma: \(locale.languageCode ?? "nil")")
print("Região: \(locale.regionCode ?? "nil")")
print("Moeda: \(locale.currencyCode ?? "nil")")
print("Calendário: \(locale.calendar.identifier)")
Verificar localidades disponíveis via Locale.availableIdentifiers retorna uma matriz de todos os identificadores suportados pela versão atual do iOS. Para filtrar por região, use Locale.availableIdentifiers.filter com a verificação de regionCode. Isso é útil para construir uma UI de seleção de região sem uma lista codificada.
Locale.current é a principal forma de obter a localidade atual do dispositivo definida pelo usuário nas configurações do iOS (Settings > General > Language & Region). Esta propriedade é atualizada automaticamente ao alterar o idioma ou região nas configurações sem reiniciar a aplicação. No entanto, pode não corresponder à localidade preferida para exibição de conteúdo: um usuário pode definir o idioma da interface como inglês, mas visualizar datas no formato russo.
Para uma determinação mais precisa das preferências do usuário, use Locale.preferredLanguages — uma matriz de idiomas ordenados por prioridade do usuário. O primeiro elemento é o idioma principal da interface. Esta lista corresponde às configurações em Language & Region, incluindo a reorganização de idiomas por ordem de preferência. Aplicações de comunicação (mensageiros, clientes de email) devem considerar esta ordem ao selecionar o idioma de exibição do conteúdo.
import Foundation
// Localidade atual do sistema
let current = Locale.current
print("Localidade atual: \(current.identifier)")
print("Idioma: \(current.language?.disjointName ?? "nil")")
// Idiomas preferidos do usuário
let preferred = Locale.preferredLanguages
print("Idiomas preferidos: \(preferred)")
// Obter região da localidade atual
if let region = current.regionCode {
let regionLocale = Locale(identifier: "en_\(region)")
let countryName = regionLocale.localizedString(
forRegionCode: region
)
print("País: \(countryName ?? region)")
}
// Verificar formato 24h
let uses24h = current.uses24hClock(
for: .dateAndTime
)
print("Usa 24h: \(uses24h)")
Localização na interface do usuário: para exibir nomes de meses e dias no idioma da interface, use Calendar com uma localidade definida. Calendar.current.symbols(for: .month) retorna os nomes dos meses no idioma da localidade atual. Para exibir nomes de países no idioma do usuário, use Locale.current.localizedString(forRegionCode:).
Formatação de data com reconhecimento de localidade é uma tarefa chave ao exibir datas ao usuário. DateFormatter com uma localidade definida seleciona automaticamente o formato correto de data e hora para a região do usuário. Para dateStyle e timeStyle com valores .short, .medium, .long, .full, o formatador usa as regras da localidade para compor os componentes da data.
import Foundation
let date = Date()
// Formato com diferentes localidades
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.locale = Locale(identifier: "ru_RU")
print("Russo: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "en_US")
print("Inglês: \(formatter.string(from: date))")
formatter.locale = Locale(identifier: "ja_JP")
print("Japonês: \(formatter.string(from: date))")
// Formatação de moeda com localidade
let numFormatter = NumberFormatter()
numFormatter.numberStyle = .currency
numFormatter.locale = Locale(identifier: "de_DE")
print("Moeda alemã: \(numFormatter.string(from: 1234.56) ?? "nil")")
numFormatter.locale = Locale(identifier: "en_US")
print("Moeda americana: \(numFormatter.string(from: 1234.56) ?? "nil")")
Análise de datas de APIs de servidor deve sempre usar Locale(identifier: “en_US_POSIX”) para um formato fixo. Os servidores geralmente enviam datas no formato ISO 8601 com nomes de meses em inglês, e usar a localidade atual do dispositivo pode causar erros de análise se o usuário estiver em uma região não inglesa. en_US_POSIX garante que a análise não dependa das configurações do dispositivo.
import Foundation
// Análise correta de data do servidor
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 analisada: \(parsed)")
}
// Nome de moeda localizado
let usLocale = Locale(identifier: "en_US")
let currencyName = usLocale.localizedString(
forCurrencyCode: "RUB"
)
print("Rublo russo em localidade americana: \(currencyName ?? "nil")")
Capacidades adicionais: Locale fornece descrições localizadas de seus componentes através dos métodos localizedString(forRegionCode:), localizedString(forLanguageCode:), localizedString(forCurrencyCode:) e localizedString(forCalendarIdentifier:). Estes métodos retornam nomes no idioma da localidade em que são chamados. Por exemplo, Locale(identifier: “ru_RU”).localizedString(forCountryCode: “DE”) retorna “Alemanha”.
Ignorar Locale ao analisar números é um erro crítico em aplicações internacionais. NumberFormatter sem uma localidade explícita usa a localidade atual do dispositivo. Se um usuário na Rússia inserir “1,5”, NumberFormatter.number(from: “1,5”) retorna corretamente 1.5. Mas se o mesmo código for executado em um dispositivo com localidade en_US, a análise retorna nil porque para en_US o separador decimal é um ponto.
Falta de en_US_POSIX para datas do servidor leva a bugs sutis. DateFormatter com dateFormat e locale = Locale.current pode falhar para usuários de regiões onde o formato de data difere do americano. Por exemplo, na Alemanha DateFormatter pode esperar “21.07.2024” enquanto o servidor envia “07/21/2024”. en_US_POSIX garante um formato fixo para análise automática independentemente da região do usuário.
Comparar strings de data em vez de usar Date é outro erro comum. Desenvolvedores às vezes comparam representações em string de datas de diferentes localidades, obtendo resultados incorretos. Locale apenas altera a exibição, não o valor absoluto da data. Sempre compare objetos Date, não suas representações em string. Para comparar componentes de data, use Calendar com uma localidade explicitamente definida.
De acordo com WWDC 2023, cerca de 30% dos problemas de internacionalização em aplicações estão relacionados à configuração incorreta de Locale. A Apple recomenda sempre definir explicitamente a localidade para DateFormatter e NumberFormatter ao trabalhar com dados do servidor e usar Locale.current apenas para exibição na interface do usuário. Esta prática simples elimina a maioria dos bugs relacionados às configurações regionais.
Perguntas frequentes
Locale é uma classe Foundation que representa regras culturais e linguísticas de formatação: formato de data, número, moeda e unidades de medida. É usada em conjunto com DateFormatter, NumberFormatter e Calendar para exibição localizada de dados.
Locale determina o formato de exibição (idioma, convenções regionais), enquanto TimeZone determina o deslocamento absoluto do tempo em relação ao UTC. Locale afeta a representação em string, TimeZone afeta o valor numérico do tempo. Ambos são usados juntos para formatação completa de data.
en_US_POSIX é uma localidade especial para formatação técnica que garante um formato estável independentemente das configurações do usuário. É obrigatória para analisar datas do servidor (ISO 8601) e trabalhar com APIs onde o formato deve ser previsível.
Locale.availableIdentifiers retorna uma matriz de strings com os identificadores de todas as localidades suportadas. Para filtrar por idioma, use filter com hasPrefix; para obter a região, use Locale(identifier:).regionCode.
NumberFormatter usa Locale para determinar o separador decimal (vírgula ou ponto), o símbolo da moeda e o separador de agrupamento. Para um formato fixo, defina a localidade como en_US_POSIX ou defina explicitamente as propriedades do formatador.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também