Migrar Localizable.strings para um String Catalog (.xcstrings)

Atualizado em · LocalePilot

Desde o Xcode 15, a Apple empurra todo mundo para os String Catalogs: um único arquivo JSON para todos os idiomas, com plurais e variações por dispositivo. A migração leva dois cliques. O diff que vem depois é o que merece sua atenção.

Com pressa? Converta arquivos .strings avulsos em um catálogo direto no navegador: grátis, sem cadastro, nada é enviado.

Antes de migrar

Duas precauções que evitam a maioria das surpresas ruins:

  • Uma árvore Git limpa, em uma branch dedicada. Tudo o que vale conferir depois está no diff, então você quer esse diff isolado.
  • Um build que passa antes da migração. O Xcode preenche o catálogo varrendo seu código durante o build. Se o projeto não compila, o catálogo fica incompleto e você não vai saber por quê.

A migração em si

No navegador do projeto, clique com o botão direito em Localizable.strings e escolha Migrate to String Catalog. O Xcode lista os arquivos e targets envolvidos; o texto exato pode mudar entre versões do Xcode, a ideia não.

Os arquivos fr.lproj/Localizable.strings, de.lproj/Localizable.strings… são substituídos por um único Localizable.xcstrings com todos os idiomas. Os comentários dos arquivos .strings viram o comentário de cada chave.

Como é o arquivo

Um String Catalog é JSON. Uma chave simples:

{
  "sourceLanguage" : "en",
  "strings" : {
    "welcome_user" : {
      "comment" : "Home screen greeting",
      "localizations" : {
        "fr" : {
          "stringUnit" : {
            "state" : "translated",
            "value" : "Bon retour, %@ !"
          }
        }
      }
    }
  },
  "version" : "1.0"
}

E um plural, guardado em variations:

"items_left" : {
  "localizations" : {
    "fr" : {
      "variations" : {
        "plural" : {
          "one" : { "stringUnit" : { "state" : "translated", "value" : "%lld article restant" } },
          "other" : { "stringUnit" : { "state" : "translated", "value" : "%lld articles restants" } }
        }
      }
    }
  }
}

Repare na formatação: um espaço antes de cada dois-pontos, do jeito que o Xcode escreve. Uma ferramenta que regrava o arquivo como JSON "padrão" vai produzir um diff enorme sem mudar uma única tradução.

O que revisar no diff

Chaves marcadas como Stale. Depois de um build, o Xcode marca as chaves que não encontra mais no seu código. Elas não estão necessariamente mortas: uma chave montada em tempo de execução (NSLocalizedString(variable, comment: ""), uma chave lida de um arquivo de configuração) é invisível para a varredura. Confira antes de apagar.

Novas chaves extraídas do código. O build pode adicionar strings que você nunca colocou no Localizable.strings, tipicamente literais Text("…") do SwiftUI, que são localizáveis por padrão. Elas chegam sem tradução, então a porcentagem que o Xcode mostra para cada idioma cai. É o esperado.

Estados. Cada valor tem um estado: translated, needs_review ou new para uma string que ninguém traduziu ainda. Daqui a três meses, é assim que você vai saber o que foi realmente revisado.

Especificadores de formato. Uma string SwiftUI como Text("\(count) items left") gera a chave %lld items left. Se o seu antigo .strings usava %d para a mesma frase, agora você tem duas chaves quase duplicadas; mantenha a que o seu código realmente usa.

E as versões mais antigas do iOS?

Não precisa de iOS 17. O catálogo é um formato de origem: no build, o Xcode o compila em arquivos .strings comuns dentro do bundle do app. Seu deployment target não muda.

Editar o catálogo fora do Xcode

O editor do Xcode serve bem para algumas strings. Para revisar um idioma inteiro, traduzir em lote ou checar placeholders, uma ferramenta dedicada ajuda. O LocalePilot abre arquivos .xcstrings e os grava de volta no estilo do Xcode: um catálogo sem alterações sai idêntico byte a byte, uma edição muda só as próprias linhas, e um valor editado passa para o estado translated. Plurais e variações por dispositivo são editáveis; chaves com substituições (%#@count@) e chaves marcadas com shouldTranslate: false são mantidas como estão, para você editar no Xcode.

Perguntas frequentes

String Catalogs exigem iOS 17?

Não. O Xcode compila o catálogo em arquivos de localização comuns no build; o deployment target do seu app não muda.

O que significa Stale em um String Catalog?

O Xcode não encontrou a chave no seu código no último build. Confirme que ela não é montada em tempo de execução antes de apagá-la.

Como desfazer a migração?

Migre em uma branch dedicada, com um commit logo antes: reverter no Git traz os arquivos .strings de volta.