Traduction de l’application iOS over-the-air avec des chaînes Phrase

Si vous voulez vous assurer que tous vos utilisateurs d’application obtiennent le bon texte, la fonctionnalité over-the-air de Phrase peut vous aider à publier vos mises à jour de traduction instantanément.

Notre Team d’application n’a pas besoin de compter sur nous, les développeurs (et de prendre notre temps précieux) lors du déploiement de nouvelles traductions dans notre application. Nous pouvons également éviter l’approbation de l’App Store lors de la mise à jour du contenu localisé de notre application. Voyons comment nous pouvons réaliser ces avantages dans notre application iOS grâce à la fonctionnalité over-the-air de Phrase. Nous allons ajouter Phrase over-the-air à une application fonctionnelle, en reliant tout sur la console Phrase et notre projet XCode.

Notre application

Nous reprenons là où nous nous étions arrêtés dans notre précédent article, localisation application iOS avec Phrase. Dans ce tutoriel, nous avons pris une application et l’avons connectée à Phrase pour rationaliser notre flux de travaux de localisation. Nous supposons que vous avez lu cet article, et/ou que vous avez déjà connecté Phrase à votre application. Sinon, nous vous recommandons vivement de consulter cet article avant de continuer.

Application de démonstration | PhraseShort Circuit, notre application de démonstration, une liste de musique électronique

Notre petite application de démonstration liste des morceaux de musique électronique ainsi que leurs artistes et dates de sortie. C’est une application simple à deux écrans avec un UITableViewController qui présente une liste de tous nos morceaux, et dispose d’un écran de détails pour afficher les informations d’un morceau unique.

🔗 Ressource » Si vous souhaitez faire le travail en parallèle, vous pouvez récupérer le Starter projet sur Github. Le projet terminé se trouve près du bas de l’article.

Préparation

D’accord, commençons à préparer notre application pour les traductions over-the-air. Dans notre application iOS, nous allons déplacer nos chaînes localisées des storyboards vers un bon vieux Localizable.strings. Nous ajouterons ensuite le support de traduction over-the-air à notre projet Phrase. Pour compléter notre préparation, nous installerons le SDK iOS de Phrase, qui synchronise les traductions de notre application avec notre projet Phrase over-the-air.

Déplacer les traductions de notre application des Storyboards vers Localizable.strings

Les traductions Phrase over-the-air fonctionneront parfaitement avec les fichiers storyboard .strings. Cependant, pour garder les choses simples ici, mettons toutes nos chaînes traduisibles dans un seul fichier Localizable.strings. Il s’agit d’un simple remaniement de Main.strings à Localizable.strings, alors allons-y.

📖 Aller plus loin » Si vous souhaitez en savoir plus sur la localisation des storyboards iOS, consultez notre guide, iOS i18n : Internationaliser les storyboards dans Xcode

Commençons par les titres des éléments de navigation de notre écran. Nous pouvons simplement remplacer les titres définis dans nos storyboards en définissant le champ title dans nos contrôleurs de vue. Notre écran d’accueil, qui présente la liste de nos artistes, est connecté à TrackListViewController. Mettons à jour ce contrôleur maintenant.

class TrackListViewController : UIViewController {
   // ...
    override func viewDidLoad() {
        super.viewDidLoad()
        title = NSLocalizedString("trackListTitle", comment: "")
        // ...
    }
    
}

Nous utilisons le NSLocalizedString habituel pour récupérer notre traduction depuis Localizable.strings. Assurons-nous que la chaîne de traduction existe dans la version anglaise de Localizable.strings.

"copyright" = "Droit d’auteur © %@ %@." « Tous droits réservés. »
"trackListTitle" = "Short Circuit";

Avec cela en place, notre application aura exactement le même aspect lorsqu’elle sera exécutée en anglais. Nous ajouterons nos paramètres régionaux non anglais un peu plus tard. Terminons d’abord de déplacer nos traductions hors de nos storyboards.
Pour nos étiquettes, nous devons nous assurer que nous disposons d’outlets depuis nos storyboards vers leurs contrôleurs respectifs.

