Hai fretta? Controlla i placeholder di una traduzione direttamente nel browser: gratis, senza registrazione, niente viene caricato.
Da dove viene il %
In un'app iOS, una stringa localizzata con una variabile diventa una stringa di formato. In SwiftUI succede in modo implicito:
Text("\(count) items left") // key: "%lld items left"
Text("Welcome back, \(name)!") // key: "Welcome back, %@!"
String(localized: "Total: \(price) €") // price is a Double: "Total: %lf €"
Un Int dà %lld, una String dà %@, un Double dà %lf. Con la vecchia API il formato lo scrivi tu: String(format: NSLocalizedString("items_left", comment: ""), count), e il file .strings contiene %d o %ld.
In entrambi i casi, il traduttore riceve un testo con dei segni % in mezzo, ed è lì che le cose si rompono.
Tre modi di rompere una traduzione
Perdere lo specificatore. "Invitez à modifier cette liste" invece di "Invitez %@ à modifier cette liste". Niente va in crash: l'argomento viene semplicemente ignorato e il nome della persona sparisce dallo schermo. È l'errore più comune e il più silenzioso.
Cambiare il tipo. Sostituire %lld con %@, o viceversa. Il formato legge allora l'argomento con il tipo sbagliato: nel migliore dei casi un numero senza senso, nel peggiore un crash, perché %@ si aspetta un oggetto dove riceve un intero.
Cambiare l'ordine in silenzio. "%@ shared %@" diventa, in una lingua con un ordine delle parole diverso, una frase in cui i due nomi sono scambiati. La sintassi è corretta, il significato no.
Riordinare con le posizioni
Per cambiare l'ordine, numera gli argomenti: %1$@ è il primo argomento, %2$@ il secondo, ovunque si trovino nella frase.
/* source */ "%@ shared %@ with you" = "%1$@ shared %2$@ with you";
/* French */ "%@ shared %@ with you" = "%1$@ vous a partagé %2$@";
/* other order */ "%@ shared %@ with you" = "%2$@ : partagé par %1$@";
Una regola da ricordare: in una stringa, o è tutto numerato o niente. Mescolare %1$@ e %@ è un comportamento indefinito.
Una trappola francese: "20 % de remise"
La tipografia francese mette uno spazio prima del segno di percentuale: "20 % de remise" (20% di sconto). In una stringa di formato è un problema, perché % d (percentuale, spazio, d) è uno specificatore valido: lo spazio è un flag printf ("anteponi uno spazio ai numeri positivi") e d la conversione intera. La frase
"Profitez de %lld % de remise"
contiene quindi due specificatori, %lld e % d, per un solo argomento. Il secondo legge un valore che non esiste. La forma corretta raddoppia il segno:
"Profitez de %lld %% de remise"
Riguarda solo le stringhe che passano da un formato, cioè quelle con almeno una variabile. Un "20 % de remise" fisso senza argomenti viene mostrato così com'è. Ma le traduzioni evolvono: il giorno in cui qualcuno aggiunge una variabile a quella frase, il % isolato diventa un bug.
Plurali
Per "1 elemento / 3 elementi", non scrivere due chiavi e un if nel codice. In uno String Catalog, la chiave %lld items left riceve varianti plurali (one, other, più few o many a seconda della lingua), ognuna con il proprio %lld. Quando una frase ha due numeri che variano indipendentemente, Xcode usa le sostituzioni (%#@items@): un caso più raro, da modificare in Xcode.
Controllare prima di pubblicare
Il controllo di base è meccanico: per ogni traduzione, l'elenco degli specificatori (tipo e posizione) deve corrispondere alla sorgente. È quello che fa la QA di LocalePilot sui file .strings e .xcstrings: riconosce %@, %1$@, %d, %ld, %lld, %.2f, %u, %i e %s, tratta %% come testo e segnala uno specificatore mancante o in più prima dell'esportazione. Ignora di proposito le conversioni rare come %e o %x, proprio perché "20%en" non venga preso per un errore. Il caso "% d" visto sopra richiede una revisione umana: cerca nelle traduzioni francesi un % seguito da uno spazio.