{"id":133356,"date":"2021-07-26T11:46:11","date_gmt":"2021-07-26T09:46:11","guid":{"rendered":"https:\/\/phrase.com\/blog\/posts\/traduction-over-the-air-flutter-avec-phrase\/"},"modified":"2026-02-26T16:50:18","modified_gmt":"2026-02-26T15:50:18","slug":"flutter-over-the-air-translation","status":"publish","type":"post","link":"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/","title":{"rendered":"Traduire du contenu Flutter en over-the-air avec Phrase"},"content":{"rendered":"<p>Rien n&rsquo;est aussi frustrant que d&rsquo;avoir du nouveau contenu pr\u00eat \u00e0 \u00eatre diffus\u00e9 dans votre application mobile et de devoir attendre l&rsquo;approbation du Play Store ou de l&rsquo;App Store (Oui, je m&rsquo;adresse particuli\u00e8rement \u00e0 vous, Apple) pour que vos utilisateurs puissent y acc\u00e9der.<br \/>\nGr\u00e2ce \u00e0 la technologie <a href=\"https:\/\/support.phrase.com\/hc\/fr-fr\/articles\/5804059067804-Over-the-Air-Strings\">Phrase Over the Air<\/a>, il vous suffit d&rsquo;un clic pour int\u00e9grer de nouvelles traductions \u00e0 votre application en direct. Z\u00e9ro complication\u00a0: pas de version \u00e0 publier, pas d&rsquo;approbation de la boutique. Ajoutez \u00e0 cela l&rsquo;exp\u00e9rience fluide des d\u00e9veloppeurs et la prise en charge multi-plateforme de Flutter et vous d\u00e9ployez des fonctionnalit\u00e9s et du contenu \u00e0 votre public \u00e0 une vitesse fulgurante.<br \/>\nDans ce guide pratique, nous allons localiser une petite application Flutter, la connecter \u00e0 l&rsquo;interface CLI Phrase, puis \u00e0 Phrase Over the Air (OTA). N&rsquo;h\u00e9sitez pas \u00e0 passer directement \u00e0 la partie de votre choix, en fonction de vos besoins.<\/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\/flutter-over-the-air-translation\/#lapplication-de-demonstration\" >L&rsquo;application de d\u00e9monstration<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#versions-utilisees\" >Versions utilis\u00e9es<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#localisation-de-notre-application-flutter\" >Localisation de notre application Flutter<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#installation-des-paquets\" >Installation des paquets<\/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\/flutter-over-the-air-translation\/#configuration\" >Configuration<\/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\/flutter-over-the-air-translation\/#ajout-des-fichiers-de-traduction\" >Ajout des fichiers de traduction<\/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\/flutter-over-the-air-translation\/#generation-du-code\" >G\u00e9n\u00e9ration du code<\/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\/flutter-over-the-air-translation\/#localiser-lapplication\" >Localiser l\u2019application<\/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\/flutter-over-the-air-translation\/#connexion-a-phrase\" >Connexion \u00e0 Phrase<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#creation-dun-projet-phrase\" >Cr\u00e9ation d\u2019un projet Phrase<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#obtenir-un-jeton-dacces-phrase\" >Obtenir un jeton d&rsquo;acc\u00e8s Phrase<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#installation-du-cli\" >Installation du CLI<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#connexion-de-notre-application-flutter-avec-phrase\" >Connexion de notre application Flutter avec Phrase<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#traductions-over-the-air-avec-phrase\" >Traductions over-the-air avec Phrase<\/a><ul class='ez-toc-list-level-3' ><li class='ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#comment-fonctionne-phrase-ota\" >Comment fonctionne Phrase OTA<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#installation-du-sdk-phrase-flutter\" >Installation du SDK Phrase Flutter<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#creer-une-distribution\" >Cr\u00e9er une distribution<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#creer-une-version-de-developpement\" >Cr\u00e9er une version de d\u00e9veloppement<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#ajout-de-phrase-a-maindart\" >Ajout de Phrase \u00e0 main.dart<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-3'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#cacher-nos-cles-secretes\" >Cacher nos cl\u00e9s secr\u00e8tes<\/a><\/li><\/ul><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-21\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#creation-dune-version-de-production\" >Cr\u00e9ation d&rsquo;une version de production<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-22\" href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-over-the-air-translation\/#et-voila\" >Et voil\u00e0\u00a0!<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"lapplication-de-demonstration\"><\/span>L&rsquo;application de d\u00e9monstration<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Cette modeste application s&rsquo;intitule <em>Heroes of Computer Science<\/em>. Nous avons d\u00e9j\u00e0 pr\u00e9sent\u00e9 cette application dans notre <a href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-localization\/\">Guide de la localisation Flutter<\/a>, un tutoriel approfondi sur l&rsquo;internationalisation du contenu Flutter. Nous allons d&rsquo;abord bri\u00e8vement passer en revue l&rsquo;application.<\/p>\n<p>\ud83d\udd17 <em>Ressources\u00a0\u00bb<\/em> Obtenez le <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-phrase-ota-2021\">code complet de notre application de d\u00e9monstration<\/a> sur GitHub.<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14613 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before-localization-en-fpo2021-1024x897.png\" alt=\"Appli de d\u00e9mo | Phrase\" width=\"1024\" height=\"897\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before-localization-en-fpo2021-1024x897.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before-localization-en-fpo2021-300x263.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before-localization-en-fpo2021-768x673.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before-localization-en-fpo2021-1536x1346.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before-localization-en-fpo2021-2048x1794.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><em>Voici nos h\u00e9ros<\/em><\/p>\n<p>Comme vous pouvez l&rsquo;imaginer, l&rsquo;application est assez simple :<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"ff941dc9-be37-42aa-84c5-5b046ecc432e\" data-enlighter-title=\"File structure\">.\n\u2514\u2500\u2500 lib\/\n    \u251c\u2500\u2500 main.dart (MaterialApp)\n    \u2514\u2500\u2500 features\/\n        \u2514\u2500\u2500 heroes\/\n            \u251c\u2500\u2500 hero_list.dart (HeroList)\n            \u2514\u2500\u2500 hero_card.dart (HeroCard)\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"58f5287f-f48a-4909-bee9-dc0b1404a7d1\" data-enlighter-title=\"lib\/main.dart\">import 'package:flutter\/material.dart';\nimport 'package:flutter_phrase_ota_2021\/features\/hereos\/hero_list.dart';\nvoid main() =&gt; runApp(MyApp());\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Heroes of Computer Science',\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: HeroList(title: 'Heroes of Computer Science'),\n    );\n  }\n}\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"b4e5bd1d-5490-4ad2-8d99-fd77e7da3568\" data-enlighter-title=\"lib\/features\/hereos\/hero_list.dart\">import 'package:flutter\/material.dart';\nimport '.\/hero_card.dart';\nclass HeroList extends StatelessWidget {\n  final String title;\n  HeroList({this.title = ''});\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(title),\n      ),\n      body: Padding(\n        padding: const EdgeInsets.all(16),\n        child: Column(\n          children: [\n            Padding(\n              padding: const EdgeInsets.only(bottom: 8.0),\n              child: Text('6 Hereos'),\n            ),\n            Expanded(\n              child: ListView(\n                children: &lt;Widget&gt;[\n                  HeroCard(\n                    name: 'Grace Hopper',\n                    born: '9 December 1906',\n                    bio: 'Devised theory of machine-independent...',\n                    imagePath: 'assets\/images\/grace_hopper.jpg',\n                  ),\n                  HeroCard(\n                    name: 'Alan Turing',\n                    born: '23 June 1912',\n                    bio: 'Father of theoretical computer science...',\n                    imagePath: 'assets\/images\/alan_turing.jpg',\n                  ),\n                  \/\/ ...\n                ],\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"01667fee-ab49-46a2-99a7-cb6e0b9aadd2\" data-enlighter-title=\"lib\/features\/hereos\/hero_card.dart\">import 'package:flutter\/material.dart';\nclass HeroCard extends StatelessWidget {\n  final String name;\n  final String born;\n  final String bio;\n  final String? imagePath;\n  final String placeholderImagePath = 'assets\/images\/placeholder.jpg';\n  const HeroCard({\n    Key? key,\n    this.name = '',\n    this.born = '',\n    this.bio = '',\n    this.imagePath,\n  }) : super(key: key);\n  @override\n  Widget build(BuildContext context) {\n    var theme = Theme.of(context);\n    return Card(\n      child: Padding(\n        padding: const EdgeInsets.all(4.0),\n        child: Row(\n          crossAxisAlignment: CrossAxisAlignment.start,\n          children: &lt;Widget&gt;[\n            Padding(\n              padding: const EdgeInsets.only(right: 8.0),\n              child: ClipRRect(\n                borderRadius: BorderRadius.circular(2),\n                child: Image.asset(\n                  imagePath ?? placeholderImagePath,\n                  width: 100,\n                  height: 100,\n                ),\n              ),\n            ),\n            Expanded(\n              child: Column(\n                crossAxisAlignment: CrossAxisAlignment.start,\n                children: &lt;Widget&gt;[\n                  Padding(\n                    padding: const EdgeInsets.only(top: 4),\n                    child: Text(\n                      name,\n                      style: theme.textTheme.headline6,\n                    ),\n                  ),\n                  Padding(\n                    padding: const EdgeInsets.only(top: 2, bottom: 4),\n                    child: Text(\n                      born.isEmpty ? '' : 'Born $born',\n                      style: TextStyle(\n                        fontSize: 12,\n                        fontWeight: FontWeight.w300,\n                      ),\n                    ),\n                  ),\n                  Text(\n                    bio,\n                    style: TextStyle(fontSize: 14),\n                  ),\n                ],\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n<\/pre>\n<p>Voil\u00e0 pour notre application de d\u00e9monstration. Nos cha\u00eenes sont actuellement cod\u00e9es en dur, ce qui est loin d&rsquo;\u00eatre id\u00e9al pour la localisation. Nous allons donc internationaliser notre application.<\/p>\n<p>\ud83d\uddd2 <em>Remarque \u00bb<\/em> Si vous souhaitez coder avec nous \u00e0 partir d&rsquo;ici, <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-phrase-ota-2021\/tree\/start\">il vous suffit de cloner la branche de d\u00e9part<\/a> du r\u00e9f\u00e9rentiel de l&rsquo;application.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"versions-utilisees\"><\/span>Versions utilis\u00e9es<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Dans cet article, nous utilisons les versions suivantes (langues, framework et packages)\u00a0:<\/p>\n<ul>\n<li>Dart SDK 2.13.4<\/li>\n<li>Flutter 2.2.3<\/li>\n<li>flutter_localizations (la version semble li\u00e9e \u00e0 Flutter) \u2014 fournit des localisations pour des widgets courants, comme Material ou Cupertino.<\/li>\n<li>intl 0.17.0 \u2014 la colonne vert\u00e9brale du syst\u00e8me de localisation\u00a0; nous permet de cr\u00e9er et d&rsquo;utiliser nos propres localisations\u00a0; sert pour le formatage des dates et des nombres\u00a0; n\u00e9cessaire pour Phrase Flutter SDK.<\/li>\n<li>Phrase 1.0.0 \u2014 Phrase Flutter SDK\u00a0; nous permet de nous connecter \u00e0 Phrase OTA.<\/li>\n<li>flutter_dotenv 5.0.0 \u2014 facilite l&rsquo;utilisation des fichiers de configuration .env afin que nous puissions garder les cl\u00e9s hors de notre d\u00e9p\u00f4t Git.<\/li>\n<\/ul>\n<h2><span class=\"ez-toc-section\" id=\"localisation-de-notre-application-flutter\"><\/span>Localisation de notre application Flutter<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Nous allons utiliser le puissant <a href=\"https:\/\/flutter.dev\/docs\/development\/accessibility-and-localization\/internationalization\">package officiel de localisation de Flutter<\/a> pour localiser rapidement notre application.<\/p>\n<p>\ud83d\uddd2 <em>Remarque \u00bb<\/em> Si vous avez d\u00e9j\u00e0 une application Flutter localis\u00e9e, n&rsquo;h\u00e9sitez pas \u00e0 passer \u00e0 <a href=\"#Over_the_Air_Translations_with_Phrase\">Traductions en over-the-air avec Phrase<\/a>. Assurez-vous simplement que vous avez localis\u00e9 avec <code>intl<\/code> ^0.17.0 et <code>flutter_localizations<\/code> et tout devrait fonctionner.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"installation-des-paquets\"><\/span>Installation des paquets<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nous allons mettre \u00e0 jour <code>pubspec.yaml<\/code> pour installer les packages.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-group=\"1367e491-2975-4a53-b2b7-14a71a9d7984\" data-enlighter-title=\"pubspec.yaml\" data-enlighter-highlight=\"6,7,8\" data-enlighter-linenumbers=\"false\"># ...\ndependencies:\n  flutter:\n    sdk: flutter\n  flutter_localizations:\n    sdk: flutter\n  intl: ^0.17.0\n# ...\n<\/pre>\n<p>Enregistrer <code>pubspec.yaml<\/code> devrait d\u00e9clencher l\u2019IDE pour que les nouveaux paquets soient install\u00e9s automatiquement. Si cela ne fonctionne pas, nous pouvons ouvrir une fen\u00eatre de terminal, naviguer jusqu&rsquo;\u00e0 la racine de notre projet et ex\u00e9cuter ce qui suit.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">flutter pub get\n<\/pre>\n<p>\u270b\ud83c\udffd <em>Avertissement \u00bb<\/em> Le SDK Phrase Flutter, qui se connecte \u00e0 Phrase OTA, n\u00e9cessite la version 0.17.0 du package <code>intl<\/code>. Assurez-vous d&rsquo;utiliser cette version dans votre <code>pubspec.yaml<\/code>.<\/p>\n<p>Le package de localisation Flutter utilise la g\u00e9n\u00e9ration de code, cr\u00e9ant des fichiers dart fortement typ\u00e9s qui correspondent \u00e0 nos fichiers de traduction. Pour activer cette g\u00e9n\u00e9ration de code, nous devons ajouter une ligne \u00e0 <code>pubspec.yaml<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-group=\"7ed7496f-5367-4b00-b73f-4b5c5adc6a3c\" data-enlighter-title=\"pubspec.yaml\" data-enlighter-linenumbers=\"false\"># ...\nflutter:\n  generate: true\n# ...\n<\/pre>\n<p>\ud83d\udd17 <em>Ressources \u00bb<\/em> Si vous souhaitez en savoir plus sur la mani\u00e8re dont fonctionne la biblioth\u00e8que de localisation Flutter, consultez notre article, <a href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-localization\/\">Guide de la localisation Flutter<\/a>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"configuration\"><\/span>Configuration<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nous devons ajouter un fichier qui permet \u00e0 la biblioth\u00e8que de localisation Flutter de savoir o\u00f9 trouver nos fichiers de traduction et de g\u00e9n\u00e9rer son code dart.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"33128200-4a45-4446-aeae-e1d7ea2b34d8\" data-enlighter-title=\"l10n.yaml\"># O\u00f9 trouver les fichiers de traduction\narb-dir: lib\/l10n\n# Traduction par d\u00e9faut\/mod\u00e8le\ntemplate-arb-file: app_en.arb\n# Comment nommer les fichiers dart g\u00e9n\u00e9r\u00e9s\noutput-localization-file: app_localizations.dart\n<\/pre>\n<p>\ud83d\udd17 <em>Ressources \u00bb<\/em> Le <a href=\"https:\/\/docs.google.com\/document\/d\/10e0saTfAv32OZLRmONy866vnaw0I2jwL8zukykpgWBc\/edit#heading=h.upij01jgi58m\">Guide utilisateur officiel d\u2019internationalisation<\/a> couvre de nombreuses autres options qui peuvent \u00eatre ajout\u00e9es dans l10n.yaml pour contr\u00f4ler le g\u00e9n\u00e9rateur de code d&rsquo;internationalisation de Flutter.<\/p>\n<h4>Configuration de notre application pour iOS<\/h4>\n<p>Une \u00e9tape de plus est n\u00e9cessaire pour iOS\u00a0: si nous n&rsquo;ajoutons pas nos param\u00e8tres r\u00e9gionaux pris en charge au fichier iOS <code>Info.plist<\/code>, cela pourrait ne pas fonctionner comme attendu.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"xml\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"d242b82c-096e-4400-83f9-8804fc579705\" data-enlighter-title=\"ios\/Runner\/Info.plist\" data-enlighter-highlight=\"4-8\">&lt;dict&gt;\n\t&lt;key&gt;CFBundleDevelopmentRegion&lt;\/key&gt;\n\t&lt;string&gt;$(DEVELOPMENT_LANGUAGE)&lt;\/string&gt;\n    &lt;key&gt;CFBundleLocalizations&lt;\/key&gt;\n\t&lt;array&gt;\n\t\t&lt;string&gt;en&lt;\/string&gt;\n\t\t&lt;string&gt;ar&lt;\/string&gt;\n\t&lt;\/array&gt;\n\t&lt;key&gt;CFBundleExecutable&lt;\/key&gt;\n\t&lt;string&gt;$(EXECUTABLE_NAME)&lt;\/string&gt;\n    &lt;!-- ... --&gt;\n<\/pre>\n<p>Pour notre d\u00e9mo, nous prendrons en charge l&rsquo;anglais et l&rsquo;arabe. Bien s\u00fbr, vous pouvez ajouter les langues que <em>vous<\/em> souhaitez prendre en charge.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"ajout-des-fichiers-de-traduction\"><\/span>Ajout des fichiers de traduction<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Ensuite, nous devrons ajouter nos fichiers ARB (Application Resource Bundle) de traduction. Ceux-ci seront utilis\u00e9s par la biblioth\u00e8que de localisation Flutter pour g\u00e9n\u00e9rer du code Dart. Les fichiers ARB contiennent simplement des paires cl\u00e9 JSON\/valeur classiques. Nous copierons toutes les cha\u00eenes cod\u00e9es en dur dans notre application vers nos fichiers de traduction.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-group=\"ec798211-0368-488f-8013-5cde35221a0b\" data-enlighter-title=\"lib\/l10n\/app_en.arb\" data-enlighter-linenumbers=\"false\">{\n  \"appTitle\": \"Heroes of Computer Science\",\n  \/\/ ...\n  \"hopperName\": \"Grace Hopper\",\n  \"hopperBio\": \"Devised theory of machine-independent programming languages.\",\n  \"turingName\": \"Alan Turing\",\n  \"turingBio\": \"Father of theoretical computer science &amp; artificial intelligence.\",\n  \/\/ ...\n}\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-group=\"0ba250c1-4e67-4eea-8ea7-30b36a4d1f71\" data-enlighter-title=\"lib\/l10n\/app_ar.arb\" data-enlighter-linenumbers=\"false\">{\n  \"appTitle\": \"\u0623\u0628\u0637\u0627\u0644 \u0639\u0644\u0648\u0645 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631\",\n  \/\/ ...\n  \"hopperName\": \"\u062c\u0631\u064a\u0633 \u0647\u0648\u0628\u0631\",\n  \"hopperBio\": \"\u0625\u0628\u062a\u0643\u0631\u062a \u0646\u0638\u0631\u064a\u0629 \u0644\u0644\u063a\u0627\u062a \u0627\u0644\u0628\u0631\u0645\u062c\u0629 \u0627\u0644\u0645\u0633\u062a\u0642\u0644\u0629 \u0639\u0646 \u0627\u0644\u062c\u0647\u0627\u0632.\",\n  \"turingName\": \"\u0622\u0644\u0627\u0646 \u062a\u0648\u0631\u064a\u0646\u062c\",\n  \"turingBio\": \"\u0627\u0644\u0623\u0628 \u0627\u0644\u0631\u0648\u062d\u064a \u0644\u0639\u0644\u0648\u0645 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631 \u0627\u0644\u0646\u0638\u0631\u064a\u0629 \u0648\u0627\u0644\u0630\u0643\u0627\u0621 \u0627\u0644\u0627\u0635\u0637\u0646\u0627\u0639\u064a.\",\n  \/\/ ...\n}\n<\/pre>\n<p>Encore une fois, nous avons ajout\u00e9 des traductions en anglais et en arabe pour notre d\u00e9mo. N&rsquo;h\u00e9sitez pas \u00e0 utiliser nos param\u00e8tres r\u00e9gionaux ou les v\u00f4tres ici.<\/p>\n<p>\ud83d\uddd2 <em>Remarque \u00bb<\/em> Nous devons nous assurer que nos noms de dossiers et de fichiers correspondent \u00e0 la configuration que nous avons plac\u00e9e dans <code>l10n.yaml<\/code> ci-dessus.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"generation-du-code\"><\/span>G\u00e9n\u00e9ration du code<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>C&rsquo;est fini pour les traductions. Nous pouvons commencer la g\u00e9n\u00e9ration du code. Tout d&rsquo;abord, configurons <code>MaterialApp<\/code> pour la localisation.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"02eaefce-6d90-42f3-8a8a-aa1e1344d9e2\" data-enlighter-title=\"lib\/main.dart\" data-enlighter-highlight=\"2,12,13,14,15,16,17,18,19,20\">import 'package:flutter\/material.dart';\nimport 'package:flutter_localizations\/flutter_localizations.dart';\nimport 'package:flutter_phrase_ota_2021\/features\/hereos\/hero_list.dart';\nvoid main() =&gt; runApp(MyApp());\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      title: 'Heroes of Computer Science',\n      localizationsDelegates: [\n        GlobalMaterialLocalizations.delegate,\n        GlobalWidgetsLocalizations.delegate,\n        GlobalCupertinoLocalizations.delegate,\n      ],\n      supportedLocales: [\n        Locale('en', ''),\n        Locale('ar', ''),\n      ],\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: HeroList(title: 'Heroes of Computer Science'),\n    );\n  }\n}\n<\/pre>\n<p>Maintenant, nous pouvons <strong>ex\u00e9cuter l&rsquo;application<\/strong> pour g\u00e9n\u00e9rer le code dart de localisation. Apr\u00e8s avoir ex\u00e9cut\u00e9 l&rsquo;application, nous devrions voir les fichiers suivants dans notre projet.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"30644a05-36b7-4917-b714-55eb87388d79\" data-enlighter-title=\"Generated code\">.\n\u2514\u2500\u2500 .dart_tool\/\n    \u2514\u2500\u2500 flutter_gen\/\n        \u2514\u2500\u2500 gen_l10n\/\n            \u251c\u2500\u2500 app_localizations.dart\n            \u251c\u2500\u2500 app_localizations_en.dart\n            \u2514\u2500\u2500 app_localizations_ar.dart\n<\/pre>\n<p>Si vous voyez les fichiers g\u00e9n\u00e9r\u00e9s, c&rsquo;est que tout a fonctionn\u00e9\u00a0!<\/p>\n<h3><span class=\"ez-toc-section\" id=\"localiser-lapplication\"><\/span>Localiser l\u2019application<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nous allons maintenant nettoyer <code>main.dart<\/code> et le localiser. Nous allons retirer l&rsquo;import direct de <code>flutter_localizations<\/code> et utiliser \u00e0 la place <code>AppLocalizations<\/code> que nous avons g\u00e9n\u00e9r\u00e9. Nous commencerons \u00e9galement \u00e0 utiliser nos localisations via <code>AppLocalizations.of(context)<\/code> pour int\u00e9grer nos traductions.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"5cdf2a54-42dd-4a10-865c-eb5daf97a3fb\" data-enlighter-title=\"lib\/main.dart\" data-enlighter-highlight=\"2,11,12,13,17,18,19,20,21\">import 'package:flutter\/material.dart';\nimport 'package:flutter_gen\/gen_l10n\/app_localizations.dart';\nimport 'package:flutter_phrase_ota_2021\/features\/hereos\/hero_list.dart';\nvoid main() =&gt; runApp(MyApp());\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      onGenerateTitle: (context) =&gt; AppLocalizations.of(context)!.appTitle,\n      localizationsDelegates: AppLocalizations.localizationsDelegates,\n      supportedLocales: AppLocalizations.supportedLocales,\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      initialRoute: '\/',\n      routes: {\n        '\/': (context) =&gt;\n            HeroList(title: AppLocalizations.of(context)!.appTitle)\n      },\n    );\n  }\n}\n<\/pre>\n<p>Vous avez peut-\u00eatre remarqu\u00e9 que nous utilisons les propri\u00e9t\u00e9s <code>onGenerateTitle<\/code>, <code>initialRoute<\/code>, et <code>routes<\/code> de <code>MaterialApp<\/code> au lieu de <code>title<\/code> et <code>home<\/code>. C&rsquo;est parce que le chargement de la biblioth\u00e8que de localisation Flutter est une op\u00e9ration asynchrone : nous n&rsquo;aurons pas de traductions disponibles tant que notre <code>MaterialApp<\/code> est en cours de construction. Nous utilisons des alternatives pratiques de rappel pour fournir des traductions d\u00e8s qu&rsquo;elles sont pr\u00eates.<br \/>\nNous allons \u00e9galement localiser nos widgets <code>HeroList<\/code> et <code>HeroCard<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"c3cd4c21-b042-465c-8c52-21663b0c44a2\" data-enlighter-title=\"lib\/features\/hereos\/hero_list.dart\" data-enlighter-highlight=\"2,12,24,30,32,36,38\">import 'package:flutter\/material.dart';\nimport 'package:flutter_gen\/gen_l10n\/app_localizations.dart';\nimport '.\/hero_card.dart';\nclass HeroList extends StatelessWidget {\n  final String title;\n  HeroList({this.title = ''});\n  @override\n  Widget build(BuildContext context) {\n    var t = AppLocalizations.of(context)!;\n    return Scaffold(\n      appBar: AppBar(\n        title: Text(title),\n      ),\n      body: Padding(\n        padding: const EdgeInsets.all(16),\n        child: Column(\n          children: [\n            Padding(\n              padding: const EdgeInsets.only(bottom: 8.0),\n              child: Text(t.heroCount(6)),\n            ),\n            Expanded(\n              child: ListView(\n                children: &lt;Widget&gt;[\n                  HeroCard(\n                    name: t.hopperName,\n                    born: '9 December 1906',\n                    bio: t.hopperBio,\n                    imagePath: 'assets\/images\/grace_hopper.jpg',\n                  ),\n                  HeroCard(\n                    nom : t.turingName,\n                    born: '23 June 1912',\n                    bio: t.turingBio,\n                    imagePath: 'assets\/images\/alan_turing.jpg',\n                  ),\n                  \/\/ ...\n                  ),\n                ],\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n<\/pre>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"f0d0ff3c-98fa-4d04-b867-62d07ee7ed89\" data-enlighter-title=\"lib\/features\/hereos\/hero_card.dart\" data-enlighter-highlight=\"1,26,48\">import 'package:flutter_gen\/gen_l10n\/app_localizations.dart';\nimport 'package:intl\/intl.dart';\nimport 'package:flutter\/material.dart';\nclass HeroCard extends StatelessWidget {\n  final String name;\n  final String born;\n  final String bio;\n  final String? imagePath;\n  final String placeholderImagePath = 'assets\/images\/placeholder.jpg';\n  final DateTime bornDateTime;\n  HeroCard({\n    Key? key,\n    this.name = '',\n    this.born = '',\n    this.bio = '',\n    this.imagePath,\n  })  : bornDateTime = DateFormat('d MMMM yyyy').parse(born),\n        super(key: key);\n  @override\n  Widget build(BuildContext context) {\n    var t = AppLocalizations.of(context)!;\n    var theme = Theme.of(context);\n    return Card(\n      child: Padding(\n        padding: const EdgeInsets.all(4.0),\n        child: Row(\n          crossAxisAlignment: CrossAxisAlignment.start,\n          children: &lt;Widget&gt;[\n            Padding(\n              \/\/ &lt;Already-localiazed image from this.imagePath&gt;...\n            ),\n            Expanded(\n              child: Column(\n                crossAxisAlignment: CrossAxisAlignment.start,\n                children: &lt;Widget&gt;[\n                  Padding(\n                    \/\/ &lt;Already-localized name from this.name&gt;...\n                  ),\n                  Padding(\n                    padding: const EdgeInsets.only(top: 2, bottom: 4),\n                    child: Text(\n                      born.isEmpty ? '' : t.heroBorn(bornDateTime),\n                      style: TextStyle(\n                       fontSize: 12,\n                       fontWeight: FontWeight.w300,\n                      ),\n                    ),\n                  ),\n                  \/\/ &lt;Already-loclalized bio from this.bio&gt;...\n                ],\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n<\/pre>\n<p>\ud83d\udd17 <em>Ressources\u00a0\u00bb<\/em> Si vous vous demandez \u00e0 quoi sert l&rsquo;appel <code>t.heroCount(6)<\/code>, lisez tout \u00e0 ce sujet dans notre <a href=\"https:\/\/phrase.com\/fr\/blog\/posts\/flutter-localization\/\">Guide de la localisation Flutter<\/a>.<\/p>\n<p>Maintenant, lorsque nous d\u00e9finissons les param\u00e8tres r\u00e9gionaux de notre syst\u00e8me d&rsquo;exploitation mobile pour l&rsquo;arabe, nous pouvons voir nos cha\u00eenes traduites. Youpi \ud83d\ude03\u00a0!<\/p>\n<p style=\"text-align: center\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14614 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/localized-app-en-ar-fpo2021-1024x966.png\" alt=\"Application de d\u00e9monstration traduite | Phrase\" width=\"1024\" height=\"966\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/localized-app-en-ar-fpo2021-1024x966.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/localized-app-en-ar-fpo2021-300x283.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/localized-app-en-ar-fpo2021-768x725.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/localized-app-en-ar-fpo2021-1536x1449.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/localized-app-en-ar-fpo2021-2048x1933.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><em>Notre application, parfaitement mondialis\u00e9e<\/em><\/p>\n<h2><span class=\"ez-toc-section\" id=\"connexion-a-phrase\"><\/span>Connexion \u00e0 Phrase<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Maintenant que notre application est localis\u00e9e, nous allons la connecter \u00e0 Phrase.<\/p>\n<p>\ud83d\uddd2 <em>Remarque \u00bb<\/em> Si vous souhaitez coder avec nous \u00e0 partir d&rsquo;ici, <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-phrase-ota-2021\/tree\/localized\">il vous suffit de cloner la branche localis\u00e9e<\/a> de notre d\u00e9p\u00f4t GitHub compagnon.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"creation-dun-projet-phrase\"><\/span>Cr\u00e9ation d\u2019un projet Phrase<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>\ud83d\uddd2 <em>Remarque\u00a0\u00bb<\/em> Si vous avez un projet Phrase connect\u00e9 \u00e0 notre application Flutter, passez directement \u00e0 <a href=\"#Over_the_Air_Translations_with_Phrase\">Traductions over-the-air avec Phrase<\/a>.<\/p>\n<p>Je suppose que vous avez un compte Phrase \u00e0 ce stade. Si ce n&rsquo;est pas le cas, <a href=\"https:\/\/eu.phrase.com\/idm-ui\/signup\">s\u2019inscrire pour un essai gratuit<\/a>.<br \/>\nTout d&rsquo;abord, nous allons cr\u00e9er un nouveau projet Phrase en nous connectant et en allant sous <em>Projects \u279e Create New Project<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14580 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-project-btn-fpo2021-1024x249.png\" alt=\"Cr\u00e9er un nouveau projet dans Phrase | Phrase\" width=\"1024\" height=\"249\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-project-btn-fpo2021-1024x249.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-project-btn-fpo2021-300x73.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-project-btn-fpo2021-768x186.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-project-btn-fpo2021-1536x373.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-project-btn-fpo2021-2048x497.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nCela ouvrira la bo\u00eete de dialogue <em>Add Project<\/em>. Ici, vous saisirez un nom de projet. Tout ce qui n&rsquo;est pas le nom du projet est facultatif : nous gagnerons du temps plus tard si nous sp\u00e9cifions <em>ARB<\/em> comme notre format principal. Lorsque nous sommes satisfaits de nos options, nous pouvons cliquer sur le bouton <em>Save<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14581 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-project-dialog-fpo2021-980x1024.png\" alt=\"Fen\u00eatre Ajouter un projet dans Phrase | Phrase\" width=\"980\" height=\"1024\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-project-dialog-fpo2021-980x1024.png 980w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-project-dialog-fpo2021-287x300.png 287w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-project-dialog-fpo2021-768x802.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-project-dialog-fpo2021.png 1294w\" sizes=\"auto, (max-width: 980px) 100vw, 980px\" \/><br \/>\nEnsuite, nous allons acc\u00e9der \u00e0 la page de configuration du projet. Cliquez sur le bouton <em>Set up languages<\/em> pour ajouter les langues prises en charge par notre application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14582 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-btn-fpo2021-1024x668.png\" alt=\"Configurer de nouvelles langues dans Phrase | Phrase\" width=\"1024\" height=\"668\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-btn-fpo2021-1024x668.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-btn-fpo2021-300x196.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-btn-fpo2021-768x501.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-btn-fpo2021-1536x1001.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-btn-fpo2021-2048x1335.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14583 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-page-fpo2021.png\" alt=\"Ajouter des langues d&apos;application prises en charge | Phrase\" width=\"2374\" height=\"1362\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-page-fpo2021.png 2374w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-page-fpo2021-300x172.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-page-fpo2021-1024x587.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-page-fpo2021-768x441.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-page-fpo2021-1536x881.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/set-up-langs-page-fpo2021-2048x1175.png 2048w\" sizes=\"auto, (max-width: 2374px) 100vw, 2374px\" \/><br \/>\nNous pouvons ajouter autant de langues que nous le souhaitons ici. La premi\u00e8re sera la langue par d\u00e9faut. Apr\u00e8s avoir ajout\u00e9 les param\u00e8tres r\u00e9gionaux, cliquez sur <em>Create languages<\/em>. Nous serons ramen\u00e9s \u00e0 la page de configuration du projet. C&rsquo;est tout pour la configuration \u00e0 ce stade. Cliquez sur le bouton <em>Skip setup<\/em> pour continuer.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14584 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/skip-setup-btn-fpo2021-1024x654.png\" alt=\"Passer la configuration | Phrase\" width=\"1024\" height=\"654\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/skip-setup-btn-fpo2021-1024x654.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/skip-setup-btn-fpo2021-300x192.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/skip-setup-btn-fpo2021-768x490.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/skip-setup-btn-fpo2021-1536x981.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/skip-setup-btn-fpo2021-2048x1308.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\n\u00c0 ce stade, notre projet Phrase est pr\u00eat \u00e0 l&#8217;emploi. Tant que nous y sommes, obtenons un jeton d&rsquo;acc\u00e8s; nous en aurons besoin pour connecter notre projet Flutter au projet Phrase.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"obtenir-un-jeton-dacces-phrase\"><\/span>Obtenir un jeton d&rsquo;acc\u00e8s Phrase<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Pour g\u00e9n\u00e9rer un jeton d\u2019acc\u00e8s, dirigeons-nous pr\u00e8s du coin sup\u00e9rieur droit de l\u2019\u00e9cran o\u00f9 se trouve notre nom. Cliquez sur notre nom pour ouvrir un menu d\u00e9roulant avec une option <em>Access Tokens<\/em> et cliquez dessus.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14585 size-medium\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-tokens-menu-item-fpo2021-288x300.png\" alt=\"Jeton d&apos;acc\u00e8s | Phrase\" width=\"288\" height=\"300\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-tokens-menu-item-fpo2021-288x300.png 288w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-tokens-menu-item-fpo2021.png 438w\" sizes=\"auto, (max-width: 288px) 100vw, 288px\" \/><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14586 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-btn-fpo2021.png\" alt=\"G\u00e9n\u00e9ration d\u2019un nouveau jeton\u00a0| Phrase\" width=\"2358\" height=\"416\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-btn-fpo2021.png 2358w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-btn-fpo2021-300x53.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-btn-fpo2021-1024x181.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-btn-fpo2021-768x135.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-btn-fpo2021-1536x271.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-btn-fpo2021-2048x361.png 2048w\" sizes=\"auto, (max-width: 2358px) 100vw, 2358px\" \/><br \/>\nCela ouvre la page <em>Jetons d&rsquo;acc\u00e8s<\/em>, r\u00e9v\u00e9lant un bouton <em>G\u00e9n\u00e9rer un jeton<\/em>. Cliquez sur ce bouton pour ouvrir la bo\u00eete de dialogue <em>Generate Token<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14587 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-dialog-fpo2021-1024x650.png\" alt=\"Dialogue de g\u00e9n\u00e9ration de jeton | Phrase\" width=\"1024\" height=\"650\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-dialog-fpo2021-1024x650.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-dialog-fpo2021-300x190.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-dialog-fpo2021-768x488.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/generate-token-dialog-fpo2021.png 1276w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nNous devons juste donner \u00e0 notre jeton une note pour nous souvenir de la raison pour laquelle nous l&rsquo;avons cr\u00e9\u00e9. Nous voulons \u00e0 la fois les autorisations <em>lecture<\/em> et <em>\u00e9criture<\/em> pour notre projet, car nous allons faire une synchronisation bidirectionnelle entre notre projet et Phrase. Choisissez les options qui ont du sens pour votre projet et cliquez sur <em>Enregistrer<\/em> pour r\u00e9v\u00e9ler le jeton.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14588 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-token-created-fpo2021.png\" alt=\"Jeton r\u00e9v\u00e9l\u00e9\u00a0| Phrase\" width=\"2360\" height=\"604\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-token-created-fpo2021.png 2360w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-token-created-fpo2021-300x77.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-token-created-fpo2021-1024x262.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-token-created-fpo2021-768x197.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-token-created-fpo2021-1536x393.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/access-token-created-fpo2021-2048x524.png 2048w\" sizes=\"auto, (max-width: 2360px) 100vw, 2360px\" \/><\/p>\n<p>\u270b\ud83c\udffd <em>Avertissement \u00bb<\/em> Copiez le jeton dans un endroit s\u00fbr : une fois que vous quittez la page des jetons, vous ne pourrez plus acc\u00e9der au jeton depuis la console de Phrase.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"installation-du-cli\"><\/span>Installation du CLI<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Avec le jeton en main, nous pouvons nous rendre \u00e0 notre projet Flutter pour le connecter \u00e0 Phrase. Nous aurons besoin de Phrase CLI pour cela, alors assurez-vous de l&rsquo;installer. Je suis sur macOS et j&rsquo;aime utiliser le gestionnaire de paquets <a href=\"https:\/\/brew.sh\/\">Homebrew<\/a>, donc je vais prendre cette voie pour installer le CLI. Je vais simplement ex\u00e9cuter la commande suivante dans un terminal.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">brew install phrase\n<\/pre>\n<p>Si tout se passe bien, vous devriez obtenir quelque chose comme ceci\u00a0:<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14589 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/cli-install-success-fpo2021-1024x530.png\" alt=\"Configuration r\u00e9ussie du CLI | Phrase\" width=\"1024\" height=\"530\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/cli-install-success-fpo2021-1024x530.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/cli-install-success-fpo2021-300x155.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/cli-install-success-fpo2021-768x398.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/cli-install-success-fpo2021-1536x795.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/cli-install-success-fpo2021-2048x1061.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>\ud83d\udd17 <em>Ressources \u00bb<\/em> Si vous n&rsquo;\u00eates pas sur macOS ou si vous ne souhaitez pas utiliser Homebrew, consultez la <a href=\"https:\/\/phrase.com\/fr\/download\/\">documentation sur l&rsquo;interface CLI de Phrase<\/a> pour conna\u00eetre toutes les options d&rsquo;installation disponibles.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"connexion-de-notre-application-flutter-avec-phrase\"><\/span>Connexion de notre application Flutter avec Phrase<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Maintenant que nous avons install\u00e9 le Phrase CLI, nous pouvons connecter notre projet Phrase \u00e0 notre projet Flutter. Ouvrons une ligne de commande, naviguons \u00e0 la racine de notre projet Flutter et ex\u00e9cutons ce qui suit.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">Phrase init\n<\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14590 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/phrase-init-fpo2021-1024x866.png\" alt=\"Invite de jeton d&apos;acc\u00e8s API\u00a0| Phrase\" width=\"1024\" height=\"866\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/phrase-init-fpo2021-1024x866.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/phrase-init-fpo2021-300x254.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/phrase-init-fpo2021-768x650.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/phrase-init-fpo2021-1536x1299.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/phrase-init-fpo2021-2048x1732.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nApr\u00e8s avoir entr\u00e9 le jeton d&rsquo;acc\u00e8s que nous avons g\u00e9n\u00e9r\u00e9 plus t\u00f4t et cliqu\u00e9 sur <em>Enter<\/em>, nous serons invit\u00e9s \u00e0 s\u00e9lectionner notre projet Phrase.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14591 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-project-fpo2021-1024x866.png\" alt=\"S\u00e9lectionner notre projet Phrase | Phrase \" width=\"1024\" height=\"866\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-project-fpo2021-1024x866.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-project-fpo2021-300x254.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-project-fpo2021-768x650.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-project-fpo2021-1536x1299.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-project-fpo2021-2048x1732.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nEntrons le num\u00e9ro du projet appropri\u00e9 et appuyons sur <em>Enter<\/em>. On nous demandera ensuite le format \u00e0 utiliser. Si nous avons s\u00e9lectionn\u00e9 <em>ARB<\/em> lors de la cr\u00e9ation de notre projet Phrase dans la console Phrase, ce format devrait \u00eatre propos\u00e9 par d\u00e9faut, et nous pouvons simplement appuyer sur <em>Enter<\/em>. Sinon, nous pouvons s\u00e9lectionner <em>1.<\/em> (arb) dans la liste.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14592 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-format-fpo2021-1024x916.png\" alt=\"S\u00e9lectionner le bon format de fichier | Phrase\" width=\"1024\" height=\"916\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-format-fpo2021-1024x916.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-format-fpo2021-300x268.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-format-fpo2021-768x687.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-format-fpo2021-1536x1375.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/select-format-fpo2021-2048x1833.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nOn vous demandera maintenant d&rsquo;entrer les chemins de vos fichiers de traduction, relatifs \u00e0 la racine du projet. Ces chemins utilisent un espace r\u00e9serv\u00e9 sp\u00e9cial, <code>&lt;locale_name&gt;<\/code>, qui correspond aux codes de param\u00e8tres r\u00e9gionaux dans notre projet. Par exemple, <code>app_&lt;locale_name&gt;.arb<\/code> indiquera \u00e0 Phrase de s&rsquo;attendre \u00e0 des fichiers <code>app_en.arb<\/code> et <code>app_ar.arb<\/code>, puisque nous avons ajout\u00e9 ces deux param\u00e8tres r\u00e9gionaux \u00e0 notre projet Phrase.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14593 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/enter-file-paths-fpo2021-1024x866.png\" alt=\"Formats de fichiers attendus dans Phrase | Phrase\" width=\"1024\" height=\"866\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/enter-file-paths-fpo2021-1024x866.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/enter-file-paths-fpo2021-300x254.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/enter-file-paths-fpo2021-768x650.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/enter-file-paths-fpo2021-1536x1299.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/enter-file-paths-fpo2021-2048x1732.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nPour les chemins source et cible, entrons <code>.\/lib\/l10n\/app_&lt;locale_name&gt;.arb<\/code>. Vous vous souviendrez que cela correspond au chemin du fichier de traduction dans notre projet Flutter.<br \/>\nEnfin, une invite vous demandera si vous souhaitez charger vos fichiers de traduction sur Phrase pour la premi\u00e8re fois. Pour ce faire, saisissez <em>y<\/em>, puis appuyez sur <em>Enter<\/em>.<\/p>\n<p>\ud83d\uddd2 <em>Remarque \u00bb<\/em> Si vous manquez l&rsquo;\u00e9tape de chargement lors de l&rsquo;initialisation, ex\u00e9cutez simplement <code>phrase push<\/code> depuis la ligne de commande pour charger les fichiers.<\/p>\n<p>\u00c0 ce stade, si tout s&rsquo;est bien pass\u00e9, un fichier <code>.phrase.yml<\/code> sera apparu \u00e0 la racine de notre projet.<\/p>\n<p>\u270b\ud83c\udffd <em>Avertissement \u00bb<\/em> Il est plus s\u00fbr d&rsquo;ajouter <code>.phrase.yml<\/code> \u00e0 notre <code>.gitignore<\/code> pour \u00e9viter que les secrets d&rsquo;acc\u00e8s au projet ne se retrouvent dans notre d\u00e9p\u00f4t Git.<\/p>\n<p>Si vous avez choisi l&rsquo;option de chargement plus t\u00f4t, vous pouvez naviguer vers votre projet Phrase, aller sous <em>Languages<\/em> et ouvrir une langue pour voir vos traductions pr\u00eates \u00e0 \u00eatre modifi\u00e9es.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14594 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/langs-in-phrase-console-fpo2021-1024x777.png\" alt=\"Menu Phrase Over the Air | Phrase\" width=\"1024\" height=\"777\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/langs-in-phrase-console-fpo2021-1024x777.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/langs-in-phrase-console-fpo2021-300x228.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/langs-in-phrase-console-fpo2021-768x583.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/langs-in-phrase-console-fpo2021-1536x1166.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/langs-in-phrase-console-fpo2021-2048x1554.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<h2><span class=\"ez-toc-section\" id=\"traductions-over-the-air-avec-phrase\"><\/span>Traductions over-the-air avec Phrase<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>\u00c0 ce stade, notre projet peut synchroniser les traductions dans les deux sens avec Phrase. Cependant, vous devriez toujours cr\u00e9er une nouvelle version de votre application mobile \u00e0 chaque mise \u00e0 jour de traduction. Cela signifie attendre l&rsquo;approbation de l&rsquo;application et que les t\u00e9l\u00e9phones de vos utilisateurs se mettent \u00e0 jour vers la derni\u00e8re version de l&rsquo;application. Il existe une meilleure fa\u00e7on : Over-the-air.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"comment-fonctionne-phrase-ota\"><\/span>Comment fonctionne Phrase OTA<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>En r\u00e9sum\u00e9, apr\u00e8s avoir connect\u00e9 votre projet \u00e0 Phrase OTA et d\u00e9ploy\u00e9 une nouvelle version de votre application avec OTA activ\u00e9, voici ce qui se passe\u00a0:<\/p>\n<ol>\n<li>Un utilisateur ouvre votre application, d\u00e9clenchant une r\u00e9cup\u00e9ration OTA de la traduction en arri\u00e8re-plan.<\/li>\n<li>La prochaine fois que l&rsquo;utilisateur ouvre l&rsquo;application, il voit vos nouvelles traductions. Il n&rsquo;\u00e9tait pas n\u00e9cessaire de mettre \u00e0 jour vers une nouvelle version de l&rsquo;application pour ce faire. Cela se produit \u00ab\u00a0over-the-air\u00a0\u00bb.<\/li>\n<\/ol>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14595 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-infographic-fpo2021.png\" alt=\"Flux de travail over-the-air | Phrase\" width=\"547\" height=\"712\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-infographic-fpo2021.png 547w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-infographic-fpo2021-230x300.png 230w\" sizes=\"auto, (max-width: 547px) 100vw, 547px\" \/><br \/>\nPlut\u00f4t g\u00e9nial, pas vrai\u00a0? Alors, qu&rsquo;attendez-vous pour connecter votre projet \u00e0 Phrase OTA\u00a0?<\/p>\n<h3><span class=\"ez-toc-section\" id=\"installation-du-sdk-phrase-flutter\"><\/span>Installation du SDK Phrase Flutter<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Tout d&rsquo;abord, nous allons ajouter le package Phrase Flutter \u00e0 notre projet en mettant \u00e0 jour notre <code>pubspec.yaml<\/code>.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-group=\"9e65fccd-b284-495d-9d9d-622abd88a609\" data-enlighter-title=\"pubspec.yaml\" data-enlighter-highlight=\"9\" data-enlighter-linenumbers=\"false\"># ...\ndependencies:\n  flutter:\n    sdk: flutter\n  flutter_localizations:\n    sdk: flutter\n  intl: ^0.17.0\n  phrase: ^1.0.0\n# ...\n<\/pre>\n<p>Notre IDE devrait avoir install\u00e9 le paquet automatiquement. Sinon, vous pouvez ouvrir une ligne de commande, naviguer jusqu&rsquo;\u00e0 la racine de votre projet et ex\u00e9cuter ce qui suit.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">flutter pub get\n<\/pre>\n<p>Le SDK Phrase doit g\u00e9n\u00e9rer du code pour vous. Pour lui demander de g\u00e9n\u00e9rer le code, ex\u00e9cutez la commande suivante depuis la racine de votre projet.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-linenumbers=\"false\">flutter pub run phrase\n<\/pre>\n<p>Si tout s&rsquo;est bien pass\u00e9, vous verrez un joli message de succ\u00e8s.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14596 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/flutter-pub-run-phrase-success-fpo2021-1024x64.png\" alt=\"Message de succ\u00e8s\u00a0| Phrase\" width=\"1024\" height=\"64\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/flutter-pub-run-phrase-success-fpo2021-1024x64.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/flutter-pub-run-phrase-success-fpo2021-300x19.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/flutter-pub-run-phrase-success-fpo2021-768x48.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/flutter-pub-run-phrase-success-fpo2021.png 1184w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>\u270b\ud83c\udffd <em>Avertissement \u00bb<\/em> Le package Flutter de Phrase installe un plug-in Flutter, donc vous aurez besoin de CocoaPods install\u00e9 et \u00e0 jour si vous voulez ex\u00e9cuter votre projet Flutter sur iOS.<\/p>\n<p>\ud83d\udd17 <em>Ressources \u00bb<\/em> Plus d&rsquo;informations sur notre SDK Flutter sont disponibles dans notre <a href=\"https:\/\/support.phrase.com\/hc\/en-us\/articles\/5804059067804-Over-the-Air-Strings\">Centre d\u2019aide<\/a>.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"creer-une-distribution\"><\/span>Cr\u00e9er une distribution<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Pour rendre les traductions mises \u00e0 jour disponibles pour votre application over-the-air, vous devrez disposer d&rsquo;une distribution OTA. Connectez-vous \u00e0 votre console Phrase et rendez-vous sur <em>Over-the-air<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14597 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-menu-item-fpo2021.png\" alt=\"Menu over-the-air | Phrase\" width=\"2372\" height=\"448\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-menu-item-fpo2021.png 2372w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-menu-item-fpo2021-300x57.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-menu-item-fpo2021-1024x193.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-menu-item-fpo2021-768x145.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-menu-item-fpo2021-1536x290.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/ota-menu-item-fpo2021-2048x387.png 2048w\" sizes=\"auto, (max-width: 2372px) 100vw, 2372px\" \/><br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14598 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-distribution-btn-fpo2021-1024x240.png\" alt=\"Cr\u00e9ation d&apos;une distribution over-the-air | Phrase\" width=\"1024\" height=\"240\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-distribution-btn-fpo2021-1024x240.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-distribution-btn-fpo2021-300x70.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-distribution-btn-fpo2021-768x180.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-distribution-btn-fpo2021-1536x360.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/create-distribution-btn-fpo2021-2048x480.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nCela ouvrira la page <em>Over the Air<\/em> avec un joli bouton <em>Cr\u00e9er une distribution<\/em>. Cliquez sur le bouton pour ouvrir la bo\u00eete de dialogue <em>Add distribution<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14599 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-distrubtion-dialog-fpo2021-745x1024.png\" alt=\"Bo\u00eete de dialogue Add distribution | Phrase\" width=\"745\" height=\"1024\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-distrubtion-dialog-fpo2021-745x1024.png 745w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-distrubtion-dialog-fpo2021-218x300.png 218w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-distrubtion-dialog-fpo2021-768x1055.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-distrubtion-dialog-fpo2021-1118x1536.png 1118w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-distrubtion-dialog-fpo2021.png 1274w\" sizes=\"auto, (max-width: 745px) 100vw, 745px\" \/><br \/>\nVous donnerez un nom \u00e0 votre distribution et la connecterez au projet Phrase que vous avez cr\u00e9\u00e9 pr\u00e9c\u00e9demment. La seule plateforme que vous couvrez ici est <em>Flutter<\/em>, donc vous s\u00e9lectionnerez cette option comme unique possibilit\u00e9 sous <em>Plateformes<\/em>. Laissez les param\u00e8tres par d\u00e9faut sous <em>Param\u00e8tres<\/em>, car ils vous conviennent. N&rsquo;h\u00e9sitez pas \u00e0 les modifier pour r\u00e9pondre \u00e0 vos besoins.<\/p>\n<p>\ud83d\uddd2 <em>Remarque \u00bb<\/em> Vous ne pouvez pas modifier les <em>Plateformes<\/em> que votre distribution cible apr\u00e8s l&rsquo;avoir cr\u00e9\u00e9e. Vous pouvez cependant modifier la distribution <em>Settings<\/em> \u00e0 tout moment.<\/p>\n<p>Cliquez sur <em>Save<\/em> lorsque vous \u00eates satisfait de votre configuration pour valider vos modifications et ouvrir la page des d\u00e9tails de la distribution.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14600 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-created-page-fpo2021-1024x692.png\" alt=\"Page de d\u00e9tail de la distribution | Phrase\" width=\"1024\" height=\"692\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-created-page-fpo2021-1024x692.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-created-page-fpo2021-300x203.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-created-page-fpo2021-768x519.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-created-page-fpo2021-1536x1038.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-created-page-fpo2021-2048x1383.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nLes trois cl\u00e9s, <em>Distribution ID<\/em>, <em>Development Secret<\/em> et <em>Production Secret<\/em>, sont essentielles pour connecter votre projet Flutter \u00e0 cette distribution OTA, et vous les utiliserez dans un instant.<\/p>\n<p>\ud83d\uddd2 <em>Remarque \u00bb<\/em> Ne vous inqui\u00e9tez pas : vous pouvez acc\u00e9der aux cl\u00e9s de distribution \u00e0 tout moment.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"creer-une-version-de-developpement\"><\/span>Cr\u00e9er une version de d\u00e9veloppement<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Maintenant que vous avez une distribution, vous aurez besoin d&rsquo;une <em>release<\/em> OTA. Une version est simplement un instantan\u00e9 des mises \u00e0 jour de traduction que vous souhaitez rendre disponibles \u00e0 vos utilisateurs d\u2019application mobile.<br \/>\nTout d&rsquo;abord, mettez \u00e0 jour vos traductions afin d&rsquo;avoir <em>quelque chose<\/em> \u00e0 publier. Rendez-vous dans <em>Projects \u279e &lt;Notre projet&gt; \u279e Languages \u279e en<\/em>, et mettez \u00e0 jour la cha\u00eene <code>appTitle<\/code>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14607 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updating-app-title-fpo2021-1024x765.png\" alt=\"Mettre \u00e0 jour la cha\u00eene apptitle\u00a0| Phrase\" width=\"1024\" height=\"765\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updating-app-title-fpo2021-1024x765.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updating-app-title-fpo2021-300x224.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updating-app-title-fpo2021-768x574.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updating-app-title-fpo2021-1536x1147.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updating-app-title-fpo2021-2048x1530.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nMaintenant, vous pouvez cr\u00e9er une version. Allez sous <em> \u279e Over-the-Air <\/em> et cliquez sur le nom de votre distribution.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14601 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-btn-fpo2021-1024x692.png\" alt=\"Cr\u00e9er une version dans le menu des d\u00e9tails de distribution | Phrase\" width=\"1024\" height=\"692\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-btn-fpo2021-1024x692.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-btn-fpo2021-300x203.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-btn-fpo2021-768x519.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-btn-fpo2021-1536x1038.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-btn-fpo2021-2048x1383.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nLe bouton <em>Create release<\/em> en bas de la page ouvrira la bo\u00eete de dialogue <em>Add release<\/em>.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14602 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-dialog-fpo2021-919x1024.png\" alt=\"Fen\u00eatre de dialogue Ajouter une version\u00a0| Phrase\" width=\"919\" height=\"1024\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-dialog-fpo2021-919x1024.png 919w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-dialog-fpo2021-269x300.png 269w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-dialog-fpo2021-768x856.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/add-release-dialog-fpo2021.png 1310w\" sizes=\"auto, (max-width: 919px) 100vw, 919px\" \/><br \/>\nPour plus de simplicit\u00e9, nous allons rendre notre version accessible \u00e0 tous les utilisateurs. C&rsquo;est le param\u00e8tre par d\u00e9faut, donc vous n&rsquo;avez pas besoin de modifier quoi que ce soit dans la bo\u00eete de dialogue. Cependant, il est recommand\u00e9 d&rsquo;ajouter une description. Une fois satisfait, cliquez sur <em>Save<\/em> pour cr\u00e9er la version.<br \/>\nNotez que la section <em>Releases<\/em> en bas de la page comporte une nouvelle ligne avec une version non publi\u00e9e. Publier une version la rend accessible \u00e0 vos utilisateurs de production, donc vous voudrez probablement la laisser non publi\u00e9e pendant vos tests.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14650 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-created-fpo2021-1024x175.png\" alt=\"Version non publi\u00e9e | Phrase\" width=\"1024\" height=\"175\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-created-fpo2021-1024x175.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-created-fpo2021-300x51.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-created-fpo2021-768x131.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-created-fpo2021-1536x262.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-created-fpo2021-2048x350.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<p>\u270b\ud83c\udffd <em>Avertissement \u00bb<\/em> M\u00eame pour votre environnement de d\u00e9veloppement, <em>vous devez toujours cr\u00e9er une version<\/em> pour voir les mises \u00e0 jour de traduction Phrase refl\u00e9t\u00e9es over-the-air dans votre application.<\/p>\n<h3><span class=\"ez-toc-section\" id=\"ajout-de-phrase-a-maindart\"><\/span>Ajout de Phrase \u00e0 main.dart<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Maintenant que vous avez une version OTA visible dans votre application, terminez la connexion de votre application \u00e0 Phrase OTA. Mettez \u00e0 jour votre <code>main.dart<\/code> pour initialiser le SDK Phrase et assurez-vous d&rsquo;utiliser Phrase lors de l&rsquo;acc\u00e8s \u00e0 vos traductions.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"77511f2a-ce07-420d-b954-78417c99c476\" data-enlighter-title=\"lib\/main.dart\" data-enlighter-highlight=\"2,4,8,9,10,11,12,13,23,24\">import 'package:flutter\/material.dart';\nimport 'package:phrase\/phrase.dart';\nimport 'package:flutter_gen\/gen_l10n\/app_localizations.dart';\nimport 'package:flutter_gen\/gen_l10n\/phrase_localizations.dart';\nimport 'package:flutter_phrase_ota_2021\/features\/hereos\/hero_list.dart';\nvoid main() {\n  Phrase.setup(\n    Identifiant de diffusion\n    '44****************************ed',\n    \/\/ Cl\u00e9 secr\u00e8te de d\u00e9veloppement\n    'in***************************************no',\n  );\n  runApp(MyApp());\n}\nclass MyApp extends StatelessWidget {\n  @override\n  Widget build(BuildContext context) {\n    return MaterialApp(\n      onGenerateTitle: (context) =&gt; AppLocalizations.of(context)!.appTitle,\n      D\u00e9l\u00e9gu\u00e9s de localisation\u00a0: PhraseLocalizations.localizationsDelegates,\n      Langues prises en charge\u00a0: PhraseLocalizations.supportedLocales ,\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      Itin\u00e9raire initial : '\/',\n      routes: {\n        '\/': (context) =&gt;\n            HeroList(title: AppLocalizations.of(context)!.appTitle\n      },\n    );\n  }\n}\n<\/pre>\n<p>C&rsquo;est tout ce que nous avons \u00e0 faire. Nous pouvons continuer \u00e0 acc\u00e9der \u00e0 nos traductions comme d&rsquo;habitude avec <code>AppLocalizations.of(context)<\/code>. Le SDK Phrase aura modifi\u00e9 les choses en coulisses afin que nos traductions soient extraites de nos mises \u00e0 jour OTA lorsque cela est appropri\u00e9.<br \/>\nNous allons maintenant ex\u00e9cuter l&rsquo;application. Veuillez noter la console de d\u00e9bogage.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14603 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/console-log-ota-ok-fpo2021.png\" alt=\"Message de d\u00e9bogage\u00a0| Phrase\" width=\"670\" height=\"80\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/console-log-ota-ok-fpo2021.png 670w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/console-log-ota-ok-fpo2021-300x36.png 300w\" sizes=\"auto, (max-width: 670px) 100vw, 670px\" \/><br \/>\nPhrase n&rsquo;a pas trouv\u00e9 de cache de traductions OTA, c&rsquo;est normal. Il en a cr\u00e9\u00e9 un et a r\u00e9cup\u00e9r\u00e9 nos traductions over-the-air pour le remplir. En attendant, Phrase a utilis\u00e9 nos traductions locales, donc nous n&rsquo;avons constat\u00e9 aucun changement dans l&rsquo;application. Encore une fois, c&rsquo;est normal.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14604 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before_ota_release-fpo2021-544x1024.png\" alt=\"Appli d\u00e9mo | Phrase\" width=\"544\" height=\"1024\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before_ota_release-fpo2021-544x1024.png 544w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before_ota_release-fpo2021-159x300.png 159w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before_ota_release-fpo2021-768x1445.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before_ota_release-fpo2021-816x1536.png 816w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/before_ota_release-fpo2021.png 1044w\" sizes=\"auto, (max-width: 544px) 100vw, 544px\" \/><br \/>\nMais ces nouvelles traductions brillantes attendent en coulisses et appara\u00eetront lors du prochain lancement de l&rsquo;application. Vous ne me croyez pas ? Relancez l&rsquo;application.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14605 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/hot-reload-btn-fpo2021.png\" alt=\"bouton de relance | Phrase\" width=\"462\" height=\"98\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/hot-reload-btn-fpo2021.png 462w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/hot-reload-btn-fpo2021-300x64.png 300w\" sizes=\"auto, (max-width: 462px) 100vw, 462px\" \/><\/p>\n<p style=\"text-align: center\"><em>C&rsquo;est un <\/em>red\u00e9marrage complet, <em>pas un rechargement \u00e0 chaud<\/em><\/p>\n<p>Veuillez noter que la traduction mise \u00e0 jour de <code>appTitle<\/code> est maintenant affich\u00e9e.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14606 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updated-app-title-fpo2021-544x1024.png\" alt=\"Application de d\u00e9monstration | Phrase\" width=\"544\" height=\"1024\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updated-app-title-fpo2021-544x1024.png 544w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updated-app-title-fpo2021-159x300.png 159w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updated-app-title-fpo2021-768x1445.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updated-app-title-fpo2021-816x1536.png 816w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/en-updated-app-title-fpo2021.png 1044w\" sizes=\"auto, (max-width: 544px) 100vw, 544px\" \/><br \/>\nNous n&rsquo;avons pas eu besoin de faire un <code>phrase pull<\/code> pour obtenir ces traductions dans notre application.<\/p>\n<p>\u270b\ud83c\udffd <em>Avertissement\u00a0\u00bb<\/em> Tout comme le package de localisations Flutter, le SDK Flutter de Phrase peut perturber votre \u00e9diteur de code avec des fichiers et des jetons apparemment manquants. Essayez toujours l\u2019option <em>Debug anyway<\/em> lorsque vous ex\u00e9cutez l\u2019application apr\u00e8s des erreurs comme celle-ci pour v\u00e9rifier si votre application fonctionne correctement. Si c&rsquo;est le cas, vous n&rsquo;avez probablement rien \u00e0 craindre, et un ou deux red\u00e9marrages de l&rsquo;\u00e9diteur de code devraient faire dispara\u00eetre les erreurs. C&rsquo;est juste un effet secondaire malheureux de la g\u00e9n\u00e9ration de code en ce moment, mais il n&rsquo;y a pas de r\u00e9el dommage.<\/p>\n<p>L&rsquo;OTA est d\u00e9sormais configur\u00e9 dans notre projet\u00a0! Hourra \ud83d\ude80 !<\/p>\n<h3><span class=\"ez-toc-section\" id=\"cacher-nos-cles-secretes\"><\/span>Cacher nos cl\u00e9s secr\u00e8tes<span class=\"ez-toc-section-end\"><\/span><\/h3>\n<p>Nous ne voulons probablement pas que nos secrets de distribution OTA se trouvent dans notre d\u00e9p\u00f4t Git. Il serait \u00e9galement agr\u00e9able que notre application utilise le secret appropri\u00e9 en fonction de l&rsquo;environnement dans lequel elle s&rsquo;ex\u00e9cute (d\u00e9veloppement ou production). Nous pouvons r\u00e9soudre ces deux probl\u00e8mes avec un petit module de configuration et un bon vieux fichier <code>.env<\/code>.<br \/>\nCommen\u00e7ons par installer un petit paquet qui g\u00e8re le chargement et l&rsquo;analyse des fichiers <code>.env<\/code> pour nous. Le package en question est <a href=\"https:\/\/pub.dev\/packages\/flutter_dotenv\">flutter_dotenv<\/a>, et nous allons l&rsquo;ajouter \u00e0 notre <code>pubspec.yaml<\/code> pour l&rsquo;installer.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"yaml\" data-enlighter-group=\"70cfbda4-9591-4ec6-8148-46eb28ffd1bc\" data-enlighter-title=\"pubspec.yaml\" data-enlighter-highlight=\"10\" data-enlighter-linenumbers=\"false\"># ...\ndependencies:\n  flutter:\n    sdk: flutter\n  flutter_localizations:\n    sdk: flutter\n  intl: ^0.17.0\n  phrase: ^1.0.0\n  flutter_dotenv: ^5.0.0\n# ...\n<\/pre>\n<h4>Ajout d&rsquo;une classe .env<\/h4>\n<p>Avec <code>flutter_dotenv<\/code> install\u00e9, ajoutons un fichier <code>.env<\/code> \u00e0 la racine de notre projet pour abriter les cl\u00e9s de notre application.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"2180d9b9-d67d-4e9f-9b40-d0eb25e37639\" data-enlighter-title=\".env\">PHRASE_OTA_DISTRIBUTION_ID=44************************ed\nPHRASE_OTA_DEV_SECRET=in***********************************no\nPHRASE_OTA_PRODUCTION_SECRET=EN***********************************gs\n<\/pre>\n<p>Vous vous souviendrez que nous obtenons nos cl\u00e9s de distribution \u00e0 partir de la page des d\u00e9tails de distribution sur la console Phrase.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14615 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-keys-fpo2021-1024x692.png\" alt=\"Page des d\u00e9tails de la distribution sur la console Phrase | Phrase\" width=\"1024\" height=\"692\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-keys-fpo2021-1024x692.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-keys-fpo2021-300x203.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-keys-fpo2021-768x519.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-keys-fpo2021-1536x1038.png 1536w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/distribution-keys-fpo2021-2048x1383.png 2048w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nNous devons ajouter le fichier <code>.env<\/code> \u00e0 notre liste d&rsquo;actifs (\u00ab\u00a0liste\u00a0\u00bb) dans <code>pubspec.yaml<\/code> afin qu&rsquo;il soit disponible pour notre application.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"c4e3d8e4-a6e9-4e4c-9b04-900c6b6e7513\" data-enlighter-title=\"pubspec.yaml\" data-enlighter-highlight=\"4\"># ...\n  assets:\n    - .env\n    - assets\/images\/placeholder.jpg\n    - assets\/images\/alan_turing.jpg\n## ...\n<\/pre>\n<p>\u270b\ud83c\udffd <em>Avertissement \u00bb<\/em> Assurez-vous d&rsquo;ajouter votre fichier <code>.env<\/code> \u00e0 <code>.gitignore<\/code> pour qu&rsquo;il ne soit pas inclus dans votre d\u00e9p\u00f4t Git.<\/p>\n<h4>Une petite classe Config<\/h4>\n<p>Maintenant, cr\u00e9ons une petite classe wrapper qui charge le fichier <code>.env<\/code> et nous donne acc\u00e8s aux cl\u00e9s Phrase OTA qu&rsquo;il contient.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"b9407cf9-6699-4018-b89a-0d2bf4a96f02\" data-enlighter-title=\"lib\/services\/config\/config.dart\">import 'package:flutter\/foundation.dart';\nimport 'package:flutter_dotenv\/flutter_dotenv.dart';\nclass Config {\n  static const String fileName = '.env';\n  static Future load() async =&gt; await dotenv.load(fileName: fileName);\n  static String? get(String key) =&gt; dotenv.env[key];\n  static String? get phraseOtaDistributionId =&gt;\n      get('PHRASE_OTA_DISTRIBUTION_ID');\n  \/\/ kDebugMode and kRelease mode are constants\n  \/\/ built into foundation.dart (imported above)\n  static String? get phraseOtaSecret {\n    if (kDebugMode) {\n      return get('PHRASE_OTA_DEV_SECRET');\n    } else if (kReleaseMode) {\n      return get('PHRASE_OTA_PRODUCTION_SECRET');\n    }\n  }\n}\n<\/pre>\n<p>Nous avons maintenant une petite API de configuration propre pour charger et avoir acc\u00e8s aux cl\u00e9s secr\u00e8tes de notre application.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"91114c1a-605c-4d0e-a681-b0ce3c6bdce6\" data-enlighter-title=\"lib\/main.dart\" data-enlighter-highlight=\"5,8,9,10,11,14,15\">import 'package:flutter\/material.dart';\nimport 'package:phrase\/phrase.dart';\nimport 'package:flutter_gen\/gen_l10n\/app_localizations.dart';\nimport 'package:flutter_gen\/gen_l10n\/phrase_localizations.dart';\nimport 'package:flutter_phrase_ota_2021\/services\/config\/config.dart';\nimport 'package:flutter_phrase_ota_2021\/features\/hereos\/hero_list.dart';\n\/\/ Le chargement du fichier .env est une op\u00e9ration asynchrone,\n\/\/ donc nous devons rendre notre fonction main() asynchrone.\nFuture&lt;void&gt; main() async {\n  await Config.load();\n  Phrase.setup(\n    Config.phraseOtaDistributionId!,\n    Config.phraseOtaSecret!,\n  );\n  runApp(MyApp());\n}\nclass MyApp extends StatelessWidget {\n  \/\/ ...\n}\n<\/pre>\n<p>Notre application utilisera maintenant automatiquement le secret de d\u00e9veloppement OTA en mode d\u00e9bogage, et le secret de production en mode production. Pratique. \ud83d\ude09<\/p>\n<h2><span class=\"ez-toc-section\" id=\"creation-dune-version-de-production\"><\/span>Cr\u00e9ation d&rsquo;une version de production<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Il ne serait pas tr\u00e8s utile d&rsquo;avoir des traductions qui arrivent sur nos machines de d\u00e9veloppement over-the-air et pas pour nos utilisateurs. Une fois que nous sommes satisfaits d&rsquo;une version, nous pouvons la publier dans notre application pour le b\u00e9n\u00e9fice de nos utilisateurs.<br \/>\nVoici une version release\/production de notre application d\u00e9ploy\u00e9e sur un appareil physique.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14608 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-no-ota-fpo2021-618x1024.png\" alt=\"Application de d\u00e9monstration | Phrase\" width=\"618\" height=\"1024\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-no-ota-fpo2021-618x1024.png 618w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-no-ota-fpo2021-181x300.png 181w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-no-ota-fpo2021-768x1273.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-no-ota-fpo2021-927x1536.png 927w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-no-ota-fpo2021.png 1020w\" sizes=\"auto, (max-width: 618px) 100vw, 618px\" \/><br \/>\nRappelez-vous que notre version OTA a mis \u00e0 jour le titre de l&rsquo;application pour qu&rsquo;il soit \u00ab Comp-Sci Champs \u00bb. Nous ne voyons pas cette mise \u00e0 jour ici car notre version OTA n&rsquo;est pas publi\u00e9e, donc elle n&rsquo;est pas disponible pour la mise en production.<br \/>\nNous allons lib\u00e9rer la b\u00eate. Dans la console Phrase, rendez-vous sous<em>Over the Air<\/em> et cliquez sur le nom de notre distribution pour ouvrir la page des d\u00e9tails. En faisant d\u00e9filer vers le bas, nous trouverons la section <em>Releases<\/em> contenant une ligne avec notre version, et un joli bouton <em>Publish<\/em> pr\u00eat \u00e0 \u00eatre cliqu\u00e9.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14609 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/publish-btn-fpo2021-1024x287.png\" alt=\"Publication des champions de l&apos;informatique | Phrase\" width=\"1024\" height=\"287\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/publish-btn-fpo2021-1024x287.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/publish-btn-fpo2021-300x84.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/publish-btn-fpo2021-768x216.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/publish-btn-fpo2021.png 1496w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><br \/>\nLorsque nous cliquons sur <em>Publish,<\/em>, nous obtenons une bo\u00eete de dialogue de confirmation ; en confirmant, vous obtenez un message indiquant que la version a \u00e9t\u00e9 publi\u00e9e avec succ\u00e8s.<\/p>\n<p>\u270b\ud83c\udffd <em>Avertissement \u00bb<\/em> Pour Android, nous devons mettre \u00e0 jour notre manifeste d&rsquo;application pour permettre l&rsquo;acc\u00e8s \u00e0 Internet en mode release. Sinon, le SDK Phrase ne pourra pas r\u00e9cup\u00e9rer nos versions OTA en mode de publication\u00a0\/ production.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-group=\"61094297-0320-48d0-b1f9-e8463c6fabeb\" data-enlighter-title=\"android\/app\/src\/main\/AndroidManifest.xml\" data-enlighter-highlight=\"4\">&lt;manifest xmlns:android=\"http:\/\/schemas.android.com\/apk\/res\/android\"\n    package=\"com.example.flutter_phrase_ota_2021\"&gt;\n    &lt;uses-permission android:name=\"android.permission.INTERNET\"\/&gt;\n   &lt;application\n     &lt;!-- ... --&gt;\n<\/pre>\n<p>Maintenant, lorsque nos utilisateurs red\u00e9marrent notre application, ils recevront les nouvelles traductions livr\u00e9es directement depuis Phrase. Pas de gestion des versions d&rsquo;application, pas d&rsquo;attente pour Apple. D\u00e9ploiement semblable au web pour les applications mobiles \ud83c\udfc4.<br \/>\n<img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14610 size-large\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-after-ota-fpo2021-618x1024.png\" alt=\"D\u00e9mo de l\u2019application termin\u00e9e | Phrase\" width=\"618\" height=\"1024\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-after-ota-fpo2021-618x1024.png 618w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-after-ota-fpo2021-181x300.png 181w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-after-ota-fpo2021-768x1273.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-after-ota-fpo2021-927x1536.png 927w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/07\/release-app-after-ota-fpo2021.png 1020w\" sizes=\"auto, (max-width: 618px) 100vw, 618px\" \/><br \/>\n\u00c0 noter\u00a0:<\/p>\n<ul>\n<li>Phrase OTA ne r\u00e9cup\u00e9rera que les traductions pour la <em>langue active<\/em> afin de pr\u00e9server la bande passante. Cela devrait \u00eatre transparent pour nos utilisateurs, mais bon \u00e0 savoir pour nous,\u00a0d\u00e9veloppeurs.<\/li>\n<li>Phrase identifie notre environnement d&rsquo;application comme d\u00e9veloppement ou production via le secret de d\u00e9veloppement ou le secret de production, respectivement. Cela peut \u00eatre pratique en d\u00e9veloppement puisque nous pouvons tester les versions de production publi\u00e9es en rempla\u00e7ant temporairement notre cl\u00e9.<\/li>\n<\/ul>\n<p>\ud83d\udd17 <em>Ressources\u00a0\u00bb<\/em> <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-phrase-ota-2021\">Obtenez le code complet de notre application de d\u00e9monstration<\/a> depuis notre d\u00e9p\u00f4t GitHub compagnon.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"et-voila\"><\/span>Et voil\u00e0\u00a0!<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Les traductions over-the-air de Phrase peuvent vous faire gagner un temps pr\u00e9cieux en publiant de nouvelles traductions directement aupr\u00e8s des utilisateurs de vos applications. Avec OTA, nous avons \u00e9galement l&rsquo;avantage suppl\u00e9mentaire de sauter l&rsquo;approbation de l&rsquo;App Store (juste pour une mise \u00e0 jour de texte). Et Phrase offre bien plus que la technologie OTA\u00a0: nombreux formats de fichiers de traduction pris en charge, traduction automatique, synchronisation avec GitHub, GitLab et Bitbucket, branchement et versionnage, etc. Phrase permet de rationaliser le processus de localisation de votre application de bout en bout. D\u00e9couvrez toutes les <a href=\"https:\/\/phrase.com\/fr\/solutions\/\">fonctionnalit\u00e9s de Phrase<\/a> et <a href=\"https:\/\/eu.phrase.com\/idm-ui\/signup\">inscrivez-vous<\/a> pour un essai gratuit de 14\u00a0jours.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Arr\u00eatez d&rsquo;attendre l&rsquo;approbation du magasin d&rsquo;applications mobiles. Avec Phrase Over the Air, g\u00e9n\u00e9rez du nouveau contenu pour les utilisateurs de vos applications Flutter instantan\u00e9ment \u00e0 travers le monde.<\/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-133356","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\/133356","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=133356"}],"version-history":[{"count":4,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/posts\/133356\/revisions"}],"predecessor-version":[{"id":136284,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/posts\/133356\/revisions\/136284"}],"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=133356"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/fr\/wp-json\/wp\/v2\/categories?post=133356"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}