Après avoir connecté nos étiquettes, nous répétons simplement le même processus d’appel à NSLocalizedString pour leur fournir les chaînes traduites. Et, bien sûr, nous ajoutons nos nouvelles chaînes dans notre fichier anglais Localizable.strings.
Notre TrackDetailsViewController, qui aide à afficher les informations d’un seul morceau, ressemblerait à ceci après que nous ayons déplacé nos traductions de storyboard :

import UIKit
classe TrackDetailsViewController : UIViewController {
    @IBOutlet weak var trackNameHeaderLabel: UILabel!
    @IBOutlet weak var artistNameHeaderLabel: UILabel!
    // ...
    var track : Track?
    override func viewDidLoad() {
        super.viewDidLoad()
        title = NSLocalizedString("trackDetailsTitle", comment: "")
        if let track = track {
            trackNameHeaderLabel.text =
                getLocalizedHeaderText(clé: "trackNameHeader")
            artistNameHeaderLabel.text =
                getLocalizedHeaderText(clé: "artistNameHeader")
            releaseDateHeaderLabel.text =
                getLocalizedHeaderText(key: "releaseDateHeader")
            // ...
        }
    }
    
    fileprivate func getLocalizedHeaderText(key: String) -> String {
        return NSLocalizedString(key, comment: "")
            .localizedUppercase
    }
}

La fonction getLocalizedHeaderText est simplement un petit utilitaire que nous utilisons pour fournir un formatage en majuscules localisé à notre texte d’étiquette traduit.
Après avoir ajouté nos chaînes de traduction à notre Localizable.strings, notre application a exactement le même aspect qu’auparavant.

App avec refactorisation réussie | PhraseOn dirait une refactorisation réussie

Nous pouvons maintenant retirer complètement nos fichiers de traduction de storyboard de notre projet XCode. Nous le faisons en sélectionnant le fichier storyboard dans le navigateur de projet et en décochant chaque paramètre régional sous l’en-tête Localisations dans le inspecteur de fichier.

📖 Aller plus loin » Si vous travaillez beaucoup avec des storyboards iOS, vous voudrez peut-être consulter notre article, Automatiser la localisation des storyboards iOS.

Mise à jour de nos traductions avec Phrase

Nous devons maintenant mettre à jour nos traductions Localizable.strings pour nos langues non-source (non-anglaises dans mon cas). Nous le faisons afin que nos utilisateurs non-anglophones puissent voir nos étiquettes de mise à jour dans leur langue. Nous pouvons, bien sûr, utiliser notre flux de travaux habituel Phrase pour traduire nos étiquettes.
Tout d’abord, nous allons charger notre nouvelle source en faisant un $ phrase push depuis la ligne de commande.
Nos nouvelles clés de traduction devraient maintenant apparaître sur la console web de Phrase . Une fois que nos traducteurs ont traduit les clés dans tous les paramètres régionaux que notre application prend en charge, nous pouvons $ phrase pull depuis la ligne de commande pour obtenir nos fichiers Localizable.strings mis à jour. Maintenant, lorsque nous exécutons notre application dans un paramètre linguistique non source (arabe dans mon cas), nous voyons que nos vues sont traduites comme prévu.

Application de démonstration traduite | PhraseTout va bien dans tous les paramètres régionaux

📖 Aller plus loin » Vous pouvez en savoir plus sur le flux de travaux de base de Phrase avec iOS dans localisation application iOS avec Phrase.

Maintenant que nous avons déplacé nos chaînes de traduction de storyboard vers des fichiers Localizable.strings, nous pouvons passer à la configuration des traductions over-the-air dans notre projet Phrase.

Ajout d’une distribution over-the-air dans Phrase

