{"id":133353,"date":"2019-06-19T09:00:26","date_gmt":"2019-06-19T07:00:26","guid":{"rendered":"https:\/\/phrase.com\/blog\/posts\/traduction-de-lapplication-ios-over-the-air-avec-des-chaines-phrase\/"},"modified":"2026-02-26T16:50:22","modified_gmt":"2026-02-26T15:50:22","slug":"ios-over-the-air-translation-with-phrase","status":"publish","type":"post","link":"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/","title":{"rendered":"Traduire une application iOS en over-the-air avec Phrase\u00a0Strings"},"content":{"rendered":"<p>Notre \u00e9quipe application peut se passer des d\u00e9veloppeurs (nous lib\u00e9rant un temps pr\u00e9cieux) lors du d\u00e9ploiement de nouvelles traductions dans notre application. Nous pouvons \u00e9galement nous passer de l\u2019approbation de l\u2019App Store en cas de mise \u00e0 jour du contenu localis\u00e9 de notre application. Voyons comment nous pouvons b\u00e9n\u00e9ficier de ces avantages dans notre application iOS gr\u00e2ce \u00e0 la fonctionnalit\u00e9 over-the-air de Phrase. Nous allons ajouter Phrase over-the-air \u00e0 une application fonctionnelle, le tout depuis la console Phrase et notre projet XCode.<\/p>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_81 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Overview<\/p>\n<span class=\"ez-toc-title-toggle\"><a href=\"#\" class=\"ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle\" aria-label=\"Toggle Table of Content\"><span class=\"ez-toc-js-icon-con\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/span><\/a><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#notre-application\" >Notre application<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#preparation\" >Pr\u00e9paration<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#deplacer-les-traductions-de-notre-application-des-storyboards-vers-localizablestrings\" >D\u00e9placer les traductions de notre application des Storyboards vers Localizable.strings<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#ajout-dune-distribution-over-the-air-dans-phrase\" >Ajout d&rsquo;une distribution over-the-air dans Phrase<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#ajout-de-notre-premiere-version-ota\" >Ajout de notre premi\u00e8re version OTA<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#installation-du-sdk-ios-de-phrase\" >Installation du SDK iOS de Phrase<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#configurer-phrase-dans-notre-application-ios\" >Configurer Phrase dans notre application iOS<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#rafraichir-manuellement-linterface-utilisateur-apres-avoir-recupere-de-nouvelles-traductions\" >Rafra\u00eechir manuellement l&rsquo;interface utilisateur apr\u00e8s avoir r\u00e9cup\u00e9r\u00e9 de nouvelles traductions<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#la-liberte-des-traductions-ios-over-the-air-avec-phrase\" >La libert\u00e9 des traductions iOS over-the-air avec Phrase<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#pour-en-savoir-plus\" >Pour en savoir plus<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/ios-over-the-air-translation-with-phrase\/#voila-cest-termine\" >Voil\u00e0, c&rsquo;est termin\u00e9\u00a0!<\/a><\/li><\/ul><\/nav><\/div>\n<h2 id=\"toc_1\"><span class=\"ez-toc-section\" id=\"notre-application\"><\/span>Notre application<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Nous reprenons l\u00e0 o\u00f9 nous nous \u00e9tions arr\u00eat\u00e9s dans notre pr\u00e9c\u00e9dent article (en anglais) <a href=\"https:\/\/phrase.com\/blog\/posts\/ios-app-localization-phrase\/\">iOS App Localization with Phrase<\/a>. Dans ce tutoriel, nous avons pris une application et nous l&rsquo;avons connect\u00e9e \u00e0 Phrase pour rationaliser notre flux de travaux de localisation. Nous supposons que vous avez lu cet article, et\/ou que vous avez d\u00e9j\u00e0 connect\u00e9 Phrase \u00e0 votre application. Dans le cas contraire, nous vous recommandons vivement de consulter cet article avant de continuer.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6831 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-sim-en-app-two-screens.png\" alt=\"Application de d\u00e9monstration | Phrase\" width=\"832\" height=\"749\" \/><em>Short Circuit, notre application de d\u00e9monstration, une liste de morceaux de musique \u00e9lectronique<\/em><\/p>\n<p>Notre petite application de d\u00e9monstration liste des morceaux de musique \u00e9lectronique, ainsi que leurs interpr\u00e8tes et leurs dates de sortie. C&rsquo;est une application simple \u00e0 deux \u00e9crans avec un <code>UITableViewController<\/code> qui pr\u00e9sente une liste des morceaux, et dispose d&rsquo;un \u00e9cran de d\u00e9tails pour afficher les informations d&rsquo;un morceau unique.<\/p>\n<blockquote><p>\ud83d\udd17 <em>Ressources \u00bb<\/em> Si vous souhaitez faire le travail en parall\u00e8le, vous pouvez r\u00e9cup\u00e9rer le <a href=\"https:\/\/github.com\/PhraseApp-Blog\/ios-ota-phraseapp-starter\">projet de d\u00e9marrage<\/a> sur Github. Le projet termin\u00e9 se trouve pr\u00e8s du bas de l&rsquo;article.<\/p><\/blockquote>\n<h2 id=\"toc_2\"><span class=\"ez-toc-section\" id=\"preparation\"><\/span>Pr\u00e9paration<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>D&rsquo;accord, commen\u00e7ons \u00e0 pr\u00e9parer notre application pour les traductions over-the-air. Dans notre application iOS, nous allons d\u00e9placer nos cha\u00eenes localis\u00e9es des storyboards vers un bon vieux <code>Localizable.strings<\/code>. Nous ajouterons ensuite le support de traduction over-the-air \u00e0 notre projet Phrase. Pour compl\u00e9ter notre pr\u00e9paration, nous installerons le SDK iOS de Phrase, qui synchronise les traductions de notre application avec notre projet Phrase over-the-air.<\/p>\n<h3 id=\"toc_3\"><span class=\"ez-toc-section\" id=\"deplacer-les-traductions-de-notre-application-des-storyboards-vers-localizablestrings\"><\/span>D\u00e9placer les traductions de notre application des Storyboards vers Localizable.strings<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Les traductions Phrase over-the-air fonctionneront parfaitement avec les fichiers storyboard <code>.strings<\/code>. Cependant, pour plus de simplicit\u00e9, nous allons ici mettre toutes nos cha\u00eenes traduisibles dans un seul fichier <code>Localizable.strings<\/code>. Il s&rsquo;agit d&rsquo;un simple remaniement de <code>Main.strings<\/code> \u00e0 <code>Localizable.strings<\/code>, alors allons-y.<\/p>\n<blockquote><p>\ud83d\udcd6 <em>Pour aller plus loin \u00bb<\/em> Si vous souhaitez en savoir plus sur la localisation des storyboards iOS, consultez notre guide, <a href=\"https:\/\/phrase.com\/blog\/posts\/ios-i18n-internationalizing-storyboards-in-xcode\/\">Internationalisation iOS\u00a0: internationaliser les storyboards dans Xcode <\/a><\/p><\/blockquote>\n<p>Commen\u00e7ons par les titres des \u00e9l\u00e9ments de navigation de notre \u00e9cran. Nous pouvons simplement remplacer les titres d\u00e9finis dans nos storyboards en d\u00e9finissant le champ <code>title<\/code> dans nos contr\u00f4leurs de vue. Notre \u00e9cran d&rsquo;accueil, qui pr\u00e9sente la liste des artistes, est connect\u00e9 \u00e0 <code>TrackListViewController<\/code>. Mettons \u00e0 jour ce contr\u00f4leur maintenant.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-group=\"1\" data-enlighter-title=\"TrackListViewController.swift\">class TrackListViewController: UIViewController {\n   \/\/ ...\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        title = NSLocalizedString(\"trackListTitle\", comment: \"\")\n        \/\/ ...\n    }\n    \/\/ ...\n}<\/pre>\n<p>Nous utilisons le <code>NSLocalizedString<\/code> habituel pour r\u00e9cup\u00e9rer notre traduction depuis <code>Localizable.strings<\/code>. Assurons-nous que la cha\u00eene de traduction existe dans la version anglaise de <code>Localizable.strings<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-group=\"2\" data-enlighter-title=\"Localizable.strings\">\"copyright\" = \"Copyright \u00a9 %@ %@. All rights reserved\";\n\"trackListTitle\" = \"Short Circuit\";<\/pre>\n<p>Ceci \u00e9tant fait, notre application aura exactement le m\u00eame aspect lorsqu&rsquo;elle sera ex\u00e9cut\u00e9e en anglais. Nous ajouterons les param\u00e8tres r\u00e9gionaux autres qu&rsquo;anglais un peu plus tard. Terminons d&rsquo;abord de d\u00e9placer nos traductions hors de nos storyboards.<br \/>\nPour nos \u00e9tiquettes, nous devons nous assurer que nous disposons d&rsquo;outlets depuis nos storyboards vers leurs contr\u00f4leurs respectifs.<\/p>\n<p>Apr\u00e8s avoir connect\u00e9 nos \u00e9tiquettes, nous r\u00e9p\u00e9tons simplement le m\u00eame processus d&rsquo;appel \u00e0 <code>NSLocalizedString<\/code> pour leur fournir les cha\u00eenes traduites. Bien s\u00fbr, nous ajoutons nos nouvelles cha\u00eenes dans notre fichier anglais <code>Localizable.strings<\/code>.<br \/>\nVoici \u00e0 quoi devrait ressembler <code>TrackDetailsViewController<\/code>, qui aide \u00e0 afficher les informations d&rsquo;un morceau, apr\u00e8s avoir d\u00e9plac\u00e9 nos traductions storyboard :<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-group=\"3\" data-enlighter-title=\"TrackDetailsViewController.swift\" data-enlighter-linenumbers=\"false\">import UIKit\nclass TrackDetailsViewController: UIViewController {\n    @IBOutlet weak var trackNameHeaderLabel: UILabel!\n    @IBOutlet weak var artistNameHeaderLabel: UILabel!\n    \/\/ ...\n    var track: Track?\n    override func viewDidLoad() {\n        super.viewDidLoad()\n        title = NSLocalizedString(\"trackDetailsTitle\", comment: \"\")\n        if let track = track {\n            trackNameHeaderLabel.text =\n                getLocalizedHeaderText(key: \"trackNameHeader\")\n            artistNameHeaderLabel.text =\n                getLocalizedHeaderText(key: \"artistNameHeader\")\n            releaseDateHeaderLabel.text =\n                getLocalizedHeaderText(key: \"releaseDateHeader\")\n            \/\/ ...\n        }\n    }\n    \/\/ ...\n    fileprivate func getLocalizedHeaderText(key: String) -&gt; String {\n        return NSLocalizedString(key, comment: \"\")\n            .localizedUppercase\n    }\n}<\/pre>\n<p>La fonction <code>getLocalizedHeaderText<\/code> est simplement un petit utilitaire que nous utilisons pour fournir un formatage en majuscules localis\u00e9 \u00e0 notre texte d&rsquo;\u00e9tiquette traduit.<br \/>\nApr\u00e8s avoir ajout\u00e9 nos cha\u00eenes de traduction \u00e0 notre <code>Localizable.strings<\/code>, notre application a exactement le m\u00eame aspect qu&rsquo;auparavant.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6833 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-after-storyboard-labels-moved-607x1024.png\" alt=\"Appli avec refactorisation r\u00e9ussie | Phrase\" width=\"607\" height=\"1024\" \/><em>Refactorisation r\u00e9ussie<\/em><\/p>\n<p>Nous pouvons maintenant retirer compl\u00e8tement nos fichiers de traduction storyboard de notre projet XCode. Nous le faisons en s\u00e9lectionnant le fichier storyboard dans le <em>navigateur de projet<\/em> et en d\u00e9cochant chaque param\u00e8tre r\u00e9gional sous l&rsquo;en-t\u00eate <em>Localizations<\/em> dans <em>File inspector<\/em>.<\/p>\n<blockquote><p>\ud83d\udcd6 <em>Pour aller plus loin \u00bb<\/em> Si vous travaillez beaucoup avec des storyboards iOS, nous vous invitons \u00e0 consulter notre article (en anglais) <a href=\"https:\/\/phrase.com\/blog\/posts\/ios-automate-ios-storyboard-localization\/\">Automate iOS Storyboard Localization<\/a>.<\/p><\/blockquote>\n<h4 id=\"toc_4\">Mise \u00e0 jour de nos traductions avec Phrase<\/h4>\n<p>Nous devons maintenant mettre \u00e0 jour nos traductions <code>Localizable.strings<\/code> pour nos langues non-source (autres qu&rsquo;anglais dans mon cas). Nous le faisons afin que nos utilisateurs non anglophones puissent voir nos \u00e9tiquettes de mise \u00e0 jour dans leur langue. Nous pouvons, bien s\u00fbr, utiliser notre flux de travaux habituel Phrase pour traduire nos \u00e9tiquettes.<br \/>\nTout d&rsquo;abord, nous allons charger notre nouvelle source en utilisant <code>$ phrase push<\/code> depuis la ligne de commande.<br \/>\nNos nouvelles cl\u00e9s de traduction devraient maintenant appara\u00eetre sur la console web de Phrase. Une fois que nos traducteurs ont traduit les cl\u00e9s dans tous les param\u00e8tres r\u00e9gionaux que notre application prend en charge, nous pouvons utiliser <code>$ phrase pull<\/code> depuis la ligne de commande pour obtenir nos fichiers <code>Localizable.strings<\/code> mis \u00e0 jour. D\u00e9sormais, lorsque nous ex\u00e9cutons notre application dans un param\u00e8tre linguistique non source (arabe dans mon cas), nous constatons que nos vues sont traduites comme pr\u00e9vu.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6835 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-after-phraseapp-pull-600x1024.png\" alt=\"Application de d\u00e9monstration traduite | Phrase\" width=\"600\" height=\"1024\" \/><em>Tout va bien dans tous les param\u00e8tres r\u00e9gionaux<\/em><\/p>\n<blockquote><p>\ud83d\udcd6 <em>Pour aller plus loin \u00bb<\/em> Consultez <a href=\"https:\/\/phrase.com\/blog\/posts\/ios-app-localization-phrase\/\">Localiser une application iOS avec Phrase<\/a> pour en savoir plus sur le flux de travaux Phrase de base pour iOS.<\/p><\/blockquote>\n<p>Maintenant que nous avons d\u00e9plac\u00e9 nos cha\u00eenes de traduction storyboard vers des fichiers <code>Localizable.strings<\/code>, nous pouvons passer \u00e0 la configuration des traductions over-the-air dans notre projet Phrase.<\/p>\n<h3 id=\"toc_5\"><span class=\"ez-toc-section\" id=\"ajout-dune-distribution-over-the-air-dans-phrase\"><\/span>Ajout d&rsquo;une distribution over-the-air dans Phrase<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nous allons pr\u00e9parer notre projet Phrase pour les traductions over-the-air. Dans notre console web Phrase, nous allons ouvrir le menu d\u00e9roulant de notre organisation dans la barre de navigation sup\u00e9rieure et s\u00e9lectionner <em>Integrations<\/em>.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6836 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-integrations-menu-item-1024x628.png\" alt=\"Ouverture du menu Int\u00e9grations dans Phrase | Phrase \" width=\"1024\" height=\"628\" \/><em>OTA se trouve sous<\/em> Int\u00e9grations<\/p>\n<p>Cela ouvre la page <a href=\"https:\/\/phrase.com\/fr\/integrations\/\"><em>Phrase Integrations<\/em><\/a>. En regard de la ligne <em>Over the Air (OTA)<\/em>, nous cliquons sur le bouton <em>Configure<\/em>.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6837 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-integrations-page-1024x741.png\" alt=\"Configuration d&apos;OTA | Phrase\" width=\"1024\" height=\"741\" \/><em>Toujours plus de nouvelles int\u00e9grations Phrase<\/em><\/p>\n<p>La page <em>Over the Air<\/em> s&rsquo;ouvre, nous invitant \u00e0 cr\u00e9er une distribution. Une distribution est une configuration OTA de projet qui cible une ou plusieurs plateformes et inclut des options de secours.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6838 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-ota-page-1024x434.png\" alt=\"Cr\u00e9er une distribution pour l&apos;application de d\u00e9monstration | Phrase\" width=\"1024\" height=\"434\" \/><em>Nous allons cr\u00e9er une distribution OTA pour notre application iOS<\/em><\/p>\n<p>Cliquez sur le bouton <em>Create distribution<\/em> pour ouvrir la bo\u00eete de dialogue <em>Add distribution<\/em>.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6839 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-add-distribtution-dialog-853x1024.png\" alt=\"Options de distribution d&apos;appli | Phrase\" width=\"853\" height=\"1024\" \/><em><\/em>Options permettant d&rsquo;ajouter d&rsquo;une distribution<em><\/em><\/p>\n<p>Pour notre projet actuel, nous pouvons donner \u00e0 la distribution le nom de notre choix, s\u00e9lectionner le projet Phrase associ\u00e9 \u00e0 notre application iOS, et cocher la case de la plateforme <em>ios<\/em>. Nous pouvons laisser les options de secours par d\u00e9faut telles qu&rsquo;elles sont, car elles conviennent \u00e0 nos besoins. Cliquez sur le bouton <em>Save<\/em> pour cr\u00e9er la distribution.<\/p>\n<blockquote><p>\ud83d\udca1<em>Pour information \u00bb<\/em> Vous pouvez modifier les param\u00e8tres de votre distribution \u00e0 tout moment en revenant \u00e0 la page <em>Over the Air<\/em>.<\/p><\/blockquote>\n<h3 id=\"toc_6\"><span class=\"ez-toc-section\" id=\"ajout-de-notre-premiere-version-ota\"><\/span>Ajout de notre premi\u00e8re version OTA<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Pour travailler avec le SDK iOS sans voir de r\u00e9sultat d&rsquo;\u00e9chec lorsque nous essayons de mettre \u00e0 jour nos traductions dans l&rsquo;application, nous devons disposer d\u2019une version OTA. Une version est essentiellement un instantan\u00e9 de nos traductions Phrase que nous pouvons tester et d\u00e9ployer dans notre application iOS over-the-air. Nous parlerons des versions plus tard. Pour l&rsquo;instant, cr\u00e9ons une premi\u00e8re version pour commencer \u00e0 utiliser le SDK.<br \/>\nNous commen\u00e7ons par cliquer sur le bouton <em>Create release<\/em> en bas de la page de notre distribution.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6841 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-create-release-button-1024x621.png\" alt=\"Bouton Create release\u00a0| Phrase\" width=\"1024\" height=\"621\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-create-release-button-1024x621.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-create-release-button-300x182.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-create-release-button-768x465.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-create-release-button.png 1170w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\n<em>Lib\u00e9rez-moi<\/em><\/p>\n<p>Cela ouvre la bo\u00eete de dialogue <em>Add release<\/em>. Ajoutez une description pour identifier facilement la version plus tard, laissez tout le reste tel quel et cliquez sur <em>Save<\/em>.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6840 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-first-release-887x1024.png\" alt=\"Menu Add release | Phrase\" width=\"887\" height=\"1024\" \/><em>Une version est un instantan\u00e9 des traductions que nous pouvons d\u00e9ployer<\/em><\/p>\n<p>Vous devriez maintenant voir une entr\u00e9e sous <em>Releases<\/em> pr\u00e8s du bas de la page de notre distribution.<br \/>\nMaintenant que nous avons une distribution OTA et une premi\u00e8re version, nous pouvons configurer OTA dans notre application iOS.<\/p>\n<h3 id=\"toc_7\"><span class=\"ez-toc-section\" id=\"installation-du-sdk-ios-de-phrase\"><\/span>Installation du SDK iOS de Phrase<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nous aurons besoin que SDK Phrase soit install\u00e9 pour utiliser OTA. Nous pouvons le faire via CocoaPods, <a href=\"https:\/\/github.com\/Carthage\/Carthage\">Carthage<\/a>, ou manuellement.<br \/>\nPour installer le SDK via CocoaPods, il faut que CocoaPods soit install\u00e9 sur notre Mac. Vous pouvez voir les instructions d&rsquo;installation sur le site web de CocoaPods. En supposant que CocoaPods est install\u00e9, nous pouvons naviguer vers le r\u00e9pertoire racine du projet (celui qui contient notre fichier <code>.xcodeproj<\/code>) et ex\u00e9cuter la commande suivante depuis le terminal.<\/p>\n<div>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\">$ pod init<\/pre>\n<\/div>\n<p>Cela cr\u00e9e un <code>Podfile<\/code> dans notre r\u00e9pertoire racine. Nous allons ouvrir ce fichier dans notre \u00e9diteur de code pr\u00e9f\u00e9r\u00e9 et ajouter une ligne pour qu&rsquo;il ressemble \u00e0 ceci\u00a0:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"ruby\" data-enlighter-linenumbers=\"false\">target 'phraseapp-demo' do\n  use_frameworks!\n  # Pods for phraseapp-demo\n  pod 'PhraseSDK'\nend<\/pre>\n<p>Cette modification \u00e9tant enregistr\u00e9e, nous pouvons ex\u00e9cuter ce qui suit depuis notre terminal :<\/p>\n<div>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">$ pod install<\/pre>\n<\/div>\n<p>Si tout s&rsquo;est bien pass\u00e9, nous devrions avoir re\u00e7u une sortie\u00a0indiquant que Phrase a \u00e9t\u00e9 install\u00e9. Apr\u00e8s cela, nous pouvons fermer toutes les fen\u00eatres XCode que nous avons ouvertes et ouvrir le fichier <code>.xcworkspace<\/code> que CocoaPods a ajout\u00e9 \u00e0 la racine de notre projet apr\u00e8s l&rsquo;installation de Phrase.<\/p>\n<h3 id=\"toc_8\"><span class=\"ez-toc-section\" id=\"configurer-phrase-dans-notre-application-ios\"><\/span>Configurer Phrase dans notre application iOS<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Le SDK \u00e9tant install\u00e9, nous allons le connecter \u00e0 notre application. Tout d&rsquo;abord, jetons un coup d&rsquo;\u0153il rapide \u00e0 deux m\u00e9thodes principales propos\u00e9es par le SDK Phrase :<br \/>\n<code>Phrase.shared.setup(distributionID:environmentSecret:timeout:)<\/code> initialise l&rsquo;objet singleton Phrase partag\u00e9, en prenant nos informations d\u2019identification et un param\u00e8tre de d\u00e9lai d&rsquo;attente facultatif.<br \/>\n<code>Phrase.shared.updateTranslations(translationResult:)<\/code> met \u00e0 jour manuellement les traductions dans l&rsquo;application, en r\u00e9cup\u00e9rant les plus r\u00e9centes depuis les serveurs Phrase si une nouvelle version existe. <code>updateTranslations<\/code> prend une fermeture d&rsquo;\u00e9chappement facultative, <code>translationResult<\/code>, que nous pouvons fournir si nous voulons agir lorsque la requ\u00eate de mise \u00e0 jour est termin\u00e9e.<\/p>\n<p>Nous allons ajouter une classe <code>OTATranslations<\/code> qui fournit un l\u00e9ger wrapper autour de <code>PhraseApp<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-group=\"4\" data-enlighter-title=\"OTATranslations.swift\" data-enlighter-linenumbers=\"false\">import PhraseSDK\nclass OTATranslations {\n    static let shared = OTATranslations()\n    private init() {\n        #if DEBUG\n        Phrase.shared.debugMode = true\n        #endif\n        let config: PList? = loadConfig()\n        if let config = config {\n            #if DEBUG\n            let environmentTokenKey: String = \"devToken\"\n            #else\n            let environmentTokenKey: String = \"prodToken\"\n            #endif\n            Phrase.shared.setup(\n                distributionID: config.getValue(withKey: \"distributionID\"),\n                environmentSecret: config.getValue(withKey: environmentTokenKey),\n                timeout: config.getValue(withKey: \"timeout\")\n            )\n        }\n    }\n    func updateTranslations(onUpdateComplete: (() -&gt; Void)? = nil) {\n        do {\n            try Phrase.shared.updateTranslations { result in\n                switch result {\n                case .success(let updated):\n                    if updated {\n                        printIfDebug(\"Translations updated successfully\")\n                        onUpdateComplete?()\n                    } else {\n                        printIfDebug(\"No new translations found\")\n                    }\n                case .failure:\n                    printIfDebug(\"Failure updating translations\")\n                }\n            }\n        } catch {\n            printIfDebug(\"Error updating translations: \\(error)\")\n        }\n    }\n    fileprivate func loadConfig() -&gt; PList? {\n        do {\n            return try PList(pListResource: \"PhraseApp\")\n        } catch {\n            printIfDebug(\n                \"Error loading PhraseApp configuration from plist, \\(error)\")\n        }\n        return nil\n    }\n}<\/pre>\n<blockquote><p>\ud83d\udca1<em>Pour information \u00bb<\/em> <code>Phrase.shared.debugMode<\/code> est un indicateur qui rend le SDK Phrase plus bavard, en affichant plus de d\u00e9tails dans la console, lorsqu&rsquo;il est activ\u00e9. Nous l&rsquo;activons lorsque nous ex\u00e9cutons une version de d\u00e9bogage de notre application.<br \/>\n\ud83d\udca1<em>Pour information \u00bb<\/em> La fonction <code>printIfDebug(_:)<\/code> est un helper personnalis\u00e9 qui affiche simplement la cha\u00eene donn\u00e9e dans la console si l&rsquo;indicateur <code>#DEBUG<\/code> est activ\u00e9.<\/p><\/blockquote>\n<p>Nous fournissons un simple objet singleton <code>OTATranslations.shared<\/code> \u00e0 utiliser dans notre application. Notre objet est initialis\u00e9 en tirant les valeurs de configuration de Phrase d&rsquo;un <code>PhraseApp.plist<\/code> et en les fournissant \u00e0 <code>PhraseApp.setup<\/code>. Pour que cela fonctionne, nous devons cr\u00e9er la classe <code>PhraseApp.plist<\/code> dans notre projet XCode. Nous allons le faire faire maintenant. Cela devrait se pr\u00e9senter de la mani\u00e8re suivante.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6842 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-phraseapp-plist-keys-values-1024x173.png\" alt=\"Cl\u00e9s | Phrase\" width=\"1024\" height=\"173\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-phraseapp-plist-keys-values-1024x173.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-phraseapp-plist-keys-values-300x51.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-phraseapp-plist-keys-values-768x129.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-phraseapp-plist-keys-values.png 1424w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><em>Assurez-vous que vos cl\u00e9s correspondent \u00e0 celles-ci<\/em><\/p>\n<p>Voici une version texte si vous voulez <code>\u2318-C<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-group=\"5\" data-enlighter-title=\"PhraseApp.plist\" data-enlighter-linenumbers=\"false\">&lt;?xml version=\"1.0\" encoding=\"UTF-8\"?&gt;\n&lt;!DOCTYPE plist PUBLIC \"-\/\/Apple\/\/DTD PLIST 1.0\/\/EN\" \"http:\/\/www.apple.com\/DTDs\/PropertyList-1.0.dtd\"&gt;\n&lt;plist version=\"1.0\"&gt;\n&lt;dict&gt;\n    &lt;key&gt;distributionID&lt;\/key&gt;\n    &lt;string&gt;your_distribution_id&lt;\/string&gt;\n    &lt;key&gt;devToken&lt;\/key&gt;\n    &lt;string&gt;your_distribution_development_secret&lt;\/string&gt;\n    &lt;key&gt;prodToken&lt;\/key&gt;\n    &lt;string&gt;your_distribution_production_secret&lt;\/string&gt;\n    &lt;key&gt;timeout&lt;\/key&gt;\n    &lt;integer&gt;10&lt;\/integer&gt;\n&lt;\/dict&gt;\n&lt;\/plist&gt;<\/pre>\n<blockquote><p>\u270b\ud83c\udffd <em>Attention \u00bb<\/em> Vous voudrez peut-\u00eatre ajouter votre fichier <code>PhraseApp.plist<\/code> \u00e0 votre <code>.gitignore<\/code> pour prot\u00e9ger vos cl\u00e9s.<br \/>\n\ud83d\udca1<em>Pour information \u00bb<\/em> La classe <code>PList<\/code> que nous utilisons pour charger les valeurs de notre fichier <code>.plist<\/code> est une classe utilitaire personnalis\u00e9e.<\/p><\/blockquote>\n<p>Les valeurs pour <code>distributionID<\/code>, <code>devToken<\/code> et <code>prodToken<\/code> peuvent \u00eatre trouv\u00e9es sur la page de la distribution OTA dans la console web Phrase. Nous pouvons naviguer vers l&rsquo;onglet <em>Overview<\/em> du tableau de bord de notre projet, puis cliquer sur le bouton <em>View distributions<\/em> sous la section <em>Over the Air<\/em>. Cela ouvre la page <em>Over the Air<\/em>. Depuis cette page, nous pouvons trouver et cliquer sur la distribution OTA de notre projet dans la liste <em>Distributions<\/em>. Une fois sur la page de la distribution sp\u00e9cifique, nous pouvons trouver les valeurs <em>Distribution ID<\/em>, <em>Development secret<\/em> et <em>Production secret<\/em> \u00e0 copier-coller dans notre fichier <code>.plist<\/code>. Bien s\u00fbr, nous utilisons \u00ab\u00a0jeton\u00a0\u00bb au lieu de \u00ab\u00a0secret\u00a0\u00bb dans notre <code>.plist<\/code>, mais vous l&rsquo;avez probablement d\u00e9j\u00e0 compris.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6843 size-large\" src=\"https:\/\/phraseapp.com\/blog\/content\/uploads\/2019\/06\/otaios01-distribution-id-and-keys-on-console-1024x602.png\" alt=\"Copier les identifiants et jetons secrets | Phrase\" width=\"1024\" height=\"602\" \/><em style=\"font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif\">Copiez-collez vos identifiants et jetons secrets<\/em><\/p>\n<p>Maintenant que nous avons connect\u00e9 le SDK Phrase \u00e0 notre classe <code>OTATranslations<\/code>, nous allons l&rsquo;utiliser dans <code>AppDelegate.swift<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-group=\"6\" data-enlighter-title=\"AppDelegate.swift\" data-enlighter-linenumbers=\"false\">import UIKit\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    var window: UIWindow?\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&gt; Bool {\n        OTATranslations.shared.updateTranslations()\n        return true\n    }\n}<\/pre>\n<p>Dans la m\u00e9thode <code>application(_:didFinishLaunchingWithOptions:)<\/code> d&rsquo;<code>AppDelegate<\/code>, qui s&rsquo;ex\u00e9cute au d\u00e9marrage de notre application, nous mettons manuellement \u00e0 jour nos traductions over-the-air. Cela r\u00e9cup\u00e8re toutes les nouvelles traductions en arri\u00e8re-plan. Cependant, notre configuration actuelle ne mettra pas \u00e0 jour l&rsquo;interface utilisateur imm\u00e9diatement. Les mises \u00e0 jour de traduction qui sont r\u00e9cup\u00e9r\u00e9es lors de ce lancement d&rsquo;application appara\u00eetront \u00e0 l&rsquo;utilisateur lors du lancement <em>suivant<\/em> de l&rsquo;application. C&rsquo;est souvent le comportement attendu : avoir de nouvelles cha\u00eenes de traduction qui apparaissent pendant que l&rsquo;utilisateur utilise l&rsquo;application pourrait \u00eatre une exp\u00e9rience utilisateur \u00e9trange et potentiellement d\u00e9stabilisante.<\/p>\n<h3 id=\"toc_9\"><span class=\"ez-toc-section\" id=\"rafraichir-manuellement-linterface-utilisateur-apres-avoir-recupere-de-nouvelles-traductions\"><\/span>Rafra\u00eechir manuellement l&rsquo;interface utilisateur apr\u00e8s avoir r\u00e9cup\u00e9r\u00e9 de nouvelles traductions<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Cependant, en fonction de nos exigences, nous pourrions avoir besoin de rafra\u00eechir l&rsquo;interface utilisateur de l&rsquo;application imm\u00e9diatement apr\u00e8s avoir r\u00e9cup\u00e9r\u00e9 une mise \u00e0 jour de traduction. Nous pouvons le faire en utilisant le param\u00e8tre de fermeture de secours que nous avons fourni dans <code>updateTranslations(onUpdateComplete:)<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"swift\" data-enlighter-group=\"7\" data-enlighter-title=\"AppDelegate.swift\" data-enlighter-linenumbers=\"false\">import UIKit\n@UIApplicationMain\nclass AppDelegate: UIResponder, UIApplicationDelegate {\n    var window: UIWindow?\n    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -&gt; Bool {\n        OTATranslations.shared.updateTranslations() {\n            AppDelegate.reloadRootViewController()\n        }\n        return true\n    }\n    static func reloadRootViewController() {\n        DispatchQueue.main.async {\n            let storyboard = UIStoryboard.init(name: \"Main\", bundle: nil)\n            let appDelegate = UIApplication.shared.delegate as! AppDelegate\n            appDelegate.window?.rootViewController =\n                storyboard.instantiateInitialViewController()\n        }<\/pre>\n<p>Ici, nous fournissons l&rsquo;argument <code>onUpdateComplete<\/code> \u00e0 <code>updateTranslations<\/code> en tant que fermeture d&rsquo;\u00e9chappement. Cette fonction de rappel sera appel\u00e9e lorsqu&rsquo;il y aura de nouvelles traductions r\u00e9cup\u00e9r\u00e9es avec succ\u00e8s. Lorsque cela se produit, nous appelons notre m\u00e9thode personnalis\u00e9e <code>AppDelegate.reloadViewController()<\/code>. Cela rechargera effectivement notre application et montrera \u00e0 l&rsquo;utilisateur nos traductions les plus r\u00e9centes.<\/p>\n<blockquote><p>\u270b\ud83c\udffd <em>Attention\u00a0\u00bb<\/em> Soyez vigilant lors du rechargement du contr\u00f4leur de vue racine de l&rsquo;application. Si l&rsquo;utilisateur a d\u00e9j\u00e0 commenc\u00e9 \u00e0 faire quelque chose dans votre application, il se peut que son flux soit interrompu (et que ses donn\u00e9es non enregistr\u00e9es soient perdues) lorsque le rechargement se produit. Pour r\u00e9duire la probabilit\u00e9 que cela se produise, vous voudrez peut-\u00eatre utiliser une configuration de <code>timeout<\/code> relativement basse lors de la configuration du SDK <code>PhraseApp<\/code>. De cette fa\u00e7on, si la demande de traduction prend du temps, elle s&rsquo;annulera simplement et ne d\u00e9clenchera pas le rechargement. Alternativement, et de fa\u00e7on plus fiable, vous pourriez faire appara\u00eetre un indicateur de chargement bloquant pendant la requ\u00eate. Cela emp\u00eacherait l&rsquo;utilisateur d&rsquo;interagir avec votre application pendant le chargement de la traduction, \u00e9vitant ainsi la perte de donn\u00e9es mentionn\u00e9e ci-dessus.<\/p><\/blockquote>\n<h2 id=\"toc_10\"><span class=\"ez-toc-section\" id=\"la-liberte-des-traductions-ios-over-the-air-avec-phrase\"><\/span>La libert\u00e9 des traductions iOS over-the-air avec Phrase<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Nous avons pratiquement termin\u00e9 d&rsquo;int\u00e9grer les traductions OTA dans notre application. Apr\u00e8s avoir publi\u00e9 <em>cette<\/em> version de notre application sur l&rsquo;App Store, nous sommes libres d&rsquo;envoyer des traductions \u00e0 nos utilisateurs sans passer \u00e0 nouveau par l&rsquo;approbation de l&rsquo;App Store. Il nous suffit de nous rendre sur notre console web Phrase, et\u00a0:<\/p>\n<ol>\n<li>Mettre \u00e0 jour nos traductions des param\u00e8tres r\u00e9gionaux, puis<\/li>\n<li>Cr\u00e9er une nouvelle version pour notre distribution OTA (tout comme nous l&rsquo;avons fait auparavant), et<\/li>\n<li>Publier la version.<\/li>\n<\/ol>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-6854 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-publish-release-1024x54.png\" alt=\"Publication de la version\u00a0| Phrase\" width=\"1024\" height=\"54\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-publish-release-1024x54.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-publish-release-300x16.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-publish-release-768x41.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2019\/06\/otaios01-publish-release.png 1170w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p style=\"text-align: center\"><em>N&rsquo;oubliez pas de publier votre version apr\u00e8s l&rsquo;avoir v\u00e9rifi\u00e9e<\/em><\/p>\n<p>C&rsquo;est aussi simple que \u00e7a. Une fois que nous publions notre version dans la console web Phrase, nos utilisateurs commenceront \u00e0 recevoir les traductions mises \u00e0 jour. Tous les utilisateurs qui ont la version de l&rsquo;application connect\u00e9e au SDK <code>PhraseApp<\/code> r\u00e9cup\u00e9reront les nouvelles traductions over-the-air. Pas besoin de publier une nouvelle version de l&rsquo;application, pas besoin d&rsquo;attendre l&rsquo;approbation de l&rsquo;App Store. \u00c7a, c&rsquo;est la libert\u00e9\u00a0!<\/p>\n<blockquote><p>\ud83d\udd17 <em>Ressources\u00a0\u00bb<\/em> Vous pouvez voir et t\u00e9l\u00e9charger le code termin\u00e9 pour le projet iOS que nous avons construit ici depuis <a href=\"https:\/\/github.com\/PhraseApp-Blog\/ios-ota-phraseapp-complete\">notre d\u00e9p\u00f4t Github<\/a>.<\/p><\/blockquote>\n<h2 id=\"toc_11\"><span class=\"ez-toc-section\" id=\"pour-en-savoir-plus\"><\/span>Pour en savoir plus<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Si vous souhaitez en savoir plus sur l&rsquo;internationalisation et la localisation iOS, nous vous sugg\u00e9rons de consulter les articles suivants sur le sujet (en anglais)\u00a0:<\/p>\n<blockquote>\n<ul>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/ios-tutorial-internationalization-localization\/\">Quick Guide: iOS Internationalization (i18n) and Localization (l10n) <\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/internationalizing-a-full-stack-ios-app-firebase-part-1-user-interface\/\">Internationalizing a Full-Stack iOS App with Firebase (Part 1): The User Interface <\/a><\/li>\n<li><a href=\"https:\/\/phrase.com\/blog\/posts\/internationalizing-a-full-stack-ios-app-firebase-part-2-firebase-i18n\/\">Internationalizing a Full-Stack iOS App with Firebase (Part 2): Firebase i18n<\/a><\/li>\n<\/ul>\n<\/blockquote>\n<h2 id=\"toc_12\"><span class=\"ez-toc-section\" id=\"voila-cest-termine\"><\/span>Voil\u00e0, c&rsquo;est termin\u00e9\u00a0!<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Connecter notre application aux traductions over-the-air de Phrase ne prend qu&rsquo;un jour ou deux. Cela peut nous faire \u00e9conomiser des dizaines et des dizaines d&rsquo;heures, en diffusant nos nouvelles traductions directement aux utilisateurs de nos applications. Avec OTA, nous n&rsquo;avons pas besoin de l&rsquo;approbation de l&rsquo;App Store (en cas de simple mise \u00e0 jour du texte). Phrase vous offre plus que la technologie OTA\u00a0: notre plateforme peut vraiment rationaliser le processus de localisation pour votre application. D\u00e9couvrez tous les produits <a href=\"https:\/\/phrase.com\/fr\/platform\/\"><span style=\"font-weight: 400\">Phrase<\/span><\/a> et <a href=\"https:\/\/eu.phrase.com\/idm-ui\/signup\">inscrivez-vous<\/a> pour un essai gratuit de 14\u00a0jours.<br \/>\nJ&rsquo;esp\u00e8re que vous commencez \u00e0 entrevoir tout le potentiel des traductions over-the-air et que vous avez appr\u00e9ci\u00e9 ce petit guide pour utiliser OTA dans vos applications iOS. Nous ajouterons plus de contenu OTA dans les jours \u00e0 venir, alors restez \u00e0 l&rsquo;\u00e9coute, et bonne programmation\u00a0:)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Si vous voulez vous assurer que tous vos utilisateurs d&rsquo;application obtiennent le bon texte, la fonctionnalit\u00e9 over-the-air de Phrase peut vous aider \u00e0 publier vos mises \u00e0 jour de traduction instantan\u00e9ment.<\/p>\n","protected":false},"author":41,"featured_media":2612,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"post-refresh-updated","format":"standard","meta":{"_acf_changed":false,"_stopmodifiedupdate":false,"_modified_date":"","_searchwp_excluded":"","episode_type":"","audio_file":"","podmotor_file_id":"","podmotor_episode_id":"","cover_image":"","cover_image_id":"","duration":"","filesize":"","filesize_raw":"","date_recorded":"","explicit":"","block":"","itunes_episode_number":"","itunes_title":"","itunes_season_number":"","itunes_episode_type":"","footnotes":""},"categories":[2459],"class_list":["post-133353","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-localisation-de-logiciels-fr"],"acf":[],"_links":{"self":[{"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/posts\/133353","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/comments?post=133353"}],"version-history":[{"count":3,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/posts\/133353\/revisions"}],"predecessor-version":[{"id":136285,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/posts\/133353\/revisions\/136285"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/media\/2612"}],"wp:attachment":[{"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/media?parent=133353"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/categories?post=133353"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}