Internacionalização no iOS com SwiftUI: Localizable.strings, pluralização e formatação

Capítulo 12

Tempo estimado de leitura: 9 minutos

+ Exercício

O que é internacionalização (i18n) e localização (l10n) no iOS

Internacionalização (i18n) é preparar o app para suportar múltiplos idiomas e formatos regionais sem reescrever telas. Localização (l10n) é fornecer os textos (e, quando necessário, regras) para cada idioma/região.

No iOS, o idioma e a região do usuário influenciam:

  • Textos exibidos (traduções)
  • Pluralização (1 item vs 2 itens)
  • Formatação de datas e horas
  • Separadores decimais e de milhar
  • Moeda e símbolo monetário

Em SwiftUI, você pode usar chaves de localização diretamente em Text e deixar o sistema escolher a tradução correta com base nas configurações do dispositivo/simulador.

Estrutura de arquivos: como o iOS organiza localizações

O padrão mais comum é usar arquivos Localizable.strings (um por idioma). No Xcode, isso é feito marcando o arquivo como Localized, e o projeto cria variações por idioma (por exemplo, pt-BR e en).

Boas práticas de organização

  • Use chaves estáveis (não use o texto como chave). Ex.: home.title, cart.items_count.
  • Agrupe por tela/feature via prefixos: settings., profile., checkout..
  • Evite concatenar strings manualmente (isso quebra gramática em outros idiomas). Prefira strings com variáveis.

Passo a passo: adicionando Português e Inglês com Localizable.strings

1) Adicionar idiomas ao projeto

No Xcode:

Continue em nosso aplicativo e ...
  • Ouça o áudio com a tela desligada
  • Ganhe Certificado após a conclusão
  • + de 5000 cursos para você explorar!
ou continue lendo abaixo...
Download App

Baixar o aplicativo

  • Selecione o projeto (ícone azul) > PROJECT > Info
  • Em Localizations, clique em + e adicione Portuguese (Brazil) (pt-BR) e English (en)

2) Criar o arquivo Localizable.strings

No Xcode:

  • File > New > File... > Strings File
  • Nomeie como Localizable.strings
  • Selecione o arquivo > no painel da direita (File Inspector) marque Localize...
  • Escolha um idioma base (geralmente English) e confirme
  • Marque também a localização para Portuguese (Brazil)

3) Preencher as chaves em cada idioma

Exemplo de conteúdo para Localizable.strings (English):

"home.title" = "Home";"home.welcome" = "Welcome, %@!";"home.last_update" = "Last update: %@";"cart.title" = "Cart";"currency.example" = "Total: %@";

Exemplo de conteúdo para Localizable.strings (Portuguese (Brazil)):

"home.title" = "Início";"home.welcome" = "Bem-vindo(a), %@!";"home.last_update" = "Última atualização: %@";"cart.title" = "Carrinho";"currency.example" = "Total: %@";

Repare no uso de %@ para inserir valores (strings) dentro do texto. Isso evita concatenação e permite que cada idioma reorganize a frase.

Usando chaves localizáveis em SwiftUI

Text com chave direta

Quando você passa uma string literal para Text, o SwiftUI trata como LocalizedStringKey por padrão, então ele busca a chave no Localizable.strings:

Text("home.title")

Quando a chave é dinâmica (String variável)

Se a chave vem de uma variável String, o SwiftUI não consegue inferir como chave localizável automaticamente. Use:

let key = "home.title"Text(LocalizedStringKey(key))

Use isso com cuidado: chaves dinâmicas dificultam manutenção e revisão de traduções.

Strings com variáveis: interpolação localizável

Para inserir valores em textos localizados, você tem duas abordagens comuns:

1) Usar String(localized:) (recomendado para controle e testes)

Você gera uma String já localizada e passa para o Text:

let userName = "Ana"let message = String(localized: "home.welcome", arguments: [userName])Text(message)

Isso usa o formato do Localizable.strings com %@.

2) Usar interpolação em Text com chave

Em muitos casos, você pode usar interpolação diretamente:

let userName = "Ana"Text("home.welcome \(userName)")