Préparons notre projet Phrase pour les traductions over-the-air. Dans notre console web Phrase, ouvrons le menu déroulant de notre organisation dans la barre de navigation supérieure et sélectionnons Intégrations.

Ouverture du menu Intégrations dans Phrase | Phrase OTA se trouve sous Intégrations

Cela ouvrira notre page Intégrations Phrase. Ici, nous pouvons trouver la ligne over-the-air (OTA) et cliquer sur son bouton Configurer.

Configuration d'OTA | PhraseLe nombre croissant d’intégrations Phrase

Nous devrions maintenant voir la page over-the-air nous invitant à créer une distribution. Une distribution est une configuration OTA de projet qui cible une ou plusieurs plateformes et dispose d’options de secours.

Créer une distribution pour l'application de démonstration | PhraseNous pouvons créer une distribution OTA spécifique à notre application iOS

Cliquons sur le bouton Créer distribution pour ouvrir la boîte de dialogue Ajouter distribution.

Options de distribution d’applications | PhraseLes options pour ajouter une distribution sont assez explicites

Pour notre projet actuel, nous pouvons donner à la distribution un nom de notre choix, sélectionner le projet Phrase associé à notre application iOS, et cocher la case de la plateforme ios. Nous pouvons laisser les options de secours par défaut telles qu’elles sont, car elles conviennent à nos besoins. Cliquons sur le bouton Enregistrer pour créer la distribution.

💡Pour votre information » Vous pouvez modifier les paramètres de votre distribution à tout moment en revenant à la page over-the-air.

Ajout de notre première version OTA

Pour travailler avec le SDK iOS sans voir de résultat d’échec lorsque nous essayons de mettre à jour nos traductions dans l’application, nous devons disposer d’une version OTA. Une version est essentiellement un instantané de nos traductions Phrase que nous pouvons tester et déployer dans notre application iOS over-the-air. Nous parlerons des versions plus tard. Pour l’instant, créons une première version pour commencer à utiliser le SDK.
Nous commencerons par cliquer sur le bouton Créer une version en bas de notre page de distribution.

Bouton Créer une version | Phrase
Libérez-moi

Cela ouvre la boîte de dialogue Ajouter une version. Nous pouvons ajouter une description pour nous aider à identifier la version plus tard, laisser tout le reste tel quel, et cliquer sur Enregistrer.

Menu Ajouter une version | PhraseUne version est un instantané de traduction que nous pouvons déployer

Nous devrions maintenant voir une entrée sous Versions près du bas de notre page de distribution.
Maintenant que nous avons une distribution OTA et une première version, nous pouvons configurer OTA dans notre application iOS.

Installation du SDK iOS de Phrase

Nous aurons besoin du SDK Phrase installé pour utiliser OTA. Nous pouvons le faire via CocoaPods, Carthage, ou manuellement.
Pour installer le SDK via CocoaPods, il faut que CocoaPods soit installé sur notre Mac. Vous pouvez voir les instructions d’installation sur le site Web de CocoaPods. En supposant que nous avons CocoaPods installé, nous pouvons naviguer vers le répertoire racine du projet (celui qui contient notre fichier .xcodeproj) et exécuter la commande suivante depuis le terminal.

$ pod init

Cela créera un Podfile dans notre répertoire racine. Ouvrons ce fichier dans notre éditeur de code préféré et ajouter une ligne pour qu’il ressemble à ceci :

target 'phraseapp-demo' do
  use_frameworks!
  # Pods for phraseapp-demo
  pod 'PhraseSDK'
end

Avec cette modification enregistrée, nous pouvons exécuter ce qui suit depuis notre terminal :

$ pod install

Si tout s’est bien passé, nous devrions avoir reçu une sortie indiquant que Phrase a été installé. Après cela, nous pouvons fermer toutes les fenêtres XCode que nous avons ouvertes et ouvrir le fichier .xcworkspace que CocoaPods a ajouté à la racine de notre projet après l’installation de Phrase.

