{"id":133330,"date":"2021-04-06T09:38:00","date_gmt":"2021-04-06T07:38:00","guid":{"rendered":"https:\/\/phrase.com\/blog\/posts\/la-guia-definitiva-para-la-localizacion-de-flutter\/"},"modified":"2026-02-26T16:51:07","modified_gmt":"2026-02-26T15:51:07","slug":"flutter-localization","status":"publish","type":"post","link":"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/","title":{"rendered":"Gu\u00eda definitiva para la localizaci\u00f3n Flutter"},"content":{"rendered":"\n\n<p><a href=\"https:\/\/flutter.dev\/\">Flutter<\/a>, el marco de aplicaci\u00f3n multiplataforma de Google, no solo ha ganado popularidad en el \u00e1mbito del desarrollo de aplicaciones m\u00f3viles, sino que tambi\u00e9n se ha ramificado sin problemas a la web, Linux, macOS y Windows. M\u00e1s all\u00e1 de eso, Flutter es incre\u00edblemente r\u00e1pido y trabajar con \u00e9l es todo un placer.<\/p>\n\n\n\n<p>Cuando se trata de la internacionalizaci\u00f3n de aplicaciones Flutter, el equipo de Flutter ha creado una s\u00f3lida soluci\u00f3n integrada de localizaci\u00f3n. En este tutorial, prepararemos y configuraremos las bibliotecas de internacionalizaci\u00f3n de Flutter, las usaremos para cargar y mostrar traducciones y trabajaremos en el formato de fecha\/hora, entre otros temas de localizaci\u00f3n.<\/p>\n\n\n\n<p>\ud83e\udd3f\u00a0<em>Profundiza m\u00e1s \u00bb<\/em> El paquete de localizaci\u00f3n de Flutter nativo se basa en el primer paquete de <a href=\"https:\/\/pub.dev\/packages\/intl\">Dart intl<\/a>.<\/p>\n\n\n\n\n\n<div class=\"wp-block-group acf-blog-cta has-phrase-green-background-color has-background has-global-padding is-layout-constrained wp-block-group-is-layout-constrained\">\n\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-7fc3d43a wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-vertically-aligned-top is-layout-flow wp-block-column-is-layout-flow\">\n<figure class=\"wp-block-image size-large is-style-not-rounded\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"806\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-1024x806.png\" alt=\"Interfaz visual de gesti\u00f3n de cadenas | Phrase\" class=\"wp-image-854\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-1024x806.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-300x236.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero-768x605.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2022\/08\/String_Hero.png 1260w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n<\/div>\n\n\n\n<div class=\"wp-block-column is-vertically-aligned-center is-layout-flow wp-block-column-is-layout-flow\">\n\n\n<p class=\"subhead has-blue-color has-text-color has-link-color wp-elements-52a8393fcfb59d29e0f5944c62dedea2\" style=\"text-transform:uppercase\">Phrase Strings<\/p>\n\n\n\n<p class=\"has-larger-font-size\"><strong>Toma tu aplicaci\u00f3n web o m\u00f3vil global sin complicaciones<\/strong><\/p>\n\n\n\n<p>Adapta tu software, <a href=\"https:\/\/phrase.com\/blog\/posts\/website-translation\/\">sitio web<\/a>, o videojuego para audiencias globales con la plataforma de localizaci\u00f3n de software m\u00e1s \u00e1gil y confiable.<\/p>\n\n\n\n<div class=\"wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex\">\n<div class=\"wp-block-button is-style-grey-filled\"><a class=\"wp-block-button__link wp-element-button\" href=\"https:\/\/phrase.com\/platform\/strings\/\">Explora Phrase Strings<\/a>\n<\/div><\/div>\n\n<\/div>\n<\/div>\n<\/div>\n\n\n\n\n\n\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=\"Alternar tabla de contenidos\"><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\/es\/blog\/posts\/flutter-localization\/#nuestra-aplicacion-de-demostracion\" >Nuestra aplicaci\u00f3n de demostraci\u00f3n<\/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\/es\/blog\/posts\/flutter-localization\/#versiones-utilizadas\" >Versiones utilizadas<\/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\/es\/blog\/posts\/flutter-localization\/#instalacion-y-configuracion\" >Instalaci\u00f3n y configuraci\u00f3n<\/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\/es\/blog\/posts\/flutter-localization\/#configuracion-de-localizacion\" >Configuraci\u00f3n de localizaci\u00f3n<\/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\/es\/blog\/posts\/flutter-localization\/#agregando-archivos-de-traduccion\" >Agregando archivos de traducci\u00f3n<\/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\/es\/blog\/posts\/flutter-localization\/#configurando-nuestra-aplicacion\" >Configurando nuestra aplicaci\u00f3n<\/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\/es\/blog\/posts\/flutter-localization\/#generacion-automatica-de-codigo\" >Generaci\u00f3n autom\u00e1tica de c\u00f3digo<\/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\/es\/blog\/posts\/flutter-localization\/#usando-nuestras-applocalizations\" >Usando nuestras AppLocalizations<\/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\/es\/blog\/posts\/flutter-localization\/#resolucion-de-localizacion\" >Resoluci\u00f3n de localizaci\u00f3n<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#actualizando-el-proyecto-de-ios\" >Actualizando el proyecto de iOS<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#obtener-la-region-activa\" >Obtener la regi\u00f3n activa<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#mensajes-de-traduccion-basicos\" >Mensajes de traducci\u00f3n b\u00e1sicos<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#interpolacion-en-mensajes\" >Interpolaci\u00f3n en mensajes<\/a><\/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\/es\/blog\/posts\/flutter-localization\/#plurales\" >Plurales<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#formato-de-numeros\" >Formato de n\u00fameros<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#formato-de-fecha\" >Formato de fecha<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#direccionalidad-de-izquierda-a-derecha-y-de-derecha-a-izquierda\" >Direccionalidad: de izquierda a derecha y de derecha a izquierda<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#agregando-activos-localizados\" >Agregando activos localizados<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-19\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#cambiando-el-idioma-en-la-aplicacion\" >Cambiando el idioma en la aplicaci\u00f3n<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-20\" href=\"https:\/\/phrase.com\/es\/blog\/posts\/flutter-localization\/#localizacion-flutter-simplificada\" >Localizaci\u00f3n Flutter simplificada<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"nuestra-aplicacion-de-demostracion\"><\/span>Nuestra aplicaci\u00f3n de demostraci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Para no hablar solo de teor\u00eda y no aburrirnos, vamos a programar una peque\u00f1a aplicaci\u00f3n de demostraci\u00f3n y la localizaremos:\u00a0<em>Heroes of Computer Science<\/em> es una selecci\u00f3n de figuras notables en la historia relativamente breve de la computaci\u00f3n.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-13861\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-13861\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-app-en-544x1024.png\" alt=\"Pantalla de inicio de H\u00e9roes de la inform\u00e1tica | Phrase\" width=\"350\" height=\"658\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-app-en-544x1024.png 544w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-app-en-159x300.png 159w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-app-en-768x1445.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-app-en-816x1536.png 816w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-app-en.png 1044w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><figcaption class=\"wp-element-caption\">Nuestra aplicaci\u00f3n en ingl\u00e9s&#8230; y pronto en otros idiomas<\/figcaption><\/figure>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"versiones-utilizadas\"><\/span>Versiones utilizadas<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Estamos utilizando los siguientes idiomas, marcos y versiones de paquetes en este art\u00edculo:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Dart 3.1.1<\/li>\n\n\n\n<li>Flutter 3.13.3<\/li>\n\n\n\n<li>DevTools 2.25.0<\/li>\n\n\n\n<li>flutter_localizations (la versi\u00f3n parece estar vinculada a Flutter): proporciona localizaciones a widgets comunes, como widgets de Material o Cupertino.<\/li>\n\n\n\n<li>intl 0.18.0 \u2014 la columna vertebral del sistema de localizaci\u00f3n; nos permite crear y usar nuestras propias localizaciones; se utiliza para formatear fechas y n\u00fameros.<\/li>\n\n<\/ul>\n\n\n\n<p>Ahora veamos el c\u00f3digo de nuestra aplicaci\u00f3n de inicio, que es bastante sencillo.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\">\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'screens\/hero_list.dart'<\/span>;\n\n<span class=\"hljs-keyword\">void<\/span> main() =&gt; runApp(MyApp());\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyApp<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> MaterialApp(\n      title: <span class=\"hljs-string\">'Heroes of Computer Science'<\/span>,\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      home: HeroList(title: <span class=\"hljs-string\">'Heroes of Computer Science'<\/span>),\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Nuestro widget ra\u00edz es un <code>MaterialApp<\/code> b\u00e1sico, con un <code>HeroList<\/code> en su ruta de <code>home<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_i18n_2021\/screens\/settings.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_i18n_2021\/widgets\/hero_card.dart'<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> title;\n\n  HeroList({<span class=\"hljs-keyword\">this<\/span>.title = <span class=\"hljs-string\">''<\/span>});\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      appBar: AppBar(\n        title: Text(title),\n        actions: &lt;Widget&gt;&#91;\n          IconButton(\n            icon: Icon(Icons.settings),\n            tooltip: <span class=\"hljs-string\">'Open settings'<\/span>,\n            onPressed: () {\n              Navigator.push(\n                context,\n                MaterialPageRoute(builder: (context) =&gt; Settings()),\n              );\n            },\n          )\n        ],\n      ),\n      body: Padding(\n        padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.all(<span class=\"hljs-number\">16<\/span>),\n        child: Column(\n          children: &#91;\n            Padding(\n              padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.only(bottom: <span class=\"hljs-number\">8.0<\/span>),\n              child: Text(<span class=\"hljs-string\">'6 Heroes'<\/span>),\n            ),\n            Expanded(\n              child: ListView(\n                children: &lt;Widget&gt;&#91;\n                  HeroCard(\n                    name: <span class=\"hljs-string\">'Grace Hopper'<\/span>,\n                    born: <span class=\"hljs-string\">'9 December 1906'<\/span>,\n                    bio: <span class=\"hljs-string\">'Devised theory of machine...'<\/span>,\n                  ),\n                  HeroCard(\n                    name: <span class=\"hljs-string\">'Alan Turing'<\/span>,\n                    born: <span class=\"hljs-string\">'23 June 1912'<\/span>,\n                    bio: <span class=\"hljs-string\">'Father of theoretical computer...'<\/span>,\n                  ),\n                  <span class=\"hljs-comment\">\/\/ ...<\/span>\n                ],\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p><code>HeroList<\/code> alberga principalmente una <code>ListView<\/code> de <code>HeroCard<\/code> parametrizados.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroCard<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  final <span class=\"hljs-built_in\">String<\/span> name;\n  final <span class=\"hljs-built_in\">String<\/span> born;\n  final <span class=\"hljs-built_in\">String<\/span> bio;\n  final <span class=\"hljs-built_in\">String<\/span> imagePath;\n  final <span class=\"hljs-built_in\">String<\/span> placeholderImagePath = <span class=\"hljs-string\">'assets\/images\/placeholder.jpg'<\/span>;\n\n  <span class=\"hljs-keyword\">const<\/span> HeroCard({\n    Key key,\n    <span class=\"hljs-keyword\">this<\/span>.name = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.born = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.bio = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.imagePath,\n  }) : <span class=\"hljs-keyword\">super<\/span>(key: key);\n\n  @override\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">var<\/span> theme = Theme.of(context);\n\n    <span class=\"hljs-keyword\">return<\/span> Card(\n      child: Padding(\n        padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.all(<span class=\"hljs-number\">4.0<\/span>),\n        <span class=\"hljs-attr\">child<\/span>: Row(\n          crossAxisAlignment: CrossAxisAlignment.start,\n          <span class=\"hljs-attr\">children<\/span>: &lt;Widget&gt;&#91;\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;&#91;\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<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p><code>HeroCard<\/code> muestra la imagen dada y los par\u00e1metros de cadena en un bonito widget <code>Card<\/code> de Material y embellece todo. \u00a1De acuerdo, vamos a localizar este cachorro!<\/p>\n\n\n\n<p>\ud83d\udd17 <em>Recurso \u00bb<\/em> Puedes obtener el c\u00f3digo de la aplicaci\u00f3n hasta este punto desde la <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-2-i18n-2021\/tree\/start\">rama de inicio de nuestro repositorio de GitHub<\/a>. La <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-2-i18n-2021\/tree\/main\">rama principal<\/a> tambi\u00e9n contiene la aplicaci\u00f3n completamente localizada.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"instalacion-y-configuracion\"><\/span>Instalaci\u00f3n y configuraci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Podemos instalar nuestros paquetes agregando unas pocas l\u00edneas a <code>pubspec.yaml<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-attr\">version:<\/span> <span class=\"hljs-number\">1.0<\/span><span class=\"hljs-number\">.0<\/span><span class=\"hljs-string\">+1<\/span>\n\n<span class=\"hljs-attr\">environment:<\/span>\n\u00a0\u00a0<span class=\"hljs-string\">sdk:<\/span>\u00a0<span class=\"hljs-string\">'&gt;=3.1.1\u00a0&lt;4.0.0'<\/span>\n\n<span class=\"hljs-attr\">dependencies:<\/span>\n\u00a0\u00a0<span class=\"hljs-attr\">flutter:<\/span>\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-string\">sdk:<\/span>\u00a0<span class=\"hljs-string\">flutter<\/span>\n\u00a0\u00a0\u00a0\u00a0\n\u00a0\u00a0<span class=\"hljs-string\">cupertino_icons:<\/span>\u00a0<span class=\"hljs-string\">^1.0.2<\/span>\n\n  <span class=\"hljs-comment\"># Add the flutter_localizations package<\/span>\n\u00a0\u00a0<span class=\"hljs-attr\">flutter_localizations:<\/span>\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-string\">sdk:<\/span>\u00a0<span class=\"hljs-string\">flutter<\/span>\n  <span class=\"hljs-comment\"># Add the intl package<\/span>\n\u00a0\u00a0<span class=\"hljs-string\">intl:<\/span>\u00a0<span class=\"hljs-string\">^0.18.0<\/span>\n\n<span class=\"hljs-attr\">dev_dependencies:<\/span>\n\u00a0\u00a0<span class=\"hljs-attr\">flutter_test:<\/span>\n\u00a0\u00a0\u00a0\u00a0<span class=\"hljs-string\">sdk:<\/span>\u00a0<span class=\"hljs-string\">flutter<\/span>\n\n<span class=\"hljs-attr\">flutter:<\/span>\n\u00a0\u00a0<span class=\"hljs-string\">generate:<\/span>\u00a0<span class=\"hljs-literal\">true<\/span> <span class=\"hljs-comment\"># Add this line<\/span>\n \u00a0<span class=\"hljs-string\">uses-material-design:<\/span>\u00a0<span class=\"hljs-literal\">true<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Despu\u00e9s de agregar las l\u00edneas resaltadas arriba, podemos ejecutar\u00a0<code>flutter pub get<\/code>\u00a0desde la l\u00ednea de comandos para obtener nuestros paquetes. La\u00a0<code>generate: true<\/code> l\u00ednea es necesaria para la generaci\u00f3n autom\u00e1tica de c\u00f3digo que los paquetes de localizaci\u00f3n nos proporcionan. Pronto profundizaremos m\u00e1s en el negocio de la generaci\u00f3n de c\u00f3digo. Por ahora, incluye la l\u00ednea. Puede ahorrarte bastante tiempo.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"configuracion-de-localizacion\"><\/span>Configuraci\u00f3n de localizaci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Con nuestros paquetes instalados, agreguemos un archivo <code>l10n.yaml<\/code> en la ra\u00edz de nuestro proyecto. Este archivo configura d\u00f3nde estar\u00e1n nuestros archivos de traducci\u00f3n y los nombres de los archivos dart generados autom\u00e1ticamente.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-attr\">arb-dir:<\/span> <span class=\"hljs-string\">lib\/l10n<\/span>\n<span class=\"hljs-attr\">template-arb-file:<\/span> <span class=\"hljs-string\">app_en.arb<\/span>\n<span class=\"hljs-attr\">output-localization-file:<\/span> <span class=\"hljs-string\">app_localizations.dart<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>\ud83d\udd17 <em>Recurso \u00bb<\/em> La <a href=\"https:\/\/docs.google.com\/document\/d\/10e0saTfAv32OZLRmONy866vnaw0I2jwL8zukykpgWBc\/edit#heading=h.upij01jgi58m\">gu\u00eda de usuario de internacionalizaci\u00f3n oficial<\/a> cubre muchas m\u00e1s opciones que puedes incorporar a <code>l10n.yaml<\/code> para controlar el generador de c\u00f3digo de internacionalizaci\u00f3n de Flutter.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"agregando-archivos-de-traduccion\"><\/span>Agregando archivos de traducci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>La localizaci\u00f3n Flutter utiliza archivos ARB (Application Resource Bundle) para albergar sus traducciones por defecto. Estos son archivos simples escritos en sintaxis JSON. Como m\u00ednimo, necesitamos un archivo de plantilla que corresponda a nuestra localizaci\u00f3n predeterminada (ingl\u00e9s en nuestro caso). Especificamos que nuestro archivo de plantilla ser\u00e1 <code>lib\/l10n\/app_en.arb<\/code> en nuestra configuraci\u00f3n anterior. As\u00ed que vamos a crear este directorio de alojamiento y agregar nuestro archivo de traducciones de plantilla a \u00e9l.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-attr\">\"appTitle\"<\/span>: <span class=\"hljs-string\">\"Heroes of Computer Science\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Por supuesto, todo este foll\u00f3n no tendr\u00eda mucho sentido si no pudi\u00e9ramos proporcionar traducciones para otras localizaciones. Agregaremos un archivo de traducci\u00f3n \u00e1rabe aqu\u00ed. Agrega t\u00fa cualquier idioma que desees. Hablaremos un poco sobre los dise\u00f1os de derecha a izquierda (RTL) m\u00e1s adelante, as\u00ed que si te interesa ese asunto, quiz\u00e1s quieras ce\u00f1irte al \u00e1rabe u otro idioma RTL.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-attr\">\"appTitle\"<\/span>: <span class=\"hljs-string\">\"\u0623\u0628\u0637\u0627\u0644 \u0639\u0644\u0648\u0645 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Podemos agregar tantas traducciones de localizaci\u00f3n como queramos. Solo necesitamos asegurarnos de que nuestros archivos se ajusten a nuestra convenci\u00f3n de nomenclatura configurada: <code>lib\/l10n\/app_&lt;locale&gt;.arb<\/code><\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"configurando-nuestra-aplicacion\"><\/span>Configurando nuestra aplicaci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Vamos a contarle a nuestra aplicaci\u00f3n lo mucho que nos interesa la internacionalizaci\u00f3n. Necesitamos configurar nuestro archivo <code>main.dart<\/code> para usar los paquetes de localizaci\u00f3n Flutter.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_localizations\/flutter_localizations.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'screens\/hero_list.dart'<\/span>;\n\n<span class=\"hljs-keyword\">void<\/span> main() =&gt; runApp(MyApp());\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyApp<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  @override\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> MaterialApp(\n      title: <span class=\"hljs-string\">'Heroes of Computer Science'<\/span>,\n      <span class=\"hljs-attr\">localizationsDelegates<\/span>: &#91;\n        GlobalMaterialLocalizations.delegate,\n        GlobalWidgetsLocalizations.delegate,\n        GlobalCupertinoLocalizations.delegate,\n      ],\n      <span class=\"hljs-attr\">supportedLocales<\/span>: &#91;\n        <span class=\"hljs-comment\">\/\/ 'en' es el c\u00f3digo de idioma. Podr\u00edamos opcionalmente proporcionar un<\/span>\n        <span class=\"hljs-comment\">\/\/ c\u00f3digo de pa\u00eds como el segundo par\u00e1metro, por ejemplo.<\/span>\n        <span class=\"hljs-comment\">\/\/ Locale('en', 'US'). Si hacemos eso, es posible que nos interese<\/span>\n        <span class=\"hljs-comment\">\/\/ proporcionar un archivo adicional app_en_US.arb para<\/span>\n        <span class=\"hljs-comment\">\/\/ traducciones espec\u00edficas para la regi\u00f3n.<\/span>\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'en'<\/span>, <span class=\"hljs-string\">''<\/span>),\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'ar'<\/span>, <span class=\"hljs-string\">''<\/span>),\n      ],\n      <span class=\"hljs-attr\">theme<\/span>: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      <span class=\"hljs-attr\">home<\/span>: HeroList(title: <span class=\"hljs-string\">'Heroes of Computer Science'<\/span>),\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Despu\u00e9s de importar <code>flutter_localizations.dart<\/code>, agregamos las propiedades <code>localizationsDelegates<\/code> y <code>supportedLocales<\/code> al constructor de <code>MaterialApp<\/code>. Los <code>localizationsDelegates<\/code> proporcionan localizaciones a nuestra aplicaci\u00f3n. Los que se incluyen arriba proporcionan localizaciones para widgets de Flutter, Material y Cupertino ya sido localizadas por el equipo de Flutter.<\/p>\n\n\n\n<p>Por ejemplo, supongamos que ten\u00edamos un <code>MaterialApp<\/code> y llamamos a <a href=\"https:\/\/api.flutter.dev\/flutter\/material\/showDatePicker.html\">la funci\u00f3n showDatePicker()<\/a> en alg\u00fan lugar dentro de \u00e9l. Suponiendo tambi\u00e9n que el idioma de nuestro sistema operativo est\u00e1 configurado en \u00e1rabe, ver\u00edamos algo como lo siguiente.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-13862\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13862\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-date-picker-ar.png\" alt=\"Flutter showDatePicker() calendar | Phrase\" width=\"350\" height=\"549\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-date-picker-ar.png 598w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-date-picker-ar-191x300.png 191w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/figure>\n\n\n\n<p>Ten en cuenta que no tuvimos que traducir nada nosotros mismos para obtener esto. El widget del selector de fecha ya ha sido localizado por el equipo de Flutter. Solo necesitamos conectar los delegados correctos en el constructor de nuestra aplicaci\u00f3n, como hicimos arriba. \u00a1Un gran aplauso para el equipo de Flutter por esto: qu\u00e9 ahorro de tiempo!<\/p>\n\n\n\n<p>\ud83d\uddd2\ufe0f <em>Nota \u00bb<\/em> En el momento de escribir esto, <code>flutter_localizations<\/code> <a href=\"https:\/\/flutter.dev\/docs\/development\/accessibility-and-localization\/internationalization#setting-up\">admite 78 idiomas<\/a>.<\/p>\n\n\n\n<p>\ud83d\udd17 <em>Recurso \u00bb<\/em> La <a href=\"https:\/\/flutter.dev\/docs\/development\/accessibility-and-localization\/internationalization#how-internationalization-in-flutter-works\">documentaci\u00f3n oficial de Flutter<\/a> es muy eficaz a la hora de explicar c\u00f3mo colaboran las distintas partes, como los delegados y la clase <code>Localizations<\/code>, para la localizaci\u00f3n.<\/p>\n\n\n\n<p>La prop <code>supportedLocales<\/code> que proporcionamos al constructor de <code>MaterialApp<\/code> enumera los idiomas que nuestra aplicaci\u00f3n soporta. Flutter <em>solo<\/em> reconstruir\u00e1 widgets en respuesta a un cambio de localizaci\u00f3n si la localizaci\u00f3n est\u00e1 en la lista de <code>supportedLocales<\/code>. Volveremos a <code>supportedLocales<\/code> en un momento cuando discutamos la resoluci\u00f3n de localizaci\u00f3n. \u00a1Ahora mismo, generemos algo de c\u00f3digo!<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"generacion-automatica-de-codigo\"><\/span>Generaci\u00f3n autom\u00e1tica de c\u00f3digo<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Para usar las traducciones de los archivos ARB en nuestra aplicaci\u00f3n Flutter, necesitamos generar algunos archivos Dart que importamos cada vez que necesitamos las traducciones. Para generar estos archivos, solo aseg\u00farate de haber seguido los pasos de instalaci\u00f3n y configuraci\u00f3n hasta este punto y ejecuta la aplicaci\u00f3n. As\u00ed es, solo ejecuta la aplicaci\u00f3n. El c\u00f3digo se generar\u00e1 autom\u00e1ticamente, y si todo sali\u00f3 bien, deber\u00edas ver los siguientes archivos en el directorio de tu proyecto:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><code>.dart_tool\/flutter_gen\/gen_l10n\/app_localizations.dart<\/code><\/li>\n\n\n\n<li><code>.dart_tool\/flutter_gen\/gen_l10n\/app_localizations_en.dart<\/code><\/li>\n\n\n\n<li><code>.dart_tool\/flutter_gen\/gen_l10n\/app_localizations_ar.dart<\/code><\/li>\n\n<\/ul>\n\n\n\n<p>\ud83d\uddd2\ufe0f<em> Nota \u00bb<\/em> Si estos archivos no se generaron, aseg\u00farate de que tu aplicaci\u00f3n Flutter no tenga errores de compilaci\u00f3n y revisa tu consola de depuraci\u00f3n cuando ejecutes la aplicaci\u00f3n.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"usando-nuestras-applocalizations\"><\/span>Usando nuestras AppLocalizations<span class=\"ez-toc-section-end\"><\/span><\/h3>\n\n\n\n<p>Hagamos uso de los archivos de c\u00f3digo reci\u00e9n generados para localizar el t\u00edtulo de nuestra aplicaci\u00f3n.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_i18n_2021\/screens\/settings.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_localizations\/flutter_localizations.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'screens\/hero_list.dart'<\/span>;\n\n<span class=\"hljs-keyword\">void<\/span> main() =&gt; runApp(MyApp());\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyApp<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> MaterialApp(\n      onGenerateTitle: (context) {\n        <span class=\"hljs-keyword\">return<\/span> AppLocalizations.of(context).appTitle;\n      },\n      localizationsDelegates: &#91;\n        AppLocalizations.delegate,\n        GlobalMaterialLocalizations.delegate,\n        GlobalWidgetsLocalizations.delegate,\n        GlobalCupertinoLocalizations.delegate,\n      ],\n      supportedLocales: &#91;\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'en'<\/span>, <span class=\"hljs-string\">''<\/span>),\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'ar'<\/span>, <span class=\"hljs-string\">''<\/span>),\n      ],\n      theme: ThemeData(\n        primarySwatch: Colors.blue,\n      ),\n      <span class=\"hljs-comment\">\/\/ eliminar home: HeroList(...)<\/span>\n      initialRoute: <span class=\"hljs-string\">'\/'<\/span>,\n      routes: {\n        <span class=\"hljs-string\">'\/'<\/span>: (context) =&gt; HeroList(title: AppLocalizations.of(context).appTitle),\n        <span class=\"hljs-string\">'\/settings'<\/span>: (context) =&gt; Settings(),\n      },\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Importamos <code>app_localizations.dart<\/code> y agregamos el <code>AppLocalizations.delegate<\/code> autogenerado a nuestra lista de delegados. Esto nos proporciona el widget <code>AppLocalizations<\/code>, que usamos para traducir el t\u00edtulo de la aplicaci\u00f3n y el t\u00edtulo de <code>HeroList<\/code>. La propiedad autogenerada <code>appTitle<\/code> contendr\u00e1 la traducci\u00f3n que coincide con la localizaci\u00f3n activa, extra\u00edda de nuestro archivo <code>app_&lt;locale&gt;.arb<\/code>.<\/p>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> Debido al orden de carga, nuestras traducciones no estar\u00e1n listas cuando estemos construyendo nuestro <code>MaterialApp<\/code>. As\u00ed que usamos las propiedades <code>onGenerateTitle<\/code> y <code>routes<\/code>, y sus funciones de constructor <code>(context) {}<\/code> para asegurarnos de que nuestras traducciones est\u00e9n listas cuando establezcamos nuestras cadenas de t\u00edtulo.<\/p>\n\n\n\n<p>Ahora, si configuramos el idioma de nuestro sistema operativo en \u00e1rabe y ejecutamos nuestra aplicaci\u00f3n, \u00a1he aqu\u00ed!<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-13863\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13863\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-title-544x1024.png\" alt=\"Heroes of Computer Science con t\u00edtulo en \u00e1rabe | Phrase\" width=\"350\" height=\"658\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-title-544x1024.png 544w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-title-159x300.png 159w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-title-768x1445.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-title-816x1536.png 816w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-title.png 1044w\" sizes=\"auto, (max-width: 350px) 100vw, 350px\" \/><\/figure>\n\n\n\n<p>Nuestro t\u00edtulo ahora est\u00e1 en \u00e1rabe. Adem\u00e1s, observa c\u00f3mo Flutter ha dispuesto muchos de sus widgets en una direcci\u00f3n de derecha a izquierda autom\u00e1ticamente para nosotros. Dado que el \u00e1rabe es un idioma de derecha a izquierda, \u00a1esto nos ahorra mucho tiempo! Tendremos que arreglar ese padding a la izquierda de la imagen en los <code>HeroCard<\/code>s, y lo haremos cuando abordemos la direccionalidad un poco m\u00e1s adelante.<\/p>\n\n\n\n<p>\ud83e\udd3f <em>Profundiza m\u00e1s \u00bb<\/em> Los lectores m\u00e1s avispados os habr\u00e9is fijado en que <code>AppLocalizations.of(context)<\/code> se parece mucho a llamar a un <a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/InheritedWidget-class.html\">InheritedWidget<\/a>. Eso es porque los objetos de localizaci\u00f3n funcionan mucho como <code>InheritedWidget<\/code>s.<\/p>\n\n\n\n<p>Eso es todo para la configuraci\u00f3n. Ahora tenemos la base para localizar nuestra aplicaci\u00f3n. Una pregunta que podr\u00edas tener en este punto es: \u00ab\u00bfc\u00f3mo decide Flutter qu\u00e9 localizaci\u00f3n usar?\u00bb Hablemos de eso.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"resolucion-de-localizacion\"><\/span>Resoluci\u00f3n de localizaci\u00f3n<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Las localizaciones que proporcionamos a <code>MaterialApp(supportedLocales: [...])<\/code> son las \u00fanicas que Flutter usar\u00e1 para determinar la localizaci\u00f3n activa cuando la aplicaci\u00f3n se ejecute. Para hacer esto, Flutter utiliza tres propiedades de una localizaci\u00f3n:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>El c\u00f3digo de idioma, por ejemplo, <code>'en'<\/code> para ingl\u00e9s<\/li>\n\n\n\n<li>El c\u00f3digo de pa\u00eds (opcional), por ejemplo, la parte <code>US<\/code> en <code>en_US<\/code><\/li>\n\n\n\n<li><a href=\"https:\/\/flutter.dev\/docs\/development\/accessibility-and-localization\/internationalization#advanced-locale-definition\">El c\u00f3digo de script<\/a> (opcional): el conjunto de letras utilizado, por ejemplo, chino tradicional (<code>Hant<\/code>) o chino simplificado (<code>Hans<\/code>)<\/li>\n\n<\/ul>\n\n\n\n<p>Por defecto, Flutter leer\u00e1 las localizaciones del sistema preferidas del usuario y:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n\n<li>Intentar\u00e1 hacer coincidir el <code>languageCode<\/code>, <code>scriptCode<\/code> y <code>countryCode<\/code> con uno en <code>supportedLocales<\/code>. Si eso falla,<\/li>\n\n\n\n<li>Intentar\u00e1 hacer coincidir el <code>languageCode<\/code> y <code>scriptCode<\/code> con uno en <code>supportedLocales<\/code>. Si eso falla,<\/li>\n\n\n\n<li>Intentar\u00e1 hacer coincidir el <code>languageCode<\/code> y <code>countryCode<\/code> con uno en <code>supportedLocales<\/code>. Si eso falla,<\/li>\n\n\n\n<li>Intenta hacer coincidir el <code>c\u00f3digoDeIdioma<\/code> con uno en <code>localesSoportados<\/code>. Si eso falla,<\/li>\n\n\n\n<li>Intenta hacer coincidir el <code>c\u00f3digoDePa\u00eds<\/code> con uno en <code>localesSoportados<\/code> solo cuando todos los locales preferidos no coincidan. Si eso falla,<\/li>\n\n\n\n<li>Devuelve el primer elemento de <code>localesSoportados<\/code> como una opci\u00f3n de respaldo.<\/li>\n\n<\/ol>\n\n\n\n<p>As\u00ed que en nuestra aplicaci\u00f3n, si el idioma de iOS del usuario est\u00e1 configurado en <code>ar_SA<\/code>, ver\u00edan nuestras localizaciones <code>ar<\/code> (4. arriba). Si el idioma de iOS del usuario est\u00e1 configurado en <code>fr<\/code> (franc\u00e9s), ver\u00edan nuestras localizaciones <code>en<\/code> (6. arriba). En <a href=\"https:\/\/phrase.com\/blog\/posts\/best-practices-for-android-localization-revisited-and-expanded\/\">Android<\/a>, un usuario puede tener una lista de locales preferidos, no solo uno. Esto lo cubre Flutter en el algoritmo de resoluci\u00f3n anterior.<\/p>\n\n\n\n<p>\ud83d\udd17 Recurso \u00bb El algoritmo anterior es una par\u00e1frasis de la <a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/WidgetsApp\/supportedLocales.html\">documentaci\u00f3n oficial de la propiedad localesSoportados<\/a>.<\/p>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> Si tu aplicaci\u00f3n soporta un locale con un c\u00f3digo de pa\u00eds, como <code>fr_CA<\/code> (franc\u00e9s canadiense), deber\u00edas proporcionar un respaldo sin el c\u00f3digo de pa\u00eds, como <code>fr<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"actualizando-el-proyecto-de-ios\"><\/span>Actualizando el proyecto de iOS<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>La documentaci\u00f3n oficial de Flutter menciona la necesidad de actualizar la <code>Info.plist<\/code> directamente en el paquete de la aplicaci\u00f3n <a href=\"https:\/\/phrase.com\/blog\/posts\/ios-tutorial-internationalization-localization\/\">iOS<\/a>, a\u00f1adiendo nuestras regiones admitidas a \u00e9l. Si <code>Info.plist<\/code> no se actualiza, nuestra aplicaci\u00f3n de iOS podr\u00eda no funcionar como se espera. Para hacer la actualizaci\u00f3n solo necesitamos abrir <code>ios\/Runner\/Info.plist<\/code> en cualquier editor de texto y asegurarnos de que las siguientes entradas est\u00e9n all\u00ed.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"texto plano\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">&lt;key&gt;CFBundleLocalizations&lt;\/key&gt;\n&lt;array&gt;\n  &lt;string&gt;en&lt;\/string&gt;\n  &lt;string&gt;ar&lt;\/string&gt;\n&lt;\/array&gt;<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">texto plano<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"obtener-la-region-activa\"><\/span>Obtener la regi\u00f3n activa<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A veces necesitamos saber cu\u00e1l es la regi\u00f3n en tiempo de ejecuci\u00f3n en nuestro c\u00f3digo. Podemos hacer esto con el siguiente fragmento.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-11\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\">Locale activeLocale = Localizations.localeOf(context);\n\n<span class=\"hljs-comment\">\/\/ Suponiendo que nuestra localizaci\u00f3n activa es fr_CA...<\/span>\ndebugPrint(activeLocale.languageCode);\n<span class=\"hljs-comment\">\/\/ =&gt; fr<\/span>\n\ndebugPrint(activeLocale.countryCode);\n<span class=\"hljs-comment\">\/\/ =&gt; CA<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> Observa que estamos usando <code>Localizations<\/code>, un widget integrado en Flutter, y no el <code>AppLocalizations<\/code> auto-generado.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"mensajes-de-traduccion-basicos\"><\/span>Mensajes de traducci\u00f3n b\u00e1sicos<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Ya cubrimos mensajes de traducci\u00f3n b\u00e1sicos cuando agregamos nuestro <code>appTitle<\/code> mensaje. Sin embargo, repasemos r\u00e1pidamente el flujo de trabajo para agregar mensajes. Traduciremos el tooltip del bot\u00f3n de icono de la barra de aplicaciones de nuestro <code>HeroList<\/code> a continuaci\u00f3n. Ya que no estamos realmente construyendo una pantalla de configuraci\u00f3n, podr\u00edamos hacer <em>algo<\/em> con ello \ud83d\ude05.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-12\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> title;\n\n  HeroList({<span class=\"hljs-keyword\">this<\/span>.title = <span class=\"hljs-string\">''<\/span>});\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      appBar: AppBar(\n        title: Text(title),\n        actions: &lt;Widget&gt;&#91;\n          IconButton(\n            icon: Icon(Icons.settings),\n            tooltip: <span class=\"hljs-string\">'Open settings'<\/span>,\n            onPressed: () {\n              Navigator.push(\n                context,\n                MaterialPageRoute(builder: (context) =&gt; Settings()),\n              );\n            },\n          )\n        ],\n      ),\n      body: ...\n  );\n}\n\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>\u00bfVamos a localizar ese tooltip, te parece? Primero, agregaremos las entradas relevantes a nuestros archivos ARB.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-13\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ English<\/span>\n{\n  <span class=\"hljs-attr\">\"appTitle\"<\/span>: <span class=\"hljs-string\">\"Heroes of Computer Science\"<\/span>,\n  <span class=\"hljs-attr\">\"openSettings\"<\/span>: <span class=\"hljs-string\">\"Abrir configuraci\u00f3n\"<\/span>\n}\n\n<span class=\"hljs-comment\">\/\/ \u00c1rabe<\/span>\n{\n  <span class=\"hljs-attr\">\"appTitle\"<\/span>: <span class=\"hljs-string\">\"\u0623\u0628\u0637\u0627\u0644 \u0639\u0644\u0648\u0645 \u0627\u0644\u0643\u0645\u0628\u064a\u0648\u062a\u0631\"<\/span>,\n  <span class=\"hljs-attr\">\"openSettings\"<\/span>: <span class=\"hljs-string\">\"\u0625\u0641\u062a\u062d \u0627\u0644\u0625\u0639\u062f\u0627\u062f\u0627\u062a\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>A continuaci\u00f3n, vamos a <em>recargar nuestra aplicaci\u00f3n para regenerar nuestros archivos de c\u00f3digo<\/em>. Este paso es realmente importante y olvidarlo puede llevar a frustraciones innecesarias. Observa que este es un reinicio completo de la aplicaci\u00f3n (<\/p>\n\n\n\n<figure class=\"wp-block-image alignnone wp-image-13872\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-13872\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-app-reload-1.png\" alt=\"Bot\u00f3n de actualizar | Phrase\" width=\"24\" height=\"24\" \/><\/figure>\n\n\n\n<p>), no es una recarga en activo.<\/p>\n\n\n\n<p>Ahora podemos actualizar nuestro c\u00f3digo para usar nuestro nuevo mensaje localizado.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-comment\">\/\/ ... <\/span>\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> title;\n\n  HeroList({<span class=\"hljs-keyword\">this<\/span>.title = <span class=\"hljs-string\">''<\/span>});\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context);\n\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      appBar: AppBar(\n        title: Text(title),\n        actions: &lt;Widget&gt;&#91;\n          IconButton(\n            icon: Icon(Icons.settings),\n            tooltip: t.openSettings,\n            onPressed: () {\n              Navigator.push(\n                context,\n                MaterialPageRoute(builder: (context) =&gt; Settings()),\n              );\n            },\n          )\n        ],\n      ),\n      body: ... \n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Con este c\u00f3digo en su lugar, cuando recarguemos nuestra aplicaci\u00f3n deber\u00edamos ver el valor localizado de nuestro tooltip en el <em>Widget Inspector<\/em>.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-13864 size-full\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-13864 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-tooltip.png\" alt=\"tooltip del Widget Inspector | Phrase\" width=\"400\" height=\"152\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-tooltip.png 400w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/04\/flutteri18n2021p1-ar-tooltip-300x114.png 300w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/figure>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> A menudo puede que obtengas <a href=\"https:\/\/docs.google.com\/document\/d\/10e0saTfAv32OZLRmONy866vnaw0I2jwL8zukykpgWBc\/edit#heading=h.xru0hle4tb2x\">resaltado de error<\/a> en tu IDE despu\u00e9s de agregar nuevos mensajes de traducci\u00f3n. Si has recargado tu aplicaci\u00f3n, el error puede ser incorrecto (puede que est\u00e9s bien). Si recibes un mensaje que dice que hay errores de construcci\u00f3n, puedes intentar ejecutar la aplicaci\u00f3n de todos modos. Mientras la aplicaci\u00f3n se construya y se ejecute, y veas tus nuevas traducciones, entonces todo probablemente est\u00e9 bien. Para hacer que el error desaparezca en el IDE, intenta cerrar completamente tu aplicaci\u00f3n y volver a iniciarla.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"interpolacion-en-mensajes\"><\/span>Interpolaci\u00f3n en mensajes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Estamos en camino de traducir nuestra aplicaci\u00f3n. \u00bfPero qu\u00e9 pasa con la interpolaci\u00f3n de valores din\u00e1micos en tiempo de ejecuci\u00f3n en nuestros mensajes de traducci\u00f3n? Por ejemplo, la biograf\u00eda de Steve Wozniak contiene los nombres de los productos <em>Apple I<\/em> y <em>Apple II<\/em>.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-15\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-comment\">\/\/ ... <\/span>\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ... <\/span>\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      <span class=\"hljs-comment\">\/\/ ... <\/span>\n      body: HeroCard(\n        name: <span class=\"hljs-string\">'Steve Wozniak'<\/span>,\n        born: <span class=\"hljs-string\">'11 August 1950'<\/span>,\n        bio: <span class=\"hljs-string\">'Designed &amp; developed the Apple I &amp; '<\/span>\n             <span class=\"hljs-string\">'Apple II.'<\/span>,\n        imagePath: <span class=\"hljs-string\">'assets\/images\/steve_wozniak.jpg'<\/span>,\n      ),\n      <span class=\"hljs-comment\">\/\/ ... <\/span>\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-15\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Cuando localizamos este mensaje, es posible que queramos mantener <em>Apple I<\/em> y <em>Apple II<\/em> en su ingl\u00e9s original independientemente de la localizaci\u00f3n activa. Podemos usar marcadores de posici\u00f3n en nuestros archivos de traducci\u00f3n para lograr esto.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-16\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ English<\/span>\n{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-attr\">\"wozniakBio\"<\/span>: <span class=\"hljs-string\">\"Developed the {appleOne} &amp; {appleTwo} microcomputers.\"<\/span>,\n  <span class=\"hljs-attr\">\"@wozniakBio\"<\/span>: {\n    <span class=\"hljs-attr\">\"placeholders\"<\/span>: {\n      <span class=\"hljs-attr\">\"appleOne\"<\/span>: {},\n      <span class=\"hljs-attr\">\"appleTwo\"<\/span>: {}\n    }\n  },\n  \n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}\n\n<span class=\"hljs-comment\">\/\/ \u00c1rabe<\/span>\n{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-attr\">\"wozniakBio\"<\/span>: <span class=\"hljs-string\">\"\u0637\u0648\u0631 \u062c\u0647\u0627\u0632\u064a \u0643\u0645\u0628\u064a\u0648\u062a\u0631 {appleOne} \u0648 {appleTwo}\"<\/span>,\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-16\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Usamos la sintaxis <code>{placeholderName}<\/code> para establecer los marcadores de posici\u00f3n para nuestros valores din\u00e1micos, y podemos tener tantos marcadores de posici\u00f3n como queramos en un mensaje.<\/p>\n\n\n\n<p>Probablemente tambi\u00e9n te hayas fijado en la clave <code>@wozniakBio<\/code> en nuestras traducciones en ingl\u00e9s anteriores. Esta entrada es un complemento del mensaje <code>wozniakBio<\/code> en el mismo archivo. Las entradas complementarias son opcionales para mensajes b\u00e1sicos pero obligatorias para mensajes con marcadores de posici\u00f3n. De hecho, usamos entradas complementarias para definir los marcadores de posici\u00f3n de los mensajes (<a href=\"https:\/\/docs.google.com\/document\/d\/10e0saTfAv32OZLRmONy866vnaw0I2jwL8zukykpgWBc\/edit#heading=h.emv7twpb8iyo\">entre otras cosas<\/a>).<\/p>\n\n\n\n<p>\ud83d\uddd2\ufe0f <em>Nota \u00bb<\/em> La entrada complementaria para un mensaje con la clave <code>foo<\/code> debe tener una clave de <code>@foo<\/code>. Solo necesitamos entradas complementarias en nuestro archivo de traducci\u00f3n predeterminado\/plantilla (ingl\u00e9s en nuestro caso).<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-17\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-string\">\"@wozniakBio\"<\/span>: { <span class=\"hljs-string\">\"placeholders\"<\/span>: { <span class=\"hljs-string\">\"appleOne\"<\/span>: {}, <span class=\"hljs-string\">\"appleTwo\"<\/span>: {} } }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-17\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> Los nombres de los marcadores de posici\u00f3n deben ser nombres de par\u00e1metros de m\u00e9todo Dart v\u00e1lidos.<\/p>\n\n\n\n<p>Podr\u00edamos usar el objeto <code>placeholders<\/code> para especificar el tipo de cada valor, e incluso proporcionar ejemplos como documentaci\u00f3n si lo deseamos. Tambi\u00e9n podemos dejar la definici\u00f3n como un <code>{}<\/code> vac\u00edo.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-18\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-string\">\"@wozniakBio\"<\/span>: {\n    <span class=\"hljs-string\">\"placeholders\"<\/span>: {\n      <span class=\"hljs-string\">\"appleOne\"<\/span>: {\n        <span class=\"hljs-comment\">\/\/ Tipo expl\u00edcito<\/span>\n        <span class=\"hljs-string\">\"type\"<\/span>: <span class=\"hljs-string\">\"String\"<\/span>,\n        <span class=\"hljs-comment\">\/\/ Un poco de documentaci\u00f3n<\/span>\n        <span class=\"hljs-string\">\"example\"<\/span>: <span class=\"hljs-string\">\"Apple I\"<\/span>\n      },\n      <span class=\"hljs-comment\">\/\/ Est\u00e1 bien especificar solo el nombre<\/span>\n      <span class=\"hljs-string\">\"appleTwo\"<\/span>: {}\n    }\n  }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-18\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>El <code>tipo<\/code> se utiliza en el m\u00e9todo que Flutter generar\u00e1 en <code>AppLocalizations<\/code> para nuestro mensaje <code>wozniakBio<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-19\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-comment\">\/\/ ... <\/span>\n\nabstract <span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">AppLocalizations<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ... <\/span>\n\n  <span class=\"hljs-comment\">\/\/ Este m\u00e9todo se implementa en app_localizations_en.dart<\/span>\n  <span class=\"hljs-comment\">\/\/ y app_localizations_ar.dart.<\/span>\n  <span class=\"hljs-comment\">\/\/ Tipo expl\u00edcito para el par\u00e1metro appleOne. AppleTwo est\u00e1 impl\u00edcito<\/span>\n  <span class=\"hljs-comment\">\/\/ como par\u00e1metro.<\/span>\n  <span class=\"hljs-built_in\">String<\/span> wozniakBio(<span class=\"hljs-built_in\">String<\/span> appleOne, <span class=\"hljs-built_in\">Object<\/span> appleTwo);\n\n  <span class=\"hljs-comment\">\/\/ ... <\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-19\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>\ud83d\uddd2\ufe0f<em> Nota \u00bb<\/em> Est\u00e1 perfectamente bien en la mayor\u00eda de los casos usar <code>{}<\/code> vac\u00edo para definiciones de marcador de posici\u00f3n. Una definici\u00f3n vac\u00eda har\u00e1 que el par\u00e1metro sea de tipo <code>Object<\/code>. Entre bastidores, Flutter solo usar\u00e1 el valor <code>theParameter.toString()<\/code> del par\u00e1metro dado, por lo que un par\u00e1metro <code>Object<\/code> funcionar\u00e1 perfectamente. Un marcador de posici\u00f3n <code>Object<\/code> impl\u00edcito tambi\u00e9n mantiene nuestros mensajes flexibles para aceptar cualquier tipo, ya que todos los tipos de Dart derivan de <a href=\"https:\/\/api.dart.dev\/stable\/2.12.4\/dart-core\/Object-class.html\">Object<\/a> y tienen un <code>toString()<\/code>.<\/p>\n\n\n\n<p>OK, despu\u00e9s de reiniciar la aplicaci\u00f3n para actualizar <code>AppLocalizations<\/code>, podemos localizar el mensaje de la biograf\u00eda de Woz con el nuevo m\u00e9todo.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-20\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-comment\">\/\/ ... <\/span>\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ... <\/span>\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context);\n\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      <span class=\"hljs-comment\">\/\/ ... <\/span>\n      body: HeroCard(\n        name: <span class=\"hljs-string\">'Steve Wozniak'<\/span>,\n        born: <span class=\"hljs-string\">'11 August 1950'<\/span>,\n        bio: t.wozniakBio(<span class=\"hljs-string\">'Apple I'<\/span>, <span class=\"hljs-string\">'Apple II'<\/span>),\n        imagePath: <span class=\"hljs-string\">'assets\/images\/steve_wozniak.jpg'<\/span>,\n      ),\n      <span class=\"hljs-comment\">\/\/ ... <\/span>\n    );\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-20\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Con eso en su lugar, sabemos que nunca podremos ser demandados por ninguna empresa de frutas por tergiversar sus productos en <em>cualquier<\/em> idioma.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14105\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-14105\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-woz-bio-ar-en-1024x702.png\" alt=\"Valores interpolados en \u00e1rabe e ingl\u00e9s | Phrase\" width=\"550\" height=\"377\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-woz-bio-ar-en-1024x702.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-woz-bio-ar-en-300x206.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-woz-bio-ar-en-768x527.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-woz-bio-ar-en.png 1070w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><figcaption class=\"wp-element-caption\">Valores interpolados en \u00e1rabe e ingl\u00e9s<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"plurales\"><\/span>Plurales<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A menudo necesitamos manejar plurales din\u00e1micos en nuestra localizaci\u00f3n. \u201cHas recibido <em>un mensaje<\/em>\u201d o \u201cHas recibido <em>3 mensajes<\/em>\u201d, por ejemplo.<\/p>\n\n\n\n<p>Es importante notar que <a href=\"https:\/\/unicode-org.github.io\/cldr-staging\/charts\/latest\/supplemental\/language_plural_rules.html\">los diferentes idiomas manejan los plurales de manera diferente<\/a>. Por ejemplo, el ingl\u00e9s tiene dos formas plurales: uno y otro (otro == cero y &gt;1). El \u00e1rabe tiene seis formas plurales. Esto puede ser un poco complicado al localizar usando bibliotecas que no soportan reglas plurales complejas. Afortunadamente, la soluci\u00f3n de internacionalizaci\u00f3n directa de Flutter maneja plurales complejos de forma predeterminada, as\u00ed que estamos cubiertos. Utilic\u00e9moslo para localizar el contador de h\u00e9roes en nuestra aplicaci\u00f3n.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14106\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14106\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-hero-count-before-l10n-1024x616.png\" alt=\"Pluralizaci\u00f3n en ingl\u00e9s, pantalla de inicio de Heroes of Computer Science | Phrase\" width=\"550\" height=\"331\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-hero-count-before-l10n-1024x616.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-hero-count-before-l10n-300x180.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-hero-count-before-l10n-768x462.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-hero-count-before-l10n.png 1169w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/figure>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-21\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      <span class=\"hljs-comment\">\/\/ ...<\/span>\n      body: Padding(\n        <span class=\"hljs-comment\">\/\/ ...<\/span>\n        child: Column(\n          children: &#91;\n            Padding(\n              padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.only(bottom: <span class=\"hljs-number\">8.0<\/span>),\n              <span class=\"hljs-comment\">\/\/ La cadena localizada deber\u00eda reemplazar '6 Heroes'<\/span>\n              child: Text(<span class=\"hljs-string\">'6 Heroes'<\/span>), \n            ),\n            <span class=\"hljs-comment\">\/\/ ...<\/span>\n          ],\n        ),\n      ),\n    );\n  }\n}\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-21\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Primero, agreguemos el mensaje a nuestro archivo ARB de plantilla en ingl\u00e9s.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-22\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-attr\">\"heroCount\"<\/span>: <span class=\"hljs-string\">\"{count,plural, =0{No heroes yet} =1{1 hero} other{{count} heroes}}\"<\/span>,\n  <span class=\"hljs-attr\">\"@heroCount\"<\/span>: {\n    <span class=\"hljs-attr\">\"placeholders\"<\/span>: {\n      <span class=\"hljs-attr\">\"count\"<\/span>: {}\n    }\n  },\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-22\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Especificamos un <code>count<\/code> marcador de posici\u00f3n en nuestro mensaje, y lo usamos con la sintaxis especial <code>{count,plural,...}<\/code> para definir las diferentes formas plurales.<\/p>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> El par\u00e1metro <code>count<\/code> siempre ser\u00e1 de tipo <code>int<\/code>. Si especificas otro tipo para <code>count<\/code>, Flutter lo ignorar\u00e1 y usar\u00e1 <code>int<\/code> de todos modos.<\/p>\n\n\n\n<p>\ud83d\uddd2\ufe0f <em>Nota \u00bb<\/em> Puedes agregar marcadores de posici\u00f3n adem\u00e1s de <code>count<\/code> a un mensaje plural; se especifican como de costumbre (ver <em>Interpolaci\u00f3n<\/em> arriba).<\/p>\n\n\n\n<p>Flutter admite las siguientes formas plurales.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>zero \u279e <code>=0{No heroes}<\/code><\/li>\n\n\n\n<li>one \u279e <code>=1{One hero}<\/code><\/li>\n\n\n\n<li>two \u279e <code>=2(Two heroes}<\/code><\/li>\n\n\n\n<li>few \u279e <code>few{The {count} heroes}<\/code><\/li>\n\n\n\n<li>many \u279e <code>many{{count} heroes}<\/code><\/li>\n\n\n\n<li>other \u279e <code>other{{count} heroes}<\/code><\/li>\n\n<\/ul>\n\n\n\n<p><code>few<\/code>, <code>many<\/code>, y <code>other<\/code> <a href=\"https:\/\/unicode-org.github.io\/cldr-staging\/charts\/latest\/supplemental\/language_plural_rules.html\">tienen diferentes significados dependiendo del idioma activo<\/a>. La \u00fanica forma requerida en <em>cualquier<\/em> idioma es la forma <code>other<\/code>.<\/p>\n\n\n\n<p>\ud83d\uddd2\ufe0f <em>Nota \u00bb<\/em> No necesit\u00e1bamos usar la forma cero <code>=0<\/code> en nuestro mensaje en ingl\u00e9s anterior. Si la hubi\u00e9ramos omitido, Flutter habr\u00eda usado nuestra forma <code>other<\/code> en su lugar.<\/p>\n\n\n\n<p>Muy bien, agreguemos nuestro mensaje en \u00e1rabe. Como mencionamos anteriormente, el \u00e1rabe tiene seis formas plurales.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-23\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\">{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-attr\">\"heroCount\"<\/span>: <span class=\"hljs-string\">\"{count,plural, =0{\u0644\u0627 \u062a\u0648\u062c\u062f \u0623\u0628\u0637\u0627\u0644 \u0628\u0639\u062f} =1{\u0628\u0637\u0644 \u0648\u0627\u062d\u062f} =2{\u0628\u0637\u0644\u0627\u0646} few{{count} \u0623\u0628\u0637\u0627\u0644} many{{count} \u0628\u0637\u0644} other{{count} \u0628\u0637\u0644}}\"<\/span>,\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-23\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Ahora conectemos todo y usemos nuestro nuevo mensaje en nuestro <code>HeroList<\/code> widget.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-24\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-comment\">\/\/ ...<\/span>\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context);\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      <span class=\"hljs-comment\">\/\/ ...<\/span>\n      body: Padding(\n        <span class=\"hljs-comment\">\/\/ ...<\/span>\n        child: Column(\n          children: &#91;\n            Padding(\n              padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.only(bottom: <span class=\"hljs-number\">8.0<\/span>),\n              child: Text(t.heroCount(<span class=\"hljs-number\">6<\/span>)),\n            ),\n            <span class=\"hljs-comment\">\/\/ ...<\/span>\n          ],\n        ),\n      ),\n    );\n  }\n}\n\n<span class=\"hljs-comment\">\/\/ ...<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-24\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Por supuesto, en una aplicaci\u00f3n de producci\u00f3n, el par\u00e1metro de conteo pasado a <code>t.heroCount()<\/code> ser\u00eda din\u00e1mico. Flutter elige la forma plural correcta de nuestro mensaje dependiendo de la localizaci\u00f3n activa.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14107\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-14107\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-plural-forms-1024x379.png\" alt=\"Formas plurales en ingl\u00e9s en nuestra app | Phrase\" width=\"500\" height=\"185\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-plural-forms-1024x379.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-plural-forms-300x111.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-plural-forms-768x284.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-plural-forms.png 1485w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><figcaption class=\"wp-element-caption\">Formas plurales en ingl\u00e9s en nuestra app<\/figcaption><\/figure>\n\n\n\n<figure class=\"wp-block-image wp-image-14108\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-14108\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-plural-forms-1024x716.png\" alt=\"Formas plurales en \u00e1rabe en nuestra app | Phrase\" width=\"500\" height=\"350\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-plural-forms-1024x716.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-plural-forms-300x210.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-plural-forms-768x537.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-plural-forms.png 1485w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><figcaption class=\"wp-element-caption\">Formas plurales en \u00e1rabe en nuestra app<\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"formato-de-numeros\"><\/span>Formato de n\u00fameros<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Podemos formatear n\u00fameros en nuestros mensajes localizados usando nuestro amigo el <code>placeholders<\/code> objeto en las entradas compa\u00f1eras de nuestro archivo de plantilla ARB (ingl\u00e9s en nuestro caso). No hay un buen lugar para poner el formato de n\u00fameros en nuestra peque\u00f1a aplicaci\u00f3n de demostraci\u00f3n, as\u00ed que solo pretendamos que tenemos una aplicaci\u00f3n de comercio electr\u00f3nico para demostrar.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-25\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ app_en.arb en la aplicaci\u00f3n de ejemplo que tiene un carrito de compras <\/span>\n{\n  <span class=\"hljs-attr\">\"itemTotal\"<\/span>: <span class=\"hljs-string\">\"Your total is: {value}\"<\/span>,\n  <span class=\"hljs-attr\">\"@itemTotal\"<\/span>: {\n    <span class=\"hljs-attr\">\"placeholders\"<\/span>: {\n      <span class=\"hljs-attr\">\"value\"<\/span>: {\n        <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"double\"<\/span>,\n        <span class=\"hljs-attr\">\"format\"<\/span>: <span class=\"hljs-string\">\"currency\"<\/span>\n      }\n    }\n  }\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-25\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Nota que especificamos un <code>tipo<\/code> expl\u00edcito y un <code>formato<\/code> para controlar c\u00f3mo se mostrar\u00e1 el n\u00famero. Como de costumbre, podemos traducir nuestro mensaje en nuestros otros archivos de localizaci\u00f3n.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-26\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ app_ar.arb en la aplicaci\u00f3n de ejemplo que tiene un carrito de compras<\/span>\n{ <span class=\"hljs-attr\">\"itemTotal\"<\/span>: <span class=\"hljs-string\">\"Total: {value}\"<\/span> }<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-26\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Despu\u00e9s de recargar nuestra aplicaci\u00f3n, podemos usar nuestro mensaje como de costumbre.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-27\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-comment\">\/\/ En un Widget<\/span>\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ En alg\u00fan constructor de widget con un contexto<\/span>\n<span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context);\n<span class=\"hljs-keyword\">var<\/span> message = t.itemTotal(<span class=\"hljs-number\">56.12<\/span>);\n<span class=\"hljs-comment\">\/\/ =&gt; \"Tu total es USD56.12\" cuando la localizaci\u00f3n actual es ingl\u00e9s<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; \"\u0625\u062c\u0645\u0627\u0644\u064a: EGP56.12\" cuando la localizaci\u00f3n actual es \u00e1rabe<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-27\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> No puedes anular el n\u00famero <code>formato<\/code>s por localizaci\u00f3n. El formato que especifiques en tu plantilla de localizaci\u00f3n (ingl\u00e9s en nuestro caso) se utilizar\u00e1 en todas las localizaciones independientemente de cualquier <code>formato<\/code> que anules en tus otros archivos de localizaci\u00f3n.<\/p>\n\n\n\n<p>Recuerda que, entre bastidores, Flutter est\u00e1 utilizando la biblioteca <a href=\"https:\/\/pub.dev\/packages\/intl\">Dart intl<\/a> para la mayor parte de su trabajo de \u00ednternacionalizaci\u00f3n. El formato de moneda que usamos arriba es uno de varios formatos integrados en el formateador de n\u00fameros intl. Otros formatos incluyen decimales, porcentajes y m\u00e1s.<\/p>\n\n\n\n<p>\ud83d\udd17 <em>Recurso \u00bb<\/em> Consulta la <a href=\"https:\/\/docs.google.com\/document\/d\/10e0saTfAv32OZLRmONy866vnaw0I2jwL8zukykpgWBc\/edit#heading=h.4jrxhcva98zs\">gu\u00eda del usuario oficial<\/a> para todos los formatos disponibles.`<\/p>\n\n\n\n<p>Sin embargo, no tenemos que depender de Flutter para pasar nuestros n\u00fameros a intl. Podemos usar intl directamente para obtener m\u00e1s control sobre nuestro formateo de n\u00fameros.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-28\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:intl\/intl.dart'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ En alg\u00fan constructor de Widget con un contexto<\/span>\n<span class=\"hljs-keyword\">var<\/span> currentLocale = AppLocalizations.of(context).localeName;\n<span class=\"hljs-keyword\">var<\/span> compact = NumberFormat.compact(locale: currentLocale).format(<span class=\"hljs-number\">6000000<\/span>);\n<span class=\"hljs-comment\">\/\/ =&gt; \"6M\" cuando la configuraci\u00f3n regional actual es ingl\u00e9s de EE. UU.<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; \"\u0666 \u0645\u0644\u064a\u0648\u0646\" cuando la configuraci\u00f3n regional actual es \u00e1rabe egipcio<\/span>\n\n<span class=\"hljs-keyword\">var<\/span> simpleCurrency = NumberFormat.simpleCurrency(locale: currentLocale).format(<span class=\"hljs-number\">14.24<\/span>);\n<span class=\"hljs-comment\">\/\/ =&gt; \"$14.24\" cuando la configuraci\u00f3n regional actual es ingl\u00e9s de EE. UU.<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; \"\u062c.\u0645.\u200f \u0661\u0664\u066b\u0662\u0664\" cuando la configuraci\u00f3n regional actual es \u00e1rabe<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-28\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>\ud83d\udd17 <em>Recurso \u00bb<\/em> No tienes por qu\u00e9 usar los formatos predefinidos como <code>compact<\/code> y <code>simpleCurrency<\/code>. El constructor internacional <code>NumberFormat<\/code> te da control granular sobre tus formatos de n\u00famero. Lee todo sobre el tema en <a href=\"https:\/\/pub.dev\/documentation\/intl\/latest\/intl\/NumberFormat-class.html\">la documentaci\u00f3n oficial<\/a>.<\/p>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> La \u00fanica forma en que pude obtener n\u00fameros \u00e1rabes orientales (\u0661\u060c\u0662\u060c\u0663\u2026) renderizando para \u00e1rabe es configurando el par\u00e1metro <code>locale<\/code> como <code>\"ar_EG\"<\/code> (\u00e1rabe egipcio). Ni <code>\"ar\"<\/code> ni ninguna variante de <code>\"ar_XX\"<\/code> que no fuera el egipcio me funcion\u00f3.<\/p>\n\n\n\n<p>\u270b <em>Atenci\u00f3n \u00bb<\/em> Los formatos no me funcionaron con la variable plural <code>count<\/code>. Parece que Flutter est\u00e1 sobrescribiendo el formato cuando procesa plurales. Si puedes obtener formatos en tus plurales, por favor h\u00e1znoslo saber c\u00f3mo lo hiciste en los comentarios a continuaci\u00f3n.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"formato-de-fecha\"><\/span>Formato de fecha<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Nuestros h\u00e9roes actualmente tienen fechas de nacimiento codificadas que no est\u00e1n localizadas, lo cual no es lo ideal.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14109\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-14109\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-unlocalized-date-1024x332.png\" alt=\"Formato de fecha en ingl\u00e9s en localizaci\u00f3n \u00e1rabe | Phrase\" width=\"550\" height=\"178\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-unlocalized-date-1024x332.png 1024w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-unlocalized-date-300x97.png 300w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-unlocalized-date-768x249.png 768w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-unlocalized-date.png 1115w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><figcaption class=\"wp-element-caption\">Queremos que esta fecha est\u00e9 localizada en \u00e1rabe<\/figcaption><\/figure>\n\n\n\n<p>Recuerda que estamos renderizando a cada uno de nuestros h\u00e9roes con un widget <code>HeroCard<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-29\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroCard<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> name;\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> born;\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> bio;\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> imagePath;\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n\n  <span class=\"hljs-keyword\">const<\/span> HeroCard({\n    Key key,\n    <span class=\"hljs-keyword\">this<\/span>.name = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.born = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.bio = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.imagePath,\n  }) : <span class=\"hljs-keyword\">super<\/span>(key: key);\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-comment\">\/\/ ...<\/span>\n    <span class=\"hljs-keyword\">return<\/span> Card(\n      child: Padding(\n        <span class=\"hljs-comment\">\/\/ ...<\/span>\n        Padding(\n          padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.only(top: <span class=\"hljs-number\">2<\/span>, bottom: <span class=\"hljs-number\">4<\/span>),\n          child: Text(\n            born.isEmpty ? <span class=\"hljs-string\">''<\/span> : <span class=\"hljs-string\">'Born <span class=\"hljs-subst\">$born<\/span>'<\/span>,\n            <span class=\"hljs-comment\">\/\/ ...<\/span>\n          ),\n        ),\n        <span class=\"hljs-comment\">\/\/ ...<\/span>\n      ),\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-29\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Para formatear la fecha <code>born<\/code> para cada regi\u00f3n que admite nuestra aplicaci\u00f3n, primero agregamos algunos nuevos mensajes localizados con valores de fecha interpolados.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-30\" data-shcb-language-name=\"JSON \/ JSON con comentarios\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-comment\">\/\/ English<\/span>\n{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-attr\">\"heroBorn\"<\/span>: <span class=\"hljs-string\">\"Born {date}\"<\/span>,\n  <span class=\"hljs-attr\">\"@heroBorn\"<\/span>: {\n    <span class=\"hljs-attr\">\"placeholders\"<\/span>: {\n      <span class=\"hljs-attr\">\"date\"<\/span>: {\n        <span class=\"hljs-attr\">\"type\"<\/span>: <span class=\"hljs-string\">\"DateTime\"<\/span>,\n        <span class=\"hljs-attr\">\"format\"<\/span>: <span class=\"hljs-string\">\"yMMMd\"<\/span>\n      }\n    }\n  },\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}\n\n<span class=\"hljs-comment\">\/\/ \u00c1rabe<\/span>\n{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-attr\">\"heroBorn\"<\/span>: <span class=\"hljs-string\">\"\u062a\u0627\u0631\u064a\u062e \u0627\u0644\u0645\u064a\u0644\u0627\u062f {date}\"<\/span>,\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-30\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON con comentarios<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Cuando definimos nuestro <code>date<\/code> marcador de posici\u00f3n en nuestro archivo de localizaci\u00f3n de plantilla, necesitamos darle el tipo <code>DateTime<\/code>. Luego podemos usar un <code>format<\/code> para especificar c\u00f3mo queremos mostrar la fecha. El formato <code>yMMMd<\/code> que definimos arriba significa \u201ca\u00f1o, mes abreviado, d\u00eda\u201d, que en ingl\u00e9s estadounidense se ver\u00eda algo como \u201cDec 9, 1906\u201d.<\/p>\n\n\n\n<p>\ud83d\udd17 <em>Recurso \u00bb<\/em> De hecho, entre bastidores, Flutter est\u00e1 usando la clase <code>DateFormat<\/code> de intl, generando c\u00f3digo como <code>DateFormat.yMMMd(localeName).format(date)<\/code>. El constructor nombrado <code>yMMMd<\/code> es un atajo \u00fatil llamado \u201cesqueleto\u201d, y hay bastantes que podemos usar. Cons\u00faltalos en <a href=\"https:\/\/pub.dev\/documentation\/intl\/latest\/intl\/DateFormat-class.html\">la documentaci\u00f3n oficial de DateFormat<\/a>.<\/p>\n\n\n\n<p>\ud83d\uddd2\ufe0f\u00a0<em>Nota \u00bb<\/em> No tuvimos que llamar a nuestra variable de marcador de posici\u00f3n <code>date<\/code>. Podr\u00edamos haberle dado cualquier nombre, siempre que fuera un nombre de par\u00e1metro de funci\u00f3n Dart v\u00e1lido.<\/p>\n\n\n\n<p>Bien, conectemos esto en nuestro widget para mostrar nuestros nuevos mensajes.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-31\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:intl\/intl.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroCard<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> name;\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> born;\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> bio;\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">String<\/span> imagePath;\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-keyword\">final<\/span> <span class=\"hljs-built_in\">DateTime<\/span> bornDateTime;\n\n  HeroCard({\n    Key key,\n    <span class=\"hljs-keyword\">this<\/span>.name = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.born = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.bio = <span class=\"hljs-string\">''<\/span>,\n    <span class=\"hljs-keyword\">this<\/span>.imagePath,\n  }) : bornDateTime = DateFormat(<span class=\"hljs-string\">'d MMMM yyyy'<\/span>).parse(born),\n       <span class=\"hljs-keyword\">super<\/span>(key: key);\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-comment\">\/\/ ...<\/span>\n    <span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context);\n    <span class=\"hljs-keyword\">return<\/span> Card(\n      child: Padding(\n        <span class=\"hljs-comment\">\/\/ ...<\/span>\n        Padding(\n          padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.only(top: <span class=\"hljs-number\">2<\/span>, bottom: <span class=\"hljs-number\">4<\/span>),\n          child: Text(\n            born.isEmpty ? <span class=\"hljs-string\">''<\/span> : t.heroBorn(bornDateTime),\n            <span class=\"hljs-comment\">\/\/ ...<\/span>\n          ),\n        ),\n        <span class=\"hljs-comment\">\/\/ ...<\/span>\n      ),\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-31\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Se nos entrega la fecha de nacimiento de un h\u00e9roe como <code>String<\/code>, as\u00ed que necesitamos convertirlo a <code>DateTime<\/code> primero. Usamos la clase <code>DateFormat<\/code> de intl para hacer esto en nuestro constructor de widget.<\/p>\n\n\n\n<p>En el m\u00e9todo <code>build<\/code>, simplemente pasamos el <code>DateTime<\/code> analizado a nuestro mensaje localizado <code>t.heroBorn()<\/code>. Esto nos da fechas bien localizadas.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14121\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14121\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-date-1.png\" alt=\"Versi\u00f3n en ingl\u00e9s de la tarjeta de Alan Turing | Phrase\" width=\"550\" height=\"178\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-date-1.png 583w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-en-date-1-300x97.png 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/figure>\n\n\n\n<figure class=\"wp-block-image wp-image-14111\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14111\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-date.png\" alt=\"Versi\u00f3n en \u00e1rabe de la tarjeta de Alan Turing | Phrase\" width=\"550\" height=\"201\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-date.png 583w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-ar-date-300x110.png 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/figure>\n\n\n\n<p>\u00bfQu\u00e9 pasa si no queremos usar ninguno de los esqueletos predefinidos y queremos personalizar completamente nuestros formatos de fecha? Bueno, al igual que el formato de n\u00fameros (ver arriba), necesitar\u00edamos usar la clase <code>intl.DateFormat<\/code> directamente. Supongamos que queremos mostrar las fechas de nacimiento de nuestro h\u00e9roes en un formato como \u201c1912-06-23\u201d. Haremos algo como lo siguiente.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-32\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:intl\/intl.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ In widget builder with context<\/span>\n<span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context);\n<span class=\"hljs-keyword\">var<\/span> bornDateTime = DateTime(<span class=\"hljs-number\">1912<\/span>, <span class=\"hljs-number\">6<\/span>, <span class=\"hljs-number\">23<\/span>);\n<span class=\"hljs-keyword\">var<\/span> formattedBorn = DateFormat(<span class=\"hljs-string\">'yyyy-MM-dd'<\/span>, t.localeName).format(bornDateTime);\n<span class=\"hljs-keyword\">var<\/span> message = t.heroBorn(formattedBorn);\n<span class=\"hljs-comment\">\/\/ =&gt; \"1912-06-23\" in US English<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; \"\u0661\u0669\u0661\u0662-\u0660\u0666-\u0662\u0663\" in Egyptian Arabic<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-32\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Nuestros mensajes localizados de <code>heroBorn<\/code> en nuestros archivos ARB tomar\u00edan simplemente par\u00e1metros regulares de <code>Object<\/code> o <code>String<\/code>, ya que ya hemos hecho el formato para ellos.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"direccionalidad-de-izquierda-a-derecha-y-de-derecha-a-izquierda\"><\/span>Direccionalidad: de izquierda a derecha y de derecha a izquierda<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Mientras que el ingl\u00e9s es un idioma de izquierda a derecha (LTR), el \u00e1rabe va en la otra direcci\u00f3n y se organiza de derecha a izquierda (RTL). Esto est\u00e1 causando actualmente un problema para nosotros cuando nuestra aplicaci\u00f3n se usa en un dispositivo con \u00e1rabe como idioma del sistema.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14114\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-14114\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-broken-ar.png\" alt=\"Versi\u00f3n \u00e1rabe de Heroes of Computer Science sin suficiente padding | Phrase\" width=\"550\" height=\"520\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-broken-ar.png 662w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-broken-ar-300x284.png 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><figcaption class=\"wp-element-caption\">F\u00edjate en la falta de padding entre im\u00e1genes y texto<\/figcaption><\/figure>\n\n\n\n<p>La imagen y el texto en cada tarjeta est\u00e1n alineados porque estamos usando <code>EdgeInsets.only(right)<\/code> para definir el padding alrededor de nuestra imagen.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-33\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:intl\/intl.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n\n<span class=\"hljs-comment\">\/\/ In widget builder with context<\/span>\n<span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context);\n<span class=\"hljs-keyword\">var<\/span> bornDateTime = <span class=\"hljs-built_in\">DateTime<\/span>(<span class=\"hljs-number\">1912<\/span>, <span class=\"hljs-number\">6<\/span>, <span class=\"hljs-number\">23<\/span>);\n<span class=\"hljs-keyword\">var<\/span> formattedBorn = DateFormat(<span class=\"hljs-string\">'yyyy-MM-dd'<\/span>, t.localeName).format(bornDateTime);\n<span class=\"hljs-keyword\">var<\/span> message = t.heroBorn(formattedBorn);\n<span class=\"hljs-comment\">\/\/ =&gt; \"1912-06-23\" in US English<\/span>\n<span class=\"hljs-comment\">\/\/ =&gt; \"\u0661\u0669\u0661\u0662-\u0660\u0666-\u0662\u0663\" in Egyptian Arabic<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-33\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Esto funciona en idiomas LTR, donde queremos un margen derecho entre la imagen y el texto. En idiomas RTL, sin embargo, queremos el margen a la <em>izquierda<\/em>.<\/p>\n\n\n\n<p>Un remedio f\u00e1cil aqu\u00ed es usar <code>EdgeInsetsDirectional<\/code> en lugar de <code>EdgeInsets<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-34\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\">\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroCard<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n\n  @override\n  Widget build(BuildContext context) {\n    <span class=\"hljs-comment\">\/\/ ...<\/span>\n    <span class=\"hljs-keyword\">return<\/span> Card(\n      child: Padding(\n        padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.all(<span class=\"hljs-number\">4.0<\/span>),\n        child: Row(\n          crossAxisAlignment: CrossAxisAlignment.start,\n          children: &lt;Widget&gt;&#91;\n            Padding(\n              padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsetsDirectional.only(end: <span class=\"hljs-number\">8.0<\/span>),\n              child: ClipRRect(\n                <span class=\"hljs-comment\">\/\/ Imagen en retrato...<\/span>\n              ),\n            ),\n            Expanded(\n              <span class=\"hljs-comment\">\/\/ Widgets de texto...<\/span>\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-34\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Observa que usamos <code>end<\/code> en lugar de <code>right<\/code> para establecer el padding entre la imagen y el texto. <code>EdgeInsetsDirectional<\/code> es uno de los pocos widgets de dise\u00f1o de Flutter que tienen en cuenta la direcci\u00f3n de la regi\u00f3n. Estos widgets usan los par\u00e1metros <code>start<\/code> y <code>end<\/code> en lugar de <code>left<\/code> y <code>right<\/code>. Y lo genial es que estos widgets direccionales har\u00e1n lo correcto autom\u00e1ticamente para la regi\u00f3n activa:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><code>start<\/code> == <code>left<\/code> para idiomas le\u00eddos de izquierda a derecha<\/li>\n\n\n\n<li><code>start<\/code> == <code>right<\/code> para idiomas le\u00eddos de derecha a izquierda<\/li>\n\n\n\n<li><code>end<\/code> == <code>right<\/code> para idiomas le\u00eddos de izquierda a derecha<\/li>\n\n\n\n<li><code>end<\/code> == <code>left<\/code> para idiomas le\u00eddos de derecha a izquierda<\/li>\n\n<\/ul>\n\n\n\n<p>Con este peque\u00f1o ajuste al c\u00f3digo, nuestro problema de dise\u00f1o se ha resuelto.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14115\"><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-14115\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-fixed-ar.png\" alt=\"Versi\u00f3n \u00e1rabe de Heroes of Computer Science con padding | Phrase\" width=\"550\" height=\"517\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-fixed-ar.png 664w, https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-fixed-ar-300x282.png 300w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><figcaption class=\"wp-element-caption\">El dise\u00f1o ahora se adapta a la direcci\u00f3n de la regi\u00f3n activa<\/figcaption><\/figure>\n\n\n\n<p>\ud83d\udd17 <em>Recurso \u00bb<\/em> En el momento de escribir, la documentaci\u00f3n oficial de Flutter enumera los siguientes widgets direccionales:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li><a href=\"https:\/\/api.flutter.dev\/flutter\/painting\/EdgeInsetsDirectional-class.html\">EdgeInsetsDirectional<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/api.flutter.dev\/flutter\/painting\/AlignmentDirectional-class.html\">AlignmentDirectional<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/api.flutter.dev\/flutter\/painting\/BorderDirectional-class.html\">BorderDirectional<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/api.flutter.dev\/flutter\/painting\/BorderRadiusDirectional-class.html\">BorderRadiusDirectional<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/PositionedDirectional-class.html\">PositionedDirectional<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/api.flutter.dev\/flutter\/widgets\/AnimatedPositionedDirectional-class.html\">AnimatedPositionedDirectional<\/a><\/li>\n\n<\/ul>\n\n\n\n<p>Con todo eso en su sitio, nuestra aplicaci\u00f3n final tiene un aspecto de lo m\u00e1s internacionalizado.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-14142\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-14142\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2021\/05\/flutteri18n2021p2-final-en-ar-1-e1699439769197.png\" alt=\"Comparaci\u00f3n lateral de la versi\u00f3n en \u00e1rabe e ingl\u00e9s de Heroes of Computer Science | Phrase\" width=\"800\" height=\"693\" \/><\/figure>\n\n\n\n<p>\ud83d\udd17 Recurso \u00bb Obt\u00e9n el c\u00f3digo completo para nuestra aplicaci\u00f3n de demostraci\u00f3n en <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-2-i18n-2021\">nuestro repositorio de GitHub<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"agregando-activos-localizados\"><\/span>Agregando activos localizados<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Localizar im\u00e1genes en Flutter implica usar diferentes conjuntos de im\u00e1genes para diferentes localizaciones o idiomas en tu aplicaci\u00f3n. Esto se suele hacer para mostrar im\u00e1genes con texto o contenido que coincida con el idioma preferido del usuario.<\/p>\n\n\n\n<p>Vamos a agregar una bandera, que se muestra de manera diferente dependiendo de la regi\u00f3n del usuario.<\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-68808\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-68808\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/flutter-l10n-flag-language.png\" alt=\"Bandera del pa\u00eds a\u00f1adida a una aplicaci\u00f3n Flutter localizada | Phrase\" width=\"550\" height=\"764\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/flutter-l10n-flag-language.png 618w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/flutter-l10n-flag-language-216x300.png 216w\" sizes=\"auto, (max-width: 550px) 100vw, 550px\" \/><\/figure>\n\n\n\n<p>Comenzaremos agregando las im\u00e1genes, una para cada localizaci\u00f3n que planeamos soportar. Deber\u00edamos organizar estas im\u00e1genes en una estructura de carpetas basada en localizaciones, por ejemplo:<!-- notionvc: fc5508b4-43d5-43ba-a914-18ef9baa152d --><\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-35\" data-shcb-language-name=\"texto plano\" data-shcb-language-slug=\"plaintext\"><span><code class=\"hljs language-plaintext\">\u2514\u2500\u2500 assets\/\n    \u2514\u2500\u2500 images\/\n        \u251c\u2500\u2500 eg\/\n        \u2502   \u2514\u2500\u2500 flag.jpg\n        \u251c\u2500\u2500 us\/\n        \u2502   \u2514\u2500\u2500 flag.jpg\n        \u2514\u2500\u2500 flag.jpg<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-35\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">texto plano<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">plaintext<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Para este tutorial, agregaremos im\u00e1genes de bandera para Egipto y los EE. UU. El archivo directamente en la carpeta de im\u00e1genes (sin localizaci\u00f3n) es una imagen de respaldo para otras regiones.<\/p>\n\n\n\n<p>A continuaci\u00f3n, registremos los archivos en el archivo <code>pubspec.yml<\/code>.<\/p>\n\n\n\n<p><!-- notionvc: 8d2588ec-6a65-4ecd-a48b-892e51f0c4be --><\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-36\" data-shcb-language-name=\"YAML\" data-shcb-language-slug=\"yaml\"><span><code class=\"hljs language-yaml\"><span class=\"hljs-comment\"># pubspec.yml<\/span>\n\n<span class=\"hljs-comment\"># ...<\/span>\n\n<span class=\"hljs-attr\">flutter:<\/span>\n  <span class=\"hljs-comment\"># ...<\/span>\n  <span class=\"hljs-attr\">assets:<\/span>\n  <span class=\"hljs-comment\"># ...<\/span>\n    <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">assets\/images\/in\/flag.jpg<\/span>\n    <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">assets\/images\/us\/flag.jpg<\/span>\n    <span class=\"hljs-bullet\">-<\/span> <span class=\"hljs-string\">assets\/images\/flag.jpg<\/span>\n\n<span class=\"hljs-comment\"># ...<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-36\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">YAML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">yaml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Ahora podemos cargar las im\u00e1genes en nuestro archivo <code>hero_list.dart<\/code>:<!-- notionvc: 8a12d860-6906-4664-bced-66bf768073ee --><\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-37\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\">\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'..\/widgets\/hero_card.dart'<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-comment\">\/\/ ...<\/span>\n    <span class=\"hljs-built_in\">String<\/span> getImagePath(<span class=\"hljs-built_in\">String<\/span> imageName) {\n      <span class=\"hljs-built_in\">String<\/span> basePath = <span class=\"hljs-string\">'assets\/images\/'<\/span>;\n\n      <span class=\"hljs-comment\">\/\/ Cuando el c\u00f3digo de pa\u00eds no es compatible,<\/span>\n      <span class=\"hljs-comment\">\/\/ mostramos la imagen de respaldo.<\/span>\n      <span class=\"hljs-keyword\">if<\/span> (locale.countryCode?.isEmpty == <span class=\"hljs-keyword\">true<\/span>) {\n        <span class=\"hljs-keyword\">return<\/span>  basePath + <span class=\"hljs-string\">'flag.jpg'<\/span>;\n      }\n\n      <span class=\"hljs-built_in\">String<\/span> localePath = <span class=\"hljs-string\">'<span class=\"hljs-subst\">${locale.countryCode!.toLowerCase()}<\/span>\/'<\/span>;\n      <span class=\"hljs-keyword\">return<\/span> basePath + localePath + imageName;\n    }\n\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      <span class=\"hljs-comment\">\/\/ ...<\/span>\n      body: Padding(\n        padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.all(<span class=\"hljs-number\">16<\/span>),\n        child: Column(\n          children: &#91;\n\t    <span class=\"hljs-comment\">\/\/ ...<\/span>\n            Padding(\n              padding: <span class=\"hljs-keyword\">const<\/span> EdgeInsets.only(bottom: <span class=\"hljs-number\">2.0<\/span>),\n              child: Image.asset(\n                getImagePath(<span class=\"hljs-string\">'flag.jpg'<\/span>),\n                width: <span class=\"hljs-number\">40<\/span>,\n                height: <span class=\"hljs-number\">40<\/span>,\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-37\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Ahora, en el archivo <code>main.dart<\/code>, haz los siguientes cambios<!-- notionvc: bb9617c5-f2af-4173-becf-6ef08ae5d950 --><\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-38\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\">...\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyApp<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> MyApp({<span class=\"hljs-keyword\">super<\/span>.key});\n\n  <span class=\"hljs-comment\">\/\/ Este widget es la ra\u00edz de tu aplicaci\u00f3n.<\/span>\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">return<\/span> MaterialApp(\n    ...    \n    supportedLocales: &#91;\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'ar'<\/span>, <span class=\"hljs-string\">''<\/span>),\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'en'<\/span>, <span class=\"hljs-string\">''<\/span>),\n\t\t\t\t<span class=\"hljs-comment\">\/\/ Agregar los c\u00f3digos de regi\u00f3n soportados <\/span>\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'ar'<\/span>, <span class=\"hljs-string\">'EG'<\/span>),\n        <span class=\"hljs-keyword\">const<\/span> Locale(<span class=\"hljs-string\">'en'<\/span>, <span class=\"hljs-string\">'US'<\/span>),\n      ],\n   ...\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-38\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Ahora la aplicaci\u00f3n muestra el recurso apropiado para la localizaci\u00f3n del usuario y muestra un recurso alternativo si su localizaci\u00f3n no es compatible. <!-- notionvc: 11d89077-09d6-4de7-9bed-5fc1c4306970 --><\/p>\n\n\n\n<figure class=\"wp-block-image wp-image-69078 size-full\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-69078 size-full\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/computer-science-hero-demo-app-screen.png\" alt=\"Pantalla de la aplicaci\u00f3n de demostraci\u00f3n mostrando el recurso apropiado para la localizaci\u00f3n del usuario y un recurso alternativo para localizaciones no soportadas | Phrase\" width=\"600\" height=\"301\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/computer-science-hero-demo-app-screen.png 600w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/computer-science-hero-demo-app-screen-300x151.png 300w\" sizes=\"auto, (max-width: 600px) 100vw, 600px\" \/><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"cambiando-el-idioma-en-la-aplicacion\"><\/span>Cambiando el idioma en la aplicaci\u00f3n<!-- notionvc: 9d86816e-04be-46f7-a903-fcb6f0d3bae1 --><span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>A veces un usuario querr\u00e1 tener su sistema operativo en un idioma y una aplicaci\u00f3n espec\u00edfica en otro. Para acomodar eso, agreguemos un selector de idioma en nuestra aplicaci\u00f3n. Deber\u00eda funcionar para todas las plataformas compatibles con Flutter. <!-- notionvc: 9444f110-143a-471a-955f-a1a9bba64d3b --><\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-image-69084\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-69084 aligncenter\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/in-app-language.png\" alt=\"Pantalla de la aplicaci\u00f3n de demostraci\u00f3n mostrando los idiomas en la aplicaci\u00f3n | Phrase\" width=\"341\" height=\"480\" srcset=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/in-app-language.png 341w, https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/in-app-language-213x300.png 213w\" sizes=\"auto, (max-width: 341px) 100vw, 341px\" \/><\/figure>\n\n\n\n<p>En el archivo <code>main.dart<\/code>, haremos los siguientes cambios:<\/p>\n\n\n\n<p><!-- notionvc: 0530a815-e9ef-468c-8f66-36c065263ac7 --><\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-39\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">void<\/span> main() {\n  runApp(<span class=\"hljs-keyword\">const<\/span> MyApp());\n}\n\n<span class=\"hljs-comment\">\/\/ Necesitamos hacer que MyApp sea Stateful porque<\/span>\n<span class=\"hljs-comment\">\/\/ necesita reaccionar cuando la Localizaci\u00f3n cambia.<\/span>\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">MyApp<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatefulWidget<\/span> <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> MyApp({Key? key}) : <span class=\"hljs-keyword\">super<\/span>(key: key);\n\n  <span class=\"hljs-meta\">@override<\/span>\n  State&lt;MyApp&gt; createState() =&gt; _MyAppState();\n\n  <span class=\"hljs-keyword\">static<\/span> <span class=\"hljs-keyword\">void<\/span> setLocale(BuildContext context, Locale newLocale) {\n    _MyAppState? state = context.findAncestorStateOfType&lt;_MyAppState&gt;();\n    state?.setLocale(newLocale);\n  }\n}\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">_MyAppState<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">State<\/span>&lt;<span class=\"hljs-title\">MyApp<\/span>&gt; <\/span>{\n  Locale? _locale;\n\n  setLocale(Locale locale) {\n    setState(() {\n      _locale = locale;\n    });\n  }\n\n  <span class=\"hljs-comment\">\/\/ Este widget es la ra\u00edz de tu aplicaci\u00f3n.<\/span>\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n\n    <span class=\"hljs-keyword\">return<\/span> MaterialApp(\n      <span class=\"hljs-comment\">\/\/ ...<\/span>\n      locale: _locale,\n      initialRoute: <span class=\"hljs-string\">'\/'<\/span>,\n      routes: {\n        <span class=\"hljs-string\">'\/'<\/span>: (context) {\n          <span class=\"hljs-keyword\">return<\/span> HeroList(title: AppLocalizations.of(context)!.appTitle);\n        },\n      },\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-39\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Ahora, en el archivo <code>hero_list.dart<\/code>, hagamos el men\u00fa desplegable y llamemos al m\u00e9todo <code>setLocale()<\/code> que definimos arriba.<\/p>\n\n\n\n<p><!-- notionvc: a23338ef-f12b-4f8c-a1ac-fc207a9d47b9 --><\/p>\n\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-40\" data-shcb-language-name=\"Dart\" data-shcb-language-slug=\"dart\"><span><code class=\"hljs language-dart\"><span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter\/material.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'package:flutter_gen\/gen_l10n\/app_localizations.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'..\/main.dart'<\/span>;\n<span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">'..\/widgets\/hero_card.dart'<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">HeroList<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">StatelessWidget<\/span> <\/span>{\n  <span class=\"hljs-comment\">\/\/ ...<\/span>\n  <span class=\"hljs-meta\">@override<\/span>\n  Widget build(BuildContext context) {\n    <span class=\"hljs-keyword\">var<\/span> t = AppLocalizations.of(context)!;\n    <span class=\"hljs-keyword\">final<\/span> Locale locale = Localizations.localeOf(context);\n    <span class=\"hljs-comment\">\/\/ Opciones del men\u00fa desplegable<\/span>\n    <span class=\"hljs-keyword\">var<\/span> items = &#91;\n      <span class=\"hljs-string\">'en'<\/span>,\n      <span class=\"hljs-string\">'ar'<\/span>,\n    ];\n\n    <span class=\"hljs-keyword\">return<\/span> Scaffold(\n      appBar: AppBar(\n        title: Text(title),\n        actions: &lt;Widget&gt;&#91;\n          DropdownButton(\n            <span class=\"hljs-comment\">\/\/ Icono de flecha hacia abajo<\/span>\n            icon: <span class=\"hljs-keyword\">const<\/span> Icon(Icons.settings, color: Colors.white,),\n            items: items.map((<span class=\"hljs-built_in\">String<\/span> items) {\n              <span class=\"hljs-keyword\">return<\/span> DropdownMenuItem(\n                value: items,\n                child: Text(items),\n              );\n            }).toList(),\n            onChanged: (<span class=\"hljs-built_in\">String<\/span>? newValue) {\n              MyApp.setLocale(context, Locale(newValue));\n            },\n          ),\n        ],\n      ),\n      <span class=\"hljs-comment\">\/\/ ...<\/span>\n    );\n  }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-40\"><span class=\"shcb-language__label\">Lenguaje del c\u00f3digo:<\/span> <span class=\"shcb-language__name\">Dart<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">dart<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n\n<p>Con eso, el usuario puede seleccionar el idioma de la aplicaci\u00f3n independientemente del idioma del sistema.<\/p>\n\n\n\n<p>\ud83d\uddd2\ufe0f <em>Nota \u00bb<\/em> Antes de seleccionar una localizaci\u00f3n, se establecer\u00e1 en la localizaci\u00f3n predeterminada del sistema del usuario.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full wp-image-69090\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-69090 aligncenter\" src=\"https:\/\/phrase.com\/wp-content\/uploads\/2023\/10\/simulator-screen-recording-iphone-14-plus.gif\" alt=\"Pantalla de grabaci\u00f3n de la aplicaci\u00f3n del simulador en iPhone 14 Plus | Phrase\" width=\"296\" height=\"640\" \/><\/figure>\n\n\n\n<p>\ud83d\uddd2\ufe0f <em>Nota \u00bb<\/em> Antes de que el usuario seleccione manualmente una localizaci\u00f3n en la aplicaci\u00f3n, se utiliza la localizaci\u00f3n del sistema como predeterminada. Sin embargo, la localizaci\u00f3n seleccionada manualmente en la aplicaci\u00f3n por el usuario <strong>no persistir\u00e1<\/strong> cuando se reinicie la aplicaci\u00f3n. Para persistir la preferencia de localizaci\u00f3n en la aplicaci\u00f3n del usuario, necesitas guardar y recuperar la localizaci\u00f3n usando algo como el <a href=\"https:\/\/pub.dev\/packages\/shared_preferences\">plugin de Preferencias Compartidas<\/a>.<\/p>\n\n\n\n<p>El proyecto final est\u00e1 disponible en <a href=\"https:\/\/github.com\/PhraseApp-Blog\/flutter-i18n-v2\">GitHub<\/a>.<\/p>\n\n\n\n<p><!-- notionvc: e6fc0d1e-c22a-45b2-8816-ef3f1c993cdc --><\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><span class=\"ez-toc-section\" id=\"localizacion-flutter-simplificada\"><\/span>Localizaci\u00f3n Flutter simplificada<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p>Esperamos que hayas disfrutado de nuestro tutorial de localizaci\u00f3n Flutter y hayas aprendido algunos trucos \u00fatiles. Ahora, si est\u00e1s listo para llevar tu juego de localizaci\u00f3n a un nivel superior, <a href=\"https:\/\/phrase.com\/es\/platform\/strings\/\">Phrase Strings<\/a> es tu soluci\u00f3n ideal. Phrase Strings, un asistente de localizaci\u00f3n para tus aplicaciones Flutter, incluye soporte para archivos ARB, y es muy intuitivo para los desarrolladores gracias a su API y CLI f\u00e1ciles de usar. Tambi\u00e9n cuenta con un elegante editor de cadenas que facilita la vida para las traducciones.<\/p>\n\n\n\n<p>Adem\u00e1s, se sincroniza sin problemas con GitHub, GitLab y Bitbucket, e incluso ofrece traducciones por aire para aplicaciones m\u00f3viles para manejar la carga pesada de la localizaci\u00f3n, permiti\u00e9ndote concentrarte en el c\u00f3digo que tanto amas. Consulta todas las <a href=\"https:\/\/phrase.com\/es\/roles\/developers\/\">caracter\u00edsticas de Phrase para desarrolladores <\/a>y comprueba por ti mismo c\u00f3mo pueden ayudarte a llevar tus aplicaciones a nivel global m\u00e1s r\u00e1pidamente.<\/p>\n\n\n\n<p><!-- notionvc: 23cc7d5c-db75-40d3-a597-92c2e44cb6b5 --><\/p>\n\n\n\n<p><!-- notionvc: 91de31c5-0f6d-40c2-9d94-f70620d96540 --><\/p>\n\n\n","protected":false},"excerpt":{"rendered":"<p>Vamos a descifrar los secretos de la localizaci\u00f3n Flutter para que puedas hablar el idioma de tus usuarios y seguir tu camino hacia la dominaci\u00f3n global, l\u00ednea de c\u00f3digo tras l\u00ednea de c\u00f3digo.<\/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":[2520],"class_list":["post-133330","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-localizacion-de-software-es"],"acf":[],"_links":{"self":[{"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/posts\/133330","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/comments?post=133330"}],"version-history":[{"count":5,"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/posts\/133330\/revisions"}],"predecessor-version":[{"id":136310,"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/posts\/133330\/revisions\/136310"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/media\/2612"}],"wp:attachment":[{"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/media?parent=133330"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/phrase.com\/es\/wp-json\/wp\/v2\/categories?post=133330"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}