Essa forma é prática, mas pode ficar limitada quando você precisa de formatações específicas (número, moeda, data) ou quando quer garantir que a frase inteira seja controlada por arquivo de localização.

Pluralização no iOS: .stringsdict

Pluralização não deve ser feita com if count == 1 e duas strings separadas, porque alguns idiomas têm mais de duas formas de plural. O iOS oferece .stringsdict para regras de plural.

Passo a passo: criando um Localizable.stringsdict

  • File > New > File... > procure por Strings Dictionary File
  • Nomeie como Localizable.stringsdict
  • Localize o arquivo (como fez com o Localizable.strings) para en e pt-BR

Exemplo de plural para itens no carrinho

Localizable.stringsdict (English) (estrutura XML):

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict>  <key>cart.items_count</key>  <dict>    <key>NSStringLocalizedFormatKey</key>    <string>%#@items@</string>    <key>items</key>    <dict>      <key>NSStringFormatSpecTypeKey</key>      <string>NSStringPluralRuleType</string>      <key>NSStringFormatValueTypeKey</key>      <string>d</string>      <key>one</key>      <string>%d item</string>      <key>other</key>      <string>%d items</string>    </dict>  </dict></dict></plist>

Localizable.stringsdict (Portuguese (Brazil)):

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict>  <key>cart.items_count</key>  <dict>    <key>NSStringLocalizedFormatKey</key>    <string>%#@items@</string>    <key>items</key>    <dict>      <key>NSStringFormatSpecTypeKey</key>      <string>NSStringPluralRuleType</string>      <key>NSStringFormatValueTypeKey</key>      <string>d</string>      <key>one</key>      <string>%d item</string>      <key>other</key>      <string>%d itens</string>    </dict>  </dict></dict></plist>

Agora, para usar essa chave com um número:

let count = 1let text = String(localized: "cart.items_count", arguments: [count])Text(text)

Troque count para 2 e valide a forma plural automaticamente.

Formatação respeitando Locale: datas, números e moeda

Mesmo com o app em inglês, um usuário pode estar com região Brasil, e vice-versa. Por isso, formatação deve respeitar Locale (região) e não apenas idioma.

Datas: usando Date.FormatStyle

Em SwiftUI/Swift moderno, prefira Date.FormatStyle:

let date = Date()Text(date, format: .dateTime.day().month().year().hour().minute())

Esse formato se adapta ao padrão do usuário. Para forçar um locale específico (útil em debug), você pode aplicar:

let date = Date()Text(date.formatted(.dateTime.day().month().year().locale(Locale(identifier: "pt_BR"))))

Números: separadores e casas decimais

Use FormatStyle para números:

let rating = 4.75Text(rating, format: .number.precision(.fractionLength(2)))

Em pt-BR, tende a aparecer com vírgula (ex.: 4,75). Em en-US, com ponto (4.75), dependendo da região.

Moeda: símbolo e padrão local

Para moeda, use .currency com o código ISO:

let total = 1234.5Text(total, format: .currency(code: "BRL"))

Se você quer que a moeda acompanhe a região do usuário, você precisa decidir a regra do seu app (por exemplo, sempre BRL para um app brasileiro, ou moeda configurável). Para exibir com a moeda da região atual, você pode obter o código:

let total = 1234.5let currencyCode = Locale.current.currency?.identifier ?? "USD"Text(total, format: .currency(code: currencyCode))

Exercício: aplicar Português e Inglês no app do curso e validar no simulador

Neste exercício, você vai criar uma tela simples (ou adaptar uma existente) para provar: (1) textos localizados, (2) pluralização, (3) data e moeda formatadas por região.

1) Adicionar chaves necessárias

No Localizable.strings de cada idioma, garanta estas chaves:

Chaveenpt-BR
home.titleHomeInício
home.welcomeWelcome, %@!Bem-vindo(a), %@!
home.last_updateLast update: %@Última atualização: %@
currency.exampleTotal: %@Total: %@

No Localizable.stringsdict, garanta a chave cart.items_count para en e pt-BR (como mostrado acima).

2) Criar uma view de teste de localização

Crie uma view (por exemplo, LocalizationDemoView) e apresente os elementos:

import SwiftUIstruct LocalizationDemoView: View {    @State private var itemCount: Int = 1    private let userName = "Ana"    private let lastUpdate = Date()    private let total: Double = 1234.5    var body: some View {        VStack(alignment: .leading, spacing: 16) {            Text("home.title")                .font(.title.bold())            Text(String(localized: "home.welcome", arguments: [userName]))            Text(String(localized: "cart.items_count", arguments: [itemCount]))            Stepper("Itens: \(itemCount)", value: $itemCount, in: 0...20)            Divider()            let formattedDate = lastUpdate.formatted(.dateTime.day().month().year().hour().minute())            Text(String(localized: "home.last_update", arguments: [formattedDate]))            let currencyCode = Locale.current.currency?.identifier ?? "USD"            let formattedMoney = total.formatted(.currency(code: currencyCode))            Text(String(localized: "currency.example", arguments: [formattedMoney]))        }        .padding()    }}

O Stepper aqui serve para você alternar rapidamente entre 0, 1, 2, 3... e observar a pluralização.

3) Inserir a tela no fluxo do app

Sem alterar sua arquitetura, você pode apresentar essa view em um ponto do app usado no curso (por exemplo, como uma tela acessível via navegação). O importante é conseguir rodar e testar no simulador.

4) Validar idioma e região no simulador

Você vai validar duas coisas: (a) idioma (tradução) e (b) região (formatação).

Opção A: mudar idioma e região do próprio simulador

  • No simulador: Settings > General > Language & Region
  • Altere iPhone Language para English e depois para Português
  • Altere Region (por exemplo, United States vs Brazil) e observe data, número e moeda
  • Feche e reabra o app se necessário para refletir mudanças

Opção B: forçar idioma/região apenas para o app (mais rápido para testar)

No Xcode: Product > Scheme > Edit Scheme... > Run > Options:

  • Em Application Language, selecione English e depois Portuguese
  • Em Application Region, selecione United States e depois Brazil

Validações esperadas:

  • Textos: home.title muda entre “Home” e “Início”.
  • Plural: com itemCount = 1 aparece “1 item”; com itemCount = 2 aparece “2 items” (en) / “2 itens” (pt-BR).
  • Data: ordem e separadores mudam conforme a região.
  • Moeda: símbolo e formatação mudam conforme Locale.current (se você usou o código da moeda da região atual).

Erros comuns e como evitar

Chave não encontrada

Se a chave não existir no arquivo do idioma atual, o iOS pode exibir a própria chave. Verifique:

  • Se o arquivo está realmente localizado para aquele idioma
  • Se a chave é idêntica (maiúsculas/minúsculas contam)
  • Se você editou o arquivo correto (en vs pt-BR)

Concatenar strings quebra tradução

Evite:

Text("Hello, " + userName)

Prefira uma frase inteira com variável:

Text(String(localized: "home.welcome", arguments: [userName]))

Pluralização feita na mão

Evite manter duas chaves (singular/plural) e escolher com if. Use .stringsdict para ficar correto em mais idiomas.

Formatar moeda/data manualmente

Evite montar data com "\(day)/\(month)/\(year)" ou moeda com "R$ \(value)". Use FormatStyle para respeitar Locale.

Agora responda o exercício sobre o conteúdo:

Ao precisar exibir a quantidade de itens no carrinho em diferentes idiomas, qual abordagem é a mais adequada para lidar corretamente com pluralização no iOS?

Você acertou! Parabéns, agora siga para a próxima página

Você errou! Tente novamente.

A pluralização varia entre idiomas e pode ter mais de duas formas. Usar Localizable.stringsdict permite que o sistema aplique a regra correta para cada Locale, evitando l3gica manual e concatenao.

Próximo capitúlo

Testes básicos em iOS com SwiftUI: XCTest, testes de unidade e UI tests essenciais

Arrow Right Icon
Capa do Ebook gratuito iOS para Iniciantes com SwiftUI: do zero ao primeiro app na App Store
86%

iOS para Iniciantes com SwiftUI: do zero ao primeiro app na App Store

Novo curso

14 páginas

Baixe o app para ganhar Certificação grátis e ouvir os cursos em background, mesmo com a tela desligada.