Configurer Phrase dans notre application iOS

Avec le SDK installé, nous allons le connecter à notre application. Tout d’abord, jetons un coup d’œil rapide à deux méthodes principales proposées par le SDK Phrase :
Phrase.shared.setup(distributionID:environmentSecret:timeout:) initialise l’objet singleton Phrase partagé, prenant nos informations d’identification et un paramètre de délai d’attente optionnel.
Phrase.shared.updateTranslations(translationResult:) met à jour manuellement les traductions dans l’application, en récupérant les plus récentes depuis les serveurs Phrase si une nouvelle version existe. updateTranslations prend une fermeture d’échappement optionnelle, translationResult, que nous pouvons fournir si nous voulons agir lorsque la demande de mettre à jour est terminée.

Ok, allons ajouter une classe OTATranslations qui fournit un léger wrapper autour de PhraseApp.

import PhraseSDK
class OTATranslations {
    static let shared = OTATranslations()
    private init() {
        #if DEBUG
        Phrase.shared.debugMode = true
        #endif
        let config : PList? = loadConfig()
        if let config = config {
            #if DEBUG
            let environmentTokenKey : String = "devToken"
            #else
            let environmentTokenKey : String = "prodToken"
            #endif
            Phrase.shared.setup(
                distributionID : config.getValue(withKey : "distributionID"),
                environmentSecret : config.getValue(withKey : environmentTokenKey),
                timeout: config.getValue(withKey: "timeout")
            )
        }
    }
    func updateTranslations(onUpdateComplete: (() -> Void)? = nil) {
        do {
            try Phrase.shared.updateTranslations { result in
                switch result {
                case .success(let updated):
                    si mis à jour {
                        printIfDebug("Translations mises à jour avec succès")
                        onUpdateComplete?()
                    } else {
                        printIfDebug("Aucune nouvelle traduction trouvée")
                    }
                case .failure:
                    printIfDebug("Échec de la mise à jour des traductions")
                }
            }
        } catch {
            printIfDebug("Erreur lors de la mise à jour des traductionsa: \(error)")
        }
    }
    fileprivate func loadConfig() -> PList? {
        do {
            return try PList(pListResource: "PhraseApp")
        } catch {
            printIfDebug(
                printIfDebug("Erreur de chargement de la configuration Phrase depuis plist, \(error)")
        }
        return nil
    }
}

💡FYI » Phrase.shared.debugMode est un indicateur qui rend le SDK Phrase plus verbeux, en affichant plus de détails dans la console, lorsqu’il est activé. Nous l’activons lorsque nous exécutons une version de débogage de notre application.
💡FYI » La fonction printIfDebug(_:) est un helper personnalisé qui affiche simplement la chaîne donnée dans la console si l’indicateur #DEBUG est activé.

Nous fournissons un simple objet singleton OTATranslations.shared à utiliser dans notre application. Notre objet est initialisé en tirant les valeurs de configuration de Phrase d’un PhraseApp.plist et en les fournissant à PhraseApp.setup. Pour que cela fonctionne, nous devons créer la classe PhraseApp.plist dans notre projet XCode. Faisons-le maintenant. Cela devrait ressembler un peu à ce qui suit.

Clés | PhraseAssurez-vous que vos clés correspondent à celles-ci

Voici une version texte si vous voulez ⌘-C.

<?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>
    <clé>distributionID</clé>
    <chaîne>votre_distribution_id</chaîne>
    <clé>devToken</clé>
    <chaîne>votre_secret_de_developpement_de_distribution</chaîne>
    <clé>prodToken</clé>
    <chaîne>votre_secret_de_production_de_distribution</chaîne>
    <clé>timeout</clé>
    <integer>10</integer>
</dict>
</plist>

✋🏽 Attention » Vous voudrez peut-être ajouter votre fichier PhraseApp.plist à votre .gitignore pour protéger vos clés.
💡Pour info » La classe PList que nous utilisons pour charger les valeurs de notre fichier .plist est une classe utilitaire personnalisée.

Les valeurs pour notre distributionID, devToken, et prodToken peuvent être trouvées sur la page de distribution OTA dans la console web de Phrase. Nous pouvons naviguer vers l’onglet Vue d’ensemble du tableau de bord de notre projet, puis cliquer sur le bouton Voir les distributions sous la section over-the-air. Cela ouvre la page over-the-air, et de là, nous pouvons trouver et cliquer sur la distribution OTA de notre projet dans la liste Distributions. Une fois sur la page de la distribution spécifique, nous pouvons trouver les valeurs Identifiant de distribution, secret de développement et secret de production à copier et coller dans notre fichier .plist. Bien sûr, nous utilisons « jeton » au lieu de « secret » dans notre .plist, mais vous l’avez probablement déjà compris.

Copier les identifiants et jetons secrets | PhraseCopiez et collez vos identifiants et jetons secrets

Ok, maintenant que nous avons connecté le SDK Phrase à notre classe OTATranslations, utilisons-le dans notre AppDelegate.swift.

import UIKit
@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {
    var window: UIWindow ?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        OTATranslations.shared.updateTranslations()
        return true
    }
}

Dans la méthode application(_:didFinishLaunchingWithOptions:) de notre AppDelegate, qui s’exécute au démarrage de notre application, nous mettons manuellement à jour nos traductions over-the-air. Cela récupère toutes les nouvelles traductions en arrière-plan. Cependant, notre configuration actuelle ne mettra pas à jour l’interface utilisateur immédiatement. Les mises à jour de traduction qui sont récupérées lors de ce lancement d’application apparaîtront à l’utilisateur lors de son suivant lancement d’application. C’est souvent le comportement que nous voulons : avoir de nouvelles chaînes de traduction qui apparaissent pendant que l’utilisateur utilise l’application pourrait être une expérience utilisateur étrange et potentiellement déstabilisante.

Rafraîchir manuellement l’interface utilisateur après avoir récupéré de nouvelles traductions

Cependant, en fonction de nos exigences, nous pourrions avoir besoin de rafraîchir l’interface utilisateur de l’application immédiatement après avoir récupéré une mise à jour de traduction. Nous pouvons le faire en utilisant le paramètre de fermeture de rappel que nous avons fourni dans updateTranslations(onUpdateComplete:).

import UIKit
@UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {
    var window: UIWindow?
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any] ?) -> Bool {
        OTATranslations.shared.updateTranslations() {
            AppDelegate.reloadRootViewController()
        }
        return true
    }
    static func reloadRootViewController() {
        DispatchQueue.main.async {
            let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
            let appDelegate = UIApplication.shared.delegate as! AppDelegate
            appDelegate.window?.rootViewController =
                storyboard.instantiateInitialViewController()
        }

Ici, nous fournissons l’argument onUpdateComplete à updateTranslations en tant que fermeture d’échappement. Cette fonction de rappel sera appelée lorsqu’il y aura de nouvelles traductions qui ont été récupérées avec succès. Lorsque cela se produit, nous appelons notre méthode personnalisée AppDelegate.reloadViewController(). Cela rechargera effectivement notre application et montrera à l’utilisateur nos traductions les plus récentes.

✋🏽 Attention » Soyez vigilant lors du rechargement du contrôleur de vue racine de l’application. Si l’utilisateur a déjà commencé à faire quelque chose dans votre application, il se peut que son flux soit interrompu – et que ses données non enregistrées soient perdues – lorsque le rechargement se produit. Pour réduire les chances que cela se produise, vous voudrez peut-être utiliser une configuration de timeout relativement basse lors de la configuration du SDK PhraseApp. De cette façon, si la demande de traduction prend du temps, elle s’annulera simplement et ne déclenchera pas le rechargement. Alternativement, et de façon plus fiable, vous pourriez faire apparaître un indicateur de chargement bloquant pendant la requête. Cela empêcherait l’utilisateur d’interagir avec votre application pendant le chargement de la traduction, évitant ainsi la perte de données mentionnée ci-dessus.

La liberté des traductions iOS over-the-air avec Phrase

Nous avons pratiquement terminé d’intégrer les traductions OTA dans notre application. Après avoir publié cette version de notre application sur l’App Store, nous sommes libres d’envoyer des traductions à nos utilisateurs sans passer à nouveau par l’approbation de l’App Store. Tout ce que nous avons à faire est de nous rendre sur notre console web Phrase, et

  1. Mettre à jour nos traductions des paramètres régionaux, puis
  2. Créer une nouvelle version pour notre distribution OTA (tout comme nous l’avons fait auparavant), et
  3. Publiez la version.

Publication de la version | Phrase

N’oubliez pas de publier votre version après l’avoir revue

C’est vraiment aussi simple que ça. Une fois que nous publions notre version dans la console web de Phrase, nos utilisateurs commenceront à recevoir les traductions mises à jour. Tous les utilisateurs qui ont la version de l’application connectée au SDK PhraseApp récupéreront les nouvelles traductions over-the-air. Pas besoin de publier une nouvelle version de l’application, pas besoin d’attendre l’approbation de l’App Store. Douce liberté.

🔗 Ressource » Vous pouvez voir et télécharger le code terminé pour le projet iOS que nous avons construit ici depuis notre dépôt Github.

Pour en savoir plus

Si vous souhaitez approfondir l’internationalisation et la localisation iOS, consultez certains de nos autres articles sur le sujet.

Et voilà, c’est terminé

Connecter notre application aux traductions over-the-air de Phrase ne prend qu’un jour ou deux. Cela peut nous faire économiser des dizaines et des dizaines d’heures alors que nous publions de nouvelles traductions directement à nos utilisateurs de l’application. Avec OTA, nous avons également l’avantage de sauter l’approbation de l’App Store (juste pour mettre à jour le texte). Et Phrase vous offre bien plus que OTA: Phrase peut vraiment rationaliser le processus de localisation pour votre application. Jetez un œil à tous les produits de Phrase et inscrivez-vous pour un essai gratuit de 14 jours.
J’espère que vous commencez à voir le potentiel des traductions over-the-air, et que vous avez apprécié ce petit guide pour faire fonctionner OTA dans votre application iOS. Nous ajouterons plus de contenu OTA dans les jours à venir, alors restez à l’écoute, et bonne programmation :)

Posts associés

Software localization blog category featured image | Phrase

Blog post

Le guide ultime de la localisation JavaScript

Démarrez la localisation JavaScript de votre navigateur avec ce guide complet et préparez votre application pour les utilisateurs internationaux.

Software localization blog category featured image | Phrase

Blog post

Traduction over-the-air Flutter avec Phrase

Arrêtez d’attendre l’approbation du magasin d’applications mobiles et obtenez du contenu frais pour vos utilisateurs d’applications Flutter instantanément à travers le monde—avec Phrase over-the-air.

Software localization blog category featured image | Phrase

Blog post

Le guide ultime de la localisation Flutter

Décodons les secrets de la localisation Flutter afin que vous puissiez parler la langue de vos utilisateurs et continuer à coder votre chemin vers la domination mondiale.

Software localization blog category featured image | Phrase

Blog post

Comment utiliser le plug-in de localisation de Phrase Strings pour WordPress

Apprenez à traduire les pages WordPress ou encore des articles dans plusieurs langues avec l’intégration Phrase Strings pour WordPress.

Software localization blog category featured image | Phrase

Blog post

Détection des paramètres régionaux d’un utilisateur dans une application web

L’un des problèmes les plus courants dans le développement d’applications web est la détection des paramètres régionaux d’un utilisateur. Voici comment le faire correctement.