-
Notifications
You must be signed in to change notification settings - Fork 0
/
i18n.html
1645 lines (1595 loc) · 147 KB
/
i18n.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html dir="ltr" lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>API de Internacionalización (I18n) de Rails — Ruby on Rails Guides</title>
<link rel="stylesheet" type="text/css" href="stylesheets/style-v2.css" data-turbo-track="reload">
<link rel="stylesheet" type="text/css" href="stylesheets/print-v2.css" media="print">
<link rel="stylesheet" type="text/css" href="stylesheets/highlight-v2.css" data-turbo-track="reload">
<link rel="icon" href="images/favicon.ico" sizes="any">
<link rel="apple-touch-icon" href="images/icon.png">
<script src="javascripts/@hotwired--turbo.js" data-turbo-track="reload"></script>
<script src="javascripts/clipboard.js" data-turbo-track="reload"></script>
<script src="javascripts/guides.js" data-turbo-track="reload"></script>
<meta property="og:title" content="API de Internacionalización (I18n) de Rails — Ruby on Rails Guides" />
<meta name="description" content="API de Internacionalización (I18n) de RailsLa gema Ruby I18n (abreviatura de internacionalización) que se incluye con Ruby on Rails (a partir de Rails 2.2) proporciona un marco fácil de usar y extensible para traducir su aplicación a un único idioma personalizado distinto del inglés o para proporcionar soporte multilingüe en su aplicación.El proceso de "internacionalización" generalmente significa abstraer todas las cadenas y otros elementos específicos de la configuración regional (como formatos de fecha o moneda) de su aplicación. El proceso de "localización" significa proporcionar traducciones y formatos localizados para estos elementos.1Entonces, en el proceso de internacionalizar su aplicación Rails debe: Asegurarse de tener soporte para I18n. Indicar a Rails dónde encontrar los diccionarios de configuración regional. Indicar a Rails cómo establecer, preservar y cambiar configuraciones regionales. En el proceso de localizar su aplicación probablemente querrá hacer las siguientes tres cosas: Reemplazar o complementar la configuración regional predeterminada de Rails, por ejemplo, formatos de fecha y hora, nombres de meses, nombres de modelos de Active Record, etc. Abstraer cadenas en su aplicación en diccionarios con claves, por ejemplo, mensajes flash, texto estático en sus vistas, etc. Almacenar los diccionarios resultantes en algún lugar. Esta guía lo guiará a través de la API de I18n y contiene un tutorial sobre cómo internacionalizar una aplicación Rails desde el principio.Después de leer esta guía, sabrá: Cómo funciona I18n en Ruby on Rails Cómo usar correctamente I18n en una aplicación RESTful de varias maneras Cómo usar I18n para traducir errores de Active Record o asuntos de correos electrónicos de Action Mailer Algunas otras herramientas para avanzar en el proceso de traducción de su aplicación" />
<meta property="og:description" content="API de Internacionalización (I18n) de RailsLa gema Ruby I18n (abreviatura de internacionalización) que se incluye con Ruby on Rails (a partir de Rails 2.2) proporciona un marco fácil de usar y extensible para traducir su aplicación a un único idioma personalizado distinto del inglés o para proporcionar soporte multilingüe en su aplicación.El proceso de "internacionalización" generalmente significa abstraer todas las cadenas y otros elementos específicos de la configuración regional (como formatos de fecha o moneda) de su aplicación. El proceso de "localización" significa proporcionar traducciones y formatos localizados para estos elementos.1Entonces, en el proceso de internacionalizar su aplicación Rails debe: Asegurarse de tener soporte para I18n. Indicar a Rails dónde encontrar los diccionarios de configuración regional. Indicar a Rails cómo establecer, preservar y cambiar configuraciones regionales. En el proceso de localizar su aplicación probablemente querrá hacer las siguientes tres cosas: Reemplazar o complementar la configuración regional predeterminada de Rails, por ejemplo, formatos de fecha y hora, nombres de meses, nombres de modelos de Active Record, etc. Abstraer cadenas en su aplicación en diccionarios con claves, por ejemplo, mensajes flash, texto estático en sus vistas, etc. Almacenar los diccionarios resultantes en algún lugar. Esta guía lo guiará a través de la API de I18n y contiene un tutorial sobre cómo internacionalizar una aplicación Rails desde el principio.Después de leer esta guía, sabrá: Cómo funciona I18n en Ruby on Rails Cómo usar correctamente I18n en una aplicación RESTful de varias maneras Cómo usar I18n para traducir errores de Active Record o asuntos de correos electrónicos de Action Mailer Algunas otras herramientas para avanzar en el proceso de traducción de su aplicación" />
<meta property="og:locale" content="en_US" />
<meta property="og:site_name" content="Ruby on Rails Guides" />
<meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" />
<meta property="og:type" content="website" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:[email protected]&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Heebo:[email protected]&family=Noto+Sans+Arabic:[email protected]&display=swap" rel="stylesheet">
<meta name="theme-color" content="#C81418">
</head>
<body class="guide">
<nav id="topNav" aria-label="Secondary">
<div class="wrapper">
<strong class="more-info-label">Más en <a href="https://rubyonrails.org/">rubyonrails.org:</a> </strong>
<span class="red-button more-info-button">
Más Ruby on Rails
</span>
<ul class="more-info-links s-hidden">
<li class="more-info"><a href="https://rubyonrails.org/blog">Blog</a></li>
<li class="more-info"><a href="https://guides.rubyonrails.org/">Guías</a></li>
<li class="more-info"><a href="https://api.rubyonrails.org/">API</a></li>
<li class="more-info"><a href="https://discuss.rubyonrails.org/">Foro</a></li>
<li class="more-info"><a href="https://github.com/rails/rails">Contribuir en GitHub</a></li>
</ul>
</div>
</nav>
<header id="page_header">
<div class="wrapper clearfix">
<nav id="feature_nav">
<div class="header-logo">
<a href="index.html" title="Regresar a la página principal de Guías para Edge">Guías</a>
<span id="version_switcher">
Versión:
<select class="guides-version">
<option value="https://edgeguides.rubyonrails.org/" selected>Edge</option>
<option value="https://guides.rubyonrails.org/v7.2/">7.2</option>
<option value="https://guides.rubyonrails.org/v7.1/">7.1</option>
<option value="https://guides.rubyonrails.org/v7.0/">7.0</option>
<option value="https://guides.rubyonrails.org/v6.1/">6.1</option>
<option value="https://guides.rubyonrails.org/v6.0/">6.0</option>
<option value="https://guides.rubyonrails.org/v5.2/">5.2</option>
<option value="https://guides.rubyonrails.org/v5.1/">5.1</option>
<option value="https://guides.rubyonrails.org/v5.0/">5.0</option>
<option value="https://guides.rubyonrails.org/v4.2/">4.2</option>
<option value="https://guides.rubyonrails.org/v4.1/">4.1</option>
<option value="https://guides.rubyonrails.org/v4.0/">4.0</option>
<option value="https://guides.rubyonrails.org/v3.2/">3.2</option>
<option value="https://guides.rubyonrails.org/v3.1/">3.1</option>
<option value="https://guides.rubyonrails.org/v3.0/">3.0</option>
<option value="https://guides.rubyonrails.org/v2.3/">2.3</option>
</select>
</span>
</div>
<ul class="nav">
<li><a class="nav-item" id="home_nav" href="https://rubyonrails.org/">Inicio</a></li>
<li class="guides-index guides-index-large">
<a href="index.html" id="guidesMenu" class="guides-index-item nav-item">Índice de Guías</a>
<div id="guides" class="clearfix" style="display: none;">
<hr />
<dl class="guides-section-container">
<div class="guides-section">
<dt>Comienza Aquí</dt>
<dd><a href="getting_started.html">Primeros Pasos con Rails</a></dd>
</div>
<div class="guides-section">
<dt>Modelos</dt>
<dd><a href="active_record_basics.html">Conceptos Básicos de Active Record</a></dd>
<dd><a href="active_record_migrations.html">Migraciones de Active Record</a></dd>
<dd><a href="active_record_validations.html">Validaciones de Active Record</a></dd>
</div>
<div class="guides-section">
<dt>Vistas</dt>
<dd><a href="action_view_overview.html">Resumen de Action View</a></dd>
<dd><a href="layouts_and_rendering.html">Diseños y Renderizado en Rails</a></dd>
</div>
<div class="guides-section">
<dt>Controladores</dt>
<dd><a href="action_controller_overview.html">Resumen de Action Controller</a></dd>
<dd><a href="routing.html">Enrutamiento en Rails desde el Exterior</a></dd>
</div>
<div class="guides-section">
<dt>Otros Componentes</dt>
<dd><a href="active_support_core_extensions.html">Extensiones Básicas de Active Support</a></dd>
<dd><a href="action_mailer_basics.html">Conceptos Básicos de Action Mailer</a></dd>
<dd><a href="action_mailbox_basics.html">Conceptos Básicos de Action Mailbox</a></dd>
<dd><a href="action_text_overview.html">Resumen de Action Text</a></dd>
<dd><a href="active_job_basics.html">Conceptos Básicos de Active Job</a></dd>
</div>
<div class="guides-section">
<dt>Políticas</dt>
<dd><a href="maintenance_policy.html">Política de Mantenimiento</a></dd>
</div>
<div class="guides-section">
<dt>Notas de Lanzamiento</dt>
<dd><a href="upgrading_ruby_on_rails.html">Actualizando Ruby on Rails</a></dd>
<dd><a href="7_2_release_notes.html">Versión 7.2 - ?</a></dd>
<dd><a href="7_1_release_notes.html">Versión 7.1 - Octubre 2023</a></dd>
<dd><a href="7_0_release_notes.html">Versión 7.0 - Diciembre 2021</a></dd>
<dd><a href="6_1_release_notes.html">Versión 6.1 - Diciembre 2020</a></dd>
</div>
</dl>
</div>
</li>
<li><a class="nav-item" href="contributing_to_ruby_on_rails.html">Contribuir</a></li>
<li class="guides-index guides-index-small">
<select class="guides-index-item nav-item">
<option value="index.html">Índice de Guías</option>
<optgroup label="Comienza Aquí">
<option value="getting_started.html">Primeros Pasos con Rails</option>
</optgroup>
<optgroup label="Modelos">
<option value="active_record_basics.html">Conceptos Básicos de Active Record</option>
<option value="active_record_migrations.html">Migraciones de Active Record</option>
<option value="active_record_validations.html">Validaciones de Active Record</option>
</optgroup>
<optgroup label="Vistas">
<option value="action_view_overview.html">Resumen de Action View</option>
<option value="layouts_and_rendering.html">Diseños y Renderizado en Rails</option>
</optgroup>
<optgroup label="Controladores">
<option value="action_controller_overview.html">Resumen de Action Controller</option>
<option value="routing.html">Enrutamiento en Rails desde el Exterior</option>
</optgroup>
<optgroup label="Otros Componentes">
<option value="active_support_core_extensions.html">Extensiones Básicas de Active Support</option>
<option value="action_mailer_basics.html">Conceptos Básicos de Action Mailer</option>
<option value="action_mailbox_basics.html">Conceptos Básicos de Action Mailbox</option>
<option value="action_text_overview.html">Resumen de Action Text</option>
<option value="active_job_basics.html">Conceptos Básicos de Active Job</option>
</optgroup>
<optgroup label="Políticas">
<option value="maintenance_policy.html">Política de Mantenimiento</option>
</optgroup>
<optgroup label="Notas de Lanzamiento">
<option value="upgrading_ruby_on_rails.html">Actualizando Ruby on Rails</option>
<option value="7_2_release_notes.html">Versión 7.2 - ?</option>
<option value="7_1_release_notes.html">Versión 7.1 - Octubre 2023</option>
<option value="7_0_release_notes.html">Versión 7.0 - Diciembre 2021</option>
<option value="6_1_release_notes.html">Versión 6.1 - Diciembre 2020</option>
</optgroup>
</select>
</li>
</ul>
</nav>
</div>
</header>
<hr class="hide" />
<section id="feature">
<div class="wrapper">
<h1>API de Internacionalización (I18n) de Rails</h1><p>La gema Ruby I18n (abreviatura de <em>internacionalización</em>) que se incluye con Ruby on Rails (a partir de Rails 2.2) proporciona un marco fácil de usar y extensible para <strong>traducir su aplicación a un único idioma personalizado</strong> distinto del inglés o para <strong>proporcionar soporte multilingüe</strong> en su aplicación.</p><p>El proceso de "internacionalización" generalmente significa abstraer todas las cadenas y otros elementos específicos de la configuración regional (como formatos de fecha o moneda) de su aplicación. El proceso de "localización" significa proporcionar traducciones y formatos localizados para estos elementos.<sup class="footnote" id="footnote-1-ref"><a href="#footnote-1">1</a></sup></p><p>Entonces, en el proceso de <em>internacionalizar</em> su aplicación Rails debe:</p>
<ul>
<li>Asegurarse de tener soporte para I18n.</li>
<li>Indicar a Rails dónde encontrar los diccionarios de configuración regional.</li>
<li>Indicar a Rails cómo establecer, preservar y cambiar configuraciones regionales.</li>
</ul>
<p>En el proceso de <em>localizar</em> su aplicación probablemente querrá hacer las siguientes tres cosas:</p>
<ul>
<li>Reemplazar o complementar la configuración regional predeterminada de Rails, por ejemplo, formatos de fecha y hora, nombres de meses, nombres de modelos de Active Record, etc.</li>
<li>Abstraer cadenas en su aplicación en diccionarios con claves, por ejemplo, mensajes flash, texto estático en sus vistas, etc.</li>
<li>Almacenar los diccionarios resultantes en algún lugar.</li>
</ul>
<p>Esta guía lo guiará a través de la API de I18n y contiene un tutorial sobre cómo internacionalizar una aplicación Rails desde el principio.</p><p>Después de leer esta guía, sabrá:</p>
<ul>
<li>Cómo funciona I18n en Ruby on Rails</li>
<li>Cómo usar correctamente I18n en una aplicación RESTful de varias maneras</li>
<li>Cómo usar I18n para traducir errores de Active Record o asuntos de correos electrónicos de Action Mailer</li>
<li>Algunas otras herramientas para avanzar en el proceso de traducción de su aplicación</li>
</ul>
<nav id="subCol">
<h3 class="chapter">
<picture>
<!-- Using the `source` HTML tag to set the dark theme image -->
<source
srcset="images/icon_book-close-bookmark-1-wht.svg"
media="(prefers-color-scheme: dark)"
/>
<img src="images/icon_book-close-bookmark-1.svg" alt="Chapter Icon" />
</picture>
Chapters
</h3>
<ol class="chapters">
<li><a href="#cómo-funciona-i18n-en-ruby-on-rails">Cómo Funciona I18n en Ruby on Rails</a>
<ul>
<li><a href="#la-arquitectura-general-de-la-biblioteca">La Arquitectura General de la Biblioteca</a></li>
<li><a href="#la-api-pública-de-i18n">La API Pública de I18n</a></li>
</ul></li>
<li><a href="#configurar-la-aplicación-rails-para-la-internacionalización">Configurar la Aplicación Rails para la Internacionalización</a>
<ul>
<li><a href="#configurar-el-módulo-i18n">Configurar el Módulo I18n</a></li>
<li><a href="#gestionar-la-configuración-regional-entre-solicitudes">Gestionar la Configuración Regional entre Solicitudes</a></li>
</ul></li>
<li><a href="#internacionalización-y-localización">Internacionalización y Localización</a>
<ul>
<li><a href="#abstraer-código-localizado">Abstraer Código Localizado</a></li>
<li><a href="#proporcionar-traducciones-para-cadenas-internacionalizadas">Proporcionar Traducciones para Cadenas Internacionalizadas</a></li>
<li><a href="#pasar-variables-a-traducciones">Pasar Variables a Traducciones</a></li>
<li><a href="#agregar-formatos-de-fecha-hora">Agregar Formatos de Fecha/Hora</a></li>
<li><a href="#reglas-de-inflección-para-otras-configuraciones-regionales">Reglas de Inflección para Otras Configuraciones Regionales</a></li>
<li><a href="#vistas-localizadas">Vistas Localizadas</a></li>
<li><a href="#organización-de-archivos-de-configuración-regional">Organización de Archivos de Configuración Regional</a></li>
</ul></li>
<li><a href="#resumen-de-las-funciones-de-la-api-de-i18n">Resumen de las Funciones de la API de I18n</a>
<ul>
<li><a href="#búsqueda-de-traducciones">Búsqueda de Traducciones</a></li>
<li><a href="#pluralización">Pluralización</a></li>
<li><a href="#establecer-y-pasar-una-configuración-regional">Establecer y Pasar una Configuración Regional</a></li>
<li><a href="#usar-traducciones-html-seguras">Usar Traducciones HTML Seguras</a></li>
<li><a href="#traducciones-para-modelos-de-active-record">Traducciones para Modelos de Active Record</a></li>
<li><a href="#traducciones-para-asuntos-de-correos-electrónicos-de-action-mailer">Traducciones para Asuntos de Correos Electrónicos de Action Mailer</a></li>
<li><a href="#resumen-de-otros-métodos-incorporados-que-proporcionan-soporte-i18n">Resumen de Otros Métodos Incorporados que Proporcionan Soporte I18n</a></li>
</ul></li>
<li><a href="#cómo-almacenar-sus-traducciones-personalizadas">Cómo Almacenar sus Traducciones Personalizadas</a></li>
<li><a href="#personalizar-su-configuración-de-i18n">Personalizar su Configuración de I18n</a>
<ul>
<li><a href="#usar-diferentes-backends">Usar Diferentes Backends</a></li>
<li><a href="#usar-diferentes-manejadores-de-excepciones">Usar Diferentes Manejadores de Excepciones</a></li>
</ul></li>
<li><a href="#traducir-contenido-del-modelo">Traducir Contenido del Modelo</a></li>
<li><a href="#conclusión">Conclusión</a></li>
<li><a href="#contribuir-a-rails-i18n">Contribuir a Rails I18n</a></li>
<li><a href="#recursos">Recursos</a></li>
<li><a href="#autores">Autores</a></li>
<li><a href="#notas-al-pie">Notas al pie</a></li>
</ol>
</nav>
<hr>
</div>
</section>
<main id="container">
<div class="wrapper">
<div id="mainCol">
<p>NOTA: El marco Ruby I18n le proporciona todos los medios necesarios para la internacionalización/localización de su aplicación Rails. También puede usar varias gemas disponibles para agregar funcionalidad o características adicionales. Consulte la <a href="https://github.com/svenfuchs/rails-i18n">gema rails-i18n</a> para obtener más información.</p><h2 id="cómo-funciona-i18n-en-ruby-on-rails"><a class="anchorlink" href="#cómo-funciona-i18n-en-ruby-on-rails"><span>1</span> Cómo Funciona I18n en Ruby on Rails</a></h2><p>La internacionalización es un problema complejo. Los idiomas naturales difieren de muchas maneras (por ejemplo, en las reglas de pluralización) que es difícil proporcionar herramientas para resolver todos los problemas a la vez. Por esa razón, la API de I18n de Rails se centra en:</p>
<ul>
<li>proporcionar soporte para inglés y lenguajes similares de manera predeterminada</li>
<li>facilitar la personalización y extensión de todo para otros idiomas</li>
</ul>
<p>Como parte de esta solución, <strong>cada cadena estática en el marco de Rails</strong> - por ejemplo, mensajes de validación de Active Record, formatos de tiempo y fecha - <strong>ha sido internacionalizada</strong>. <em>La localización</em> de una aplicación Rails significa definir valores traducidos para estas cadenas en los idiomas deseados.</p><p>Para localizar, almacenar y actualizar <em>contenido</em> en su aplicación (por ejemplo, traducir publicaciones de blog), consulte la sección <a href="#csonfigurar-el-módulo-i18n">Traducir contenido del modelo</a>.</p><h3 id="la-arquitectura-general-de-la-biblioteca"><a class="anchorlink" href="#la-arquitectura-general-de-la-biblioteca"><span>1.1</span> La Arquitectura General de la Biblioteca</a></h3><p>Por lo tanto, la gema Ruby I18n se divide en dos partes:</p>
<ul>
<li>La API pública del marco I18n - un módulo Ruby con métodos públicos que definen cómo funciona la biblioteca</li>
<li>Un backend predeterminado (que se llama intencionalmente <em>Simple</em> backend) que implementa estos métodos</li>
</ul>
<p>Como usuario, siempre debe acceder solo a los métodos públicos en el módulo I18n, pero es útil conocer las capacidades del backend.</p><p>NOTA: Es posible intercambiar el backend Simple enviado con uno más poderoso, que almacenaría datos de traducción en una base de datos relacional, un diccionario GetText o similar. Consulte la sección <a href="#usar-diferentes-backends">Usando diferentes backends</a> a continuación.</p><h3 id="la-api-pública-de-i18n"><a class="anchorlink" href="#la-api-pública-de-i18n"><span>1.2</span> La API Pública de I18n</a></h3><p>Los métodos más importantes de la API de I18n son:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">translate</span> <span class="c1"># Buscar traducciones de texto</span>
<span class="n">localize</span> <span class="c1"># Localizar objetos de Fecha y Hora a formatos locales</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="translate # Buscar traducciones de texto
localize # Localizar objetos de Fecha y Hora a formatos locales
">Copy</button>
</div>
<p>Estos tienen los alias #t y #l, por lo que puede usarlos así:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'store.title'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">l</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t 'store.title'
I18n.l Time.now
">Copy</button>
</div>
<p>También hay lectores y escritores de atributos para los siguientes atributos:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">load_path</span> <span class="c1"># Anunciar sus archivos de traducción personalizados</span>
<span class="n">locale</span> <span class="c1"># Obtener y establecer la configuración regional actual</span>
<span class="n">default_locale</span> <span class="c1"># Obtener y establecer la configuración regional predeterminada</span>
<span class="n">available_locales</span> <span class="c1"># Configuraciones regionales permitidas disponibles para la aplicación</span>
<span class="n">enforce_available_locales</span> <span class="c1"># Hacer cumplir el permiso de configuración regional (verdadero o falso)</span>
<span class="n">exception_handler</span> <span class="c1"># Usar un exception_handler diferente</span>
<span class="n">backend</span> <span class="c1"># Usar un backend diferente</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="load_path # Anunciar sus archivos de traducción personalizados
locale # Obtener y establecer la configuración regional actual
default_locale # Obtener y establecer la configuración regional predeterminada
available_locales # Configuraciones regionales permitidas disponibles para la aplicación
enforce_available_locales # Hacer cumplir el permiso de configuración regional (verdadero o falso)
exception_handler # Usar un exception_handler diferente
backend # Usar un backend diferente
">Copy</button>
</div>
<p>¡Así que internacionalicemos una aplicación Rails simple desde cero en los próximos capítulos!</p><h2 id="configurar-la-aplicación-rails-para-la-internacionalización"><a class="anchorlink" href="#configurar-la-aplicación-rails-para-la-internacionalización"><span>2</span> Configurar la Aplicación Rails para la Internacionalización</a></h2><p>Hay algunos pasos para comenzar a funcionar con soporte I18n para una aplicación Rails.</p><h3 id="configurar-el-módulo-i18n"><a class="anchorlink" href="#configurar-el-módulo-i18n"><span>2.1</span> Configurar el Módulo I18n</a></h3><p>Siguiendo la filosofía <em>convención sobre configuración</em>, Rails I18n proporciona cadenas de traducción predeterminadas razonables. Cuando se necesitan diferentes cadenas de traducción, se pueden sobrescribir.</p><p>Rails agrega automáticamente todos los archivos <code>.rb</code> y <code>.yml</code> del directorio <code>config/locales</code> a la <strong>ruta de carga de traducciones</strong>.</p><p>La configuración regional predeterminada <code>en.yml</code> en este directorio contiene un par de cadenas de traducción de muestra:</p><div class="interstitial code">
<pre><code class="highlight yaml"><span class="na">en</span><span class="pi">:</span>
<span class="na">hello</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Hello</span><span class="nv"> </span><span class="s">world"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="en:
hello: "Hello world"
">Copy</button>
</div>
<p>Esto significa que en la configuración regional <code>:en</code>, la clave <em>hello</em> se mapeará a la cadena <em>Hello world</em>. Cada cadena dentro de Rails está internacionalizada de esta manera, vea, por ejemplo, los mensajes de validación de Active Model en el archivo <a href="https://github.com/rails/rails/blob/main/activemodel/lib/active_model/locale/en.yml"><code>activemodel/lib/active_model/locale/en.yml</code></a> o los formatos de tiempo y fecha en el archivo <a href="https://github.com/rails/rails/blob/main/activesupport/lib/active_support/locale/en.yml"><code>activesupport/lib/active_support/locale/en.yml</code></a>. Puede usar YAML o Hashes estándar de Ruby para almacenar traducciones en el backend predeterminado (Simple).</p><p>La biblioteca I18n usará <strong>inglés</strong> como <strong>configuración regional predeterminada</strong>, es decir, si no se establece una configuración regional diferente, se usará <code>:en</code> para buscar traducciones.</p><p>NOTA: La biblioteca i18n adopta un enfoque <strong>pragmático</strong> para las claves de configuración regional (después de <a href="https://groups.google.com/g/rails-i18n/c/FN7eLH2-lHA">alguna discusión</a>), incluyendo solo la parte <em>locale</em> ("idioma"), como <code>:en</code>, <code>:pl</code>, no la parte <em>región</em>, como <code>:"en-US"</code> o <code>:"en-GB"</code>, que tradicionalmente se utilizan para separar "idiomas" y "configuración regional" o "dialectos". Muchas aplicaciones internacionales usan solo el elemento "idioma" de una configuración regional como <code>:cs</code>, <code>:th</code>, o <code>:es</code> (para checo, tailandés y español). Sin embargo, también hay diferencias regionales dentro de diferentes grupos de idiomas que pueden ser importantes. Por ejemplo, en la configuración regional <code>:"en-US"</code> tendría $ como símbolo de moneda, mientras que en <code>:"en-GB"</code>, tendría £. Nada le impide separar configuraciones regionales y otras configuraciones de esta manera: solo tiene que proporcionar la configuración regional completa de "Inglés - Reino Unido" en un diccionario <code>:"en-GB"</code>.</p><p>La <strong>ruta de carga de traducciones</strong> (<code>I18n.load_path</code>) es una matriz de rutas a archivos que se cargarán automáticamente. Configurar esta ruta permite la personalización de la estructura del directorio de traducciones y el esquema de nombres de archivos.</p><p>NOTA: El backend carga perezosamente estas traducciones cuando se busca una traducción por primera vez. Este backend se puede intercambiar por otro incluso después de que las traducciones ya se hayan anunciado.</p><p>Puede cambiar la configuración regional predeterminada, así como configurar las rutas de carga de traducciones en <code>config/application.rb</code> de la siguiente manera:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">config</span><span class="p">.</span><span class="nf">i18n</span><span class="p">.</span><span class="nf">load_path</span> <span class="o">+=</span> <span class="no">Dir</span><span class="p">[</span><span class="no">Rails</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">'my'</span><span class="p">,</span> <span class="s1">'locales'</span><span class="p">,</span> <span class="s1">'*.{rb,yml}'</span><span class="p">)]</span>
<span class="n">config</span><span class="p">.</span><span class="nf">i18n</span><span class="p">.</span><span class="nf">default_locale</span> <span class="o">=</span> <span class="ss">:de</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}')]
config.i18n.default_locale = :de
">Copy</button>
</div>
<p>La ruta de carga debe especificarse antes de que se busquen las traducciones. Para cambiar la configuración regional predeterminada desde un inicializador en lugar de <code>config/application.rb</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># config/initializers/locale.rb</span>
<span class="c1"># Dónde debería buscar la biblioteca I18n archivos de traducción</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">load_path</span> <span class="o">+=</span> <span class="no">Dir</span><span class="p">[</span><span class="no">Rails</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">'lib'</span><span class="p">,</span> <span class="s1">'locale'</span><span class="p">,</span> <span class="s1">'*.{rb,yml}'</span><span class="p">)]</span>
<span class="c1"># Configuraciones regionales permitidas disponibles para la aplicación</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">available_locales</span> <span class="o">=</span> <span class="p">[</span><span class="ss">:en</span><span class="p">,</span> <span class="ss">:pt</span><span class="p">]</span>
<span class="c1"># Establecer la configuración regional predeterminada en algo diferente a :en</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">default_locale</span> <span class="o">=</span> <span class="ss">:pt</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="
# Dónde debería buscar la biblioteca I18n archivos de traducción
I18n.load_path += Dir[Rails.root.join('lib', 'locale', '*.{rb,yml}')]
# Configuraciones regionales permitidas disponibles para la aplicación
I18n.available_locales = [:en, :pt]
# Establecer la configuración regional predeterminada en algo diferente a :en
I18n.default_locale = :pt
">Copy</button>
</div>
<p>Tenga en cuenta que al agregar directamente a <code>I18n.load_path</code> en lugar de a la configuración de I18n de la aplicación, <em>no</em> se sobrescribirán las traducciones de gemas externas.</p><h3 id="gestionar-la-configuración-regional-entre-solicitudes"><a class="anchorlink" href="#gestionar-la-configuración-regional-entre-solicitudes"><span>2.2</span> Gestionar la Configuración Regional entre Solicitudes</a></h3><p>Una aplicación localizada probablemente necesitará proporcionar soporte para múltiples configuraciones regionales. Para lograr esto, la configuración regional debe establecerse al comienzo de cada solicitud para que todas las cadenas se traduzcan utilizando la configuración regional deseada durante la duración de esa solicitud.</p><p>La configuración regional predeterminada se utiliza para todas las traducciones a menos que se use <code>I18n.locale=</code> o <code>I18n.with_locale</code>.</p><p><code>I18n.locale</code> puede filtrarse en solicitudes posteriores atendidas por el mismo hilo/proceso si no se establece de manera consistente en cada controlador. Por ejemplo, ejecutar <code>I18n.locale = :es</code> en una solicitud POST tendrá efectos para todas las solicitudes posteriores a controladores que no establezcan la configuración regional, pero solo en ese hilo/proceso en particular. Por esa razón, en lugar de <code>I18n.locale =</code> puede usar <code>I18n.with_locale</code> que no tiene este problema de fuga.</p><p>La configuración regional se puede establecer en una <code>around_action</code> en el <code>ApplicationController</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">around_action</span> <span class="ss">:switch_locale</span>
<span class="k">def</span> <span class="nf">switch_locale</span><span class="p">(</span><span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="n">locale</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="ss">:locale</span><span class="p">]</span> <span class="o">||</span> <span class="no">I18n</span><span class="p">.</span><span class="nf">default_locale</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">with_locale</span><span class="p">(</span><span class="n">locale</span><span class="p">,</span> <span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="around_action :switch_locale
def switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
end
">Copy</button>
</div>
<p>Este ejemplo ilustra el uso de un parámetro de consulta de URL para establecer la configuración regional (por ejemplo, <code>http://example.com/books?locale=pt</code>). Con este enfoque, <code>http://localhost:3000?locale=pt</code> renderiza la localización en portugués, mientras que <code>http://localhost:3000?locale=de</code> carga una localización en alemán.</p><p>La configuración regional se puede establecer utilizando uno de varios enfoques diferentes.</p><h4 id="establecer-la-configuración-regional-desde-el-nombre-de-dominio"><a class="anchorlink" href="#establecer-la-configuración-regional-desde-el-nombre-de-dominio"><span>2.2.1</span> Establecer la Configuración Regional desde el Nombre de Dominio</a></h4><p>Una opción que tiene es establecer la configuración regional desde el nombre de dominio donde se ejecuta su aplicación. Por ejemplo, queremos que <code>www.example.com</code> cargue la configuración regional en inglés (o predeterminada) y <code>www.example.es</code> cargue la configuración regional en español. Así, el <em>nombre de dominio de nivel superior</em> se utiliza para establecer la configuración regional. Esto tiene varias ventajas:</p>
<ul>
<li>La configuración regional es una parte <em>obvia</em> de la URL.</li>
<li>Las personas comprenden intuitivamente en qué idioma se mostrará el contenido.</li>
<li>Es muy trivial de implementar en Rails.</li>
<li>Los motores de búsqueda parecen gustar de que el contenido en diferentes idiomas viva en diferentes dominios interconectados.</li>
</ul>
<p>Puede implementarlo así en su <code>ApplicationController</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">around_action</span> <span class="ss">:switch_locale</span>
<span class="k">def</span> <span class="nf">switch_locale</span><span class="p">(</span><span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="n">locale</span> <span class="o">=</span> <span class="n">extract_locale_from_tld</span> <span class="o">||</span> <span class="no">I18n</span><span class="p">.</span><span class="nf">default_locale</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">with_locale</span><span class="p">(</span><span class="n">locale</span><span class="p">,</span> <span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="k">end</span>
<span class="c1"># Obtener la configuración regional del dominio de nivel superior o devolver +nil+ si dicha configuración regional no está disponible</span>
<span class="c1"># Debe poner algo como:</span>
<span class="c1"># 127.0.0.1 application.com</span>
<span class="c1"># 127.0.0.1 application.it</span>
<span class="c1"># 127.0.0.1 application.pl</span>
<span class="c1"># en su archivo /etc/hosts para probar esto localmente</span>
<span class="k">def</span> <span class="nf">extract_locale_from_tld</span>
<span class="n">parsed_locale</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">host</span><span class="p">.</span><span class="nf">split</span><span class="p">(</span><span class="s1">'.'</span><span class="p">).</span><span class="nf">last</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">available_locales</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:to_s</span><span class="p">).</span><span class="nf">include?</span><span class="p">(</span><span class="n">parsed_locale</span><span class="p">)</span> <span class="p">?</span> <span class="n">parsed_locale</span> <span class="p">:</span> <span class="kp">nil</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="around_action :switch_locale
def switch_locale(&action)
locale = extract_locale_from_tld || I18n.default_locale
I18n.with_locale(locale, &action)
end
# Obtener la configuración regional del dominio de nivel superior o devolver +nil+ si dicha configuración regional no está disponible
# Debe poner algo como:
# 127.0.0.1 application.com
# 127.0.0.1 application.it
# 127.0.0.1 application.pl
# en su archivo /etc/hosts para probar esto localmente
def extract_locale_from_tld
parsed_locale = request.host.split('.').last
I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end
">Copy</button>
</div>
<p>También podemos establecer la configuración regional desde el <em>subdominio</em> de una manera muy similar:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># Obtener el código de configuración regional del subdominio de la solicitud (como http://it.application.local:3000)</span>
<span class="c1"># Debe poner algo como:</span>
<span class="c1"># 127.0.0.1 gr.application.local</span>
<span class="c1"># en su archivo /etc/hosts para probar esto localmente</span>
<span class="k">def</span> <span class="nf">extract_locale_from_subdomain</span>
<span class="n">parsed_locale</span> <span class="o">=</span> <span class="n">request</span><span class="p">.</span><span class="nf">subdomains</span><span class="p">.</span><span class="nf">first</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">available_locales</span><span class="p">.</span><span class="nf">map</span><span class="p">(</span><span class="o">&</span><span class="ss">:to_s</span><span class="p">).</span><span class="nf">include?</span><span class="p">(</span><span class="n">parsed_locale</span><span class="p">)</span> <span class="p">?</span> <span class="n">parsed_locale</span> <span class="p">:</span> <span class="kp">nil</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="# Obtener el código de configuración regional del subdominio de la solicitud (como http://it.application.local:3000)
# Debe poner algo como:
# 127.0.0.1 gr.application.local
# en su archivo /etc/hosts para probar esto localmente
def extract_locale_from_subdomain
parsed_locale = request.subdomains.first
I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
end
">Copy</button>
</div>
<p>Si su aplicación incluye un menú de cambio de configuración regional, tendría algo como esto en él:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">link_to</span><span class="p">(</span><span class="s2">"Deutsch"</span><span class="p">,</span> <span class="s2">"</span><span class="si">#{</span><span class="no">APP_CONFIG</span><span class="p">[</span><span class="ss">:deutsch_website_url</span><span class="p">]</span><span class="si">}#{</span><span class="n">request</span><span class="p">.</span><span class="nf">env</span><span class="p">[</span><span class="s1">'PATH_INFO'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span><span class="p">)</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="link_to("Deutsch", "#{APP_CONFIG[:deutsch_website_url]}#{request.env['PATH_INFO']}")
">Copy</button>
</div>
<p>asumiendo que establecería <code>APP_CONFIG[:deutsch_website_url]</code> en algún valor como <code>http://www.application.de</code>.</p><p>Esta solución tiene las ventajas mencionadas anteriormente, sin embargo, puede que no pueda o no quiera proporcionar diferentes localizaciones ("versiones de idioma") en diferentes dominios. La solución más obvia sería incluir el código de configuración regional en los parámetros de la URL (o en la ruta de solicitud).</p><h4 id="establecer-la-configuración-regional-desde-los-parámetros-de-la-url"><a class="anchorlink" href="#establecer-la-configuración-regional-desde-los-parámetros-de-la-url"><span>2.2.2</span> Establecer la Configuración Regional desde los Parámetros de la URL</a></h4><p>La forma más habitual de establecer (y pasar) la configuración regional sería incluirla en los parámetros de la URL, como hicimos en el <em>around_action</em> <code>I18n.with_locale(params[:locale], &action)</code> en el primer ejemplo. Nos gustaría tener URLs como <code>www.example.com/books?locale=ja</code> o <code>www.example.com/ja/books</code> en este caso.</p><p>Este enfoque tiene casi el mismo conjunto de ventajas que establecer la configuración regional desde el nombre de dominio: a saber, que es RESTful y está de acuerdo con el resto de la World Wide Web. Sin embargo, requiere un poco más de trabajo para implementar.</p><p>Obtener la configuración regional de <code>params</code> y establecerla en consecuencia no es difícil; incluirla en cada URL y, por lo tanto, <strong>pasarla a través de las solicitudes</strong> sí lo es. Incluir una opción explícita en cada URL, por ejemplo, <code>link_to(books_url(locale: I18n.locale))</code>, sería tedioso y probablemente imposible, por supuesto.</p><p>Rails contiene infraestructura para "centralizar decisiones dinámicas sobre las URLs" en su <a href="https://edgeapi.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-default_url_options"><code>ApplicationController#default_url_options</code></a>, que es útil precisamente en este escenario: nos permite establecer "predeterminados" para <a href="https://edgeapi.rubyonrails.org/classes/ActionDispatch/Routing/UrlFor.html#method-i-url_for"><code>url_for</code></a> y métodos auxiliares dependientes de él (implementando/sobrescribiendo <code>default_url_options</code>).</p><p>Podemos incluir algo como esto en nuestro <code>ApplicationController</code> entonces:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># app/controllers/application_controller.rb</span>
<span class="k">def</span> <span class="nf">default_url_options</span>
<span class="p">{</span> <span class="ss">locale: </span><span class="no">I18n</span><span class="p">.</span><span class="nf">locale</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="def default_url_options
{ locale: I18n.locale }
end
">Copy</button>
</div>
<p>Cada método auxiliar dependiente de <code>url_for</code> (por ejemplo, auxiliares para rutas nombradas como <code>root_path</code> o <code>root_url</code>, rutas de recursos como <code>books_path</code> o <code>books_url</code>, etc.) ahora <strong>incluirá automáticamente la configuración regional en la cadena de consulta</strong>, así: <code>http://localhost:3001/?locale=ja</code>.</p><p>Puede estar satisfecho con esto. Sin embargo, afecta la legibilidad de las URLs, cuando la configuración regional "cuelga" al final de cada URL en su aplicación. Además, desde el punto de vista arquitectónico, la configuración regional generalmente está jerárquicamente por encima de las otras partes del dominio de la aplicación: y las URLs deberían reflejar esto.</p><p>Probablemente desee que las URLs se vean así: <code>http://www.example.com/en/books</code> (que carga la configuración regional en inglés) y <code>http://www.example.com/nl/books</code> (que carga la configuración regional en neerlandés). Esto se puede lograr con la estrategia de "sobrescribir <code>default_url_options</code>" desde arriba: solo tiene que configurar sus rutas con <a href="https://edgeapi.rubyonrails.org/classes/ActionDispatch/Routing/Mapper/Scoping.html"><code>scope</code></a>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># config/routes.rb</span>
<span class="n">scope</span> <span class="s2">"/:locale"</span> <span class="k">do</span>
<span class="n">resources</span> <span class="ss">:books</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="scope "/:locale" do
resources :books
end
">Copy</button>
</div>
<p>Ahora, cuando llame al método <code>books_path</code> debería obtener <code>"/en/books"</code> (para la configuración regional predeterminada). Una URL como <code>http://localhost:3001/nl/books</code> debería cargar la configuración regional en neerlandés, entonces, y las llamadas posteriores a <code>books_path</code> deberían devolver <code>"/nl/books"</code> (porque la configuración regional cambió).</p><p>ADVERTENCIA. Dado que el valor de retorno de <code>default_url_options</code> se almacena en caché por solicitud, las URLs en un selector de configuración regional no se pueden generar invocando auxiliares en un bucle que establece el <code>I18n.locale</code> correspondiente en cada iteración. En su lugar, deje <code>I18n.locale</code> sin tocar y pase una opción <code>:locale</code> explícita al auxiliar, o edite <code>request.original_fullpath</code>.</p><p>Si no desea forzar el uso de una configuración regional en sus rutas, puede usar un alcance de ruta opcional (denotado por los paréntesis) así:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># config/routes.rb</span>
<span class="n">scope</span> <span class="s2">"(:locale)"</span><span class="p">,</span> <span class="ss">locale: </span><span class="sr">/en|nl/</span> <span class="k">do</span>
<span class="n">resources</span> <span class="ss">:books</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="scope "(:locale)", locale: /en|nl/ do
resources :books
end
">Copy</button>
</div>
<p>Con este enfoque, no obtendrá un <code>Routing Error</code> al acceder a sus recursos como <code>http://localhost:3001/books</code> sin una configuración regional. Esto es útil cuando desea usar la configuración regional predeterminada cuando no se especifica una.</p><p>Por supuesto, debe tener especial cuidado con la URL raíz (generalmente "página de inicio" o "tablero") de su aplicación. Una URL como <code>http://localhost:3001/nl</code> no funcionará automáticamente, porque la declaración <code>root to: "dashboard#index"</code> en su <code>routes.rb</code> no toma en cuenta la configuración regional. (Y con razón: solo hay una URL "raíz").</p><p>Probablemente necesitaría mapear URLs como estas:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># config/routes.rb</span>
<span class="n">get</span> <span class="s1">'/:locale'</span> <span class="o">=></span> <span class="s1">'dashboard#index'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="get '/:locale' => 'dashboard#index'
">Copy</button>
</div>
<p>Tome especial cuidado con el <strong>orden de sus rutas</strong>, para que esta declaración de ruta no "coma" otras. (Es posible que desee agregarla directamente antes de la declaración <code>root :to</code>).</p><p>NOTA: Eche un vistazo a varias gemas que simplifican el trabajo con rutas: <a href="https://github.com/svenfuchs/routing-filter/tree/master">routing_filter</a>, <a href="https://github.com/enriclluelles/route_translator">route_translator</a>.</p><h4 id="establecer-la-configuración-regional-desde-las-preferencias-del-usuario"><a class="anchorlink" href="#establecer-la-configuración-regional-desde-las-preferencias-del-usuario"><span>2.2.3</span> Establecer la Configuración Regional desde las Preferencias del Usuario</a></h4><p>Una aplicación con usuarios autenticados puede permitir que los usuarios establezcan una preferencia de configuración regional a través de la interfaz de la aplicación. Con este enfoque, la preferencia de configuración regional seleccionada por un usuario se guarda en la base de datos y se utiliza para establecer la configuración regional para solicitudes autenticadas por ese usuario.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">around_action</span> <span class="ss">:switch_locale</span>
<span class="k">def</span> <span class="nf">switch_locale</span><span class="p">(</span><span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="n">locale</span> <span class="o">=</span> <span class="n">current_user</span><span class="p">.</span><span class="nf">try</span><span class="p">(</span><span class="ss">:locale</span><span class="p">)</span> <span class="o">||</span> <span class="no">I18n</span><span class="p">.</span><span class="nf">default_locale</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">with_locale</span><span class="p">(</span><span class="n">locale</span><span class="p">,</span> <span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="around_action :switch_locale
def switch_locale(&action)
locale = current_user.try(:locale) || I18n.default_locale
I18n.with_locale(locale, &action)
end
">Copy</button>
</div>
<h4 id="elegir-una-configuración-regional-implícita"><a class="anchorlink" href="#elegir-una-configuración-regional-implícita"><span>2.2.4</span> Elegir una Configuración Regional Implícita</a></h4><p>Cuando no se ha establecido una configuración regional explícita para una solicitud (por ejemplo, a través de uno de los métodos anteriores), una aplicación debería intentar inferir la configuración regional deseada.</p><h5 id="inferir-la-configuración-regional-desde-el-encabezado-de-idioma"><a class="anchorlink" href="#inferir-la-configuración-regional-desde-el-encabezado-de-idioma"><span>2.2.4.1</span> Inferir la Configuración Regional desde el Encabezado de Idioma</a></h5><p>El encabezado HTTP <code>Accept-Language</code> indica el idioma preferido para la respuesta de la solicitud. Los navegadores <a href="https://www.w3.org/International/questions/qa-lang-priorities">establecen este valor de encabezado según la configuración de preferencia de idioma del usuario</a>, lo que lo convierte en una buena primera opción al inferir una configuración regional.</p><p>Una implementación trivial del uso de un encabezado <code>Accept-Language</code> sería:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">def</span> <span class="nf">switch_locale</span><span class="p">(</span><span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">debug</span> <span class="s2">"* Accept-Language: </span><span class="si">#{</span><span class="n">request</span><span class="p">.</span><span class="nf">env</span><span class="p">[</span><span class="s1">'HTTP_ACCEPT_LANGUAGE'</span><span class="p">]</span><span class="si">}</span><span class="s2">"</span>
<span class="n">locale</span> <span class="o">=</span> <span class="n">extract_locale_from_accept_language_header</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">debug</span> <span class="s2">"* Locale set to '</span><span class="si">#{</span><span class="n">locale</span><span class="si">}</span><span class="s2">'"</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">with_locale</span><span class="p">(</span><span class="n">locale</span><span class="p">,</span> <span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">extract_locale_from_accept_language_header</span>
<span class="n">request</span><span class="p">.</span><span class="nf">env</span><span class="p">[</span><span class="s1">'HTTP_ACCEPT_LANGUAGE'</span><span class="p">].</span><span class="nf">scan</span><span class="p">(</span><span class="sr">/^[a-z]{2}/</span><span class="p">).</span><span class="nf">first</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="def switch_locale(&action)
logger.debug "* Accept-Language: #{request.env['HTTP_ACCEPT_LANGUAGE']}"
locale = extract_locale_from_accept_language_header
logger.debug "* Locale set to '#{locale}'"
I18n.with_locale(locale, &action)
end
private
def extract_locale_from_accept_language_header
request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first
end
">Copy</button>
</div>
<p>En la práctica, se necesita un código más robusto para hacer esto de manera confiable. La biblioteca <a href="https://github.com/iain/http_accept_language/tree/master">http_accept_language</a> de Iain Hecker o el middleware Rack <a href="https://github.com/rack/rack-contrib/blob/main/lib/rack/contrib/locale.rb">locale</a> de Ryan Tomayko proporcionan soluciones a este problema.</p><h5 id="inferir-la-configuración-regional-desde-la-geolocalización-por-ip"><a class="anchorlink" href="#inferir-la-configuración-regional-desde-la-geolocalización-por-ip"><span>2.2.4.2</span> Inferir la Configuración Regional desde la Geolocalización por IP</a></h5><p>La dirección IP del cliente que realiza la solicitud se puede utilizar para inferir la región del cliente y, por lo tanto, su configuración regional. Servicios como <a href="https://dev.maxmind.com/geoip/geolite2-free-geolocation-data">GeoLite2 Country</a> o gemas como <a href="https://github.com/alexreisner/geocoder">geocoder</a> se pueden usar para implementar este enfoque.</p><p>En general, este enfoque es mucho menos confiable que usar el encabezado de idioma y no se recomienda para la mayoría de las aplicaciones web.</p><h4 id="almacenar-la-configuración-regional-en-la-sesión-o-cookies"><a class="anchorlink" href="#almacenar-la-configuración-regional-en-la-sesión-o-cookies"><span>2.2.5</span> Almacenar la Configuración Regional en la Sesión o Cookies</a></h4><p>ADVERTENCIA: Puede sentirse tentado a almacenar la configuración regional elegida en una <em>sesión</em> o una <em>cookie</em>. Sin embargo, <strong>no lo haga</strong>. La configuración regional debe ser transparente y formar parte de la URL. De esta manera, no romperá las suposiciones básicas de las personas sobre la web misma: si envía una URL a un amigo, deberían ver la misma página y contenido que usted. Una palabra elegante para esto sería que está siendo <a href="https://en.wikipedia.org/wiki/Representational_State_Transfer"><em>RESTful</em></a>. Lea más sobre el enfoque RESTful en <a href="https://www.infoq.com/articles/rest-introduction">los artículos de Stefan Tilkov</a>. A veces hay excepciones a esta regla y se discuten a continuación.</p><h2 id="internacionalización-y-localización"><a class="anchorlink" href="#internacionalización-y-localización"><span>3</span> Internacionalización y Localización</a></h2><p>¡OK! Ahora ha inicializado el soporte I18n para su aplicación Ruby on Rails y le ha indicado qué configuración regional usar y cómo preservarla entre solicitudes.</p><p>A continuación, necesitamos <em>internacionalizar</em> nuestra aplicación abstrayendo cada elemento específico de la configuración regional. Finalmente, necesitamos <em>localizarla</em> proporcionando las traducciones necesarias para estos abstractos.</p><p>Dado el siguiente ejemplo:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># config/routes.rb</span>
<span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span>
<span class="n">root</span> <span class="ss">to: </span><span class="s2">"home#index"</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="Rails.application.routes.draw do
root to: "home#index"
end
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># app/controllers/application_controller.rb</span>
<span class="k">class</span> <span class="nc">ApplicationController</span> <span class="o"><</span> <span class="no">ActionController</span><span class="o">::</span><span class="no">Base</span>
<span class="n">around_action</span> <span class="ss">:switch_locale</span>
<span class="k">def</span> <span class="nf">switch_locale</span><span class="p">(</span><span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="n">locale</span> <span class="o">=</span> <span class="n">params</span><span class="p">[</span><span class="ss">:locale</span><span class="p">]</span> <span class="o">||</span> <span class="no">I18n</span><span class="p">.</span><span class="nf">default_locale</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">with_locale</span><span class="p">(</span><span class="n">locale</span><span class="p">,</span> <span class="o">&</span><span class="n">action</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class ApplicationController < ActionController::Base
around_action :switch_locale
def switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
end
end
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># app/controllers/home_controller.rb</span>
<span class="k">class</span> <span class="nc">HomeController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">index</span>
<span class="n">flash</span><span class="p">[</span><span class="ss">:notice</span><span class="p">]</span> <span class="o">=</span> <span class="s2">"Hello Flash"</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class HomeController < ApplicationController
def index
flash[:notice] = "Hello Flash"
end
end
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight erb"><span class="c"><!-- app/views/home/index.html.erb --></span>
<span class="nt"><h1></span>Hello World<span class="nt"></h1></span>
<span class="nt"><p></span><span class="cp"><%=</span> <span class="n">flash</span><span class="p">[</span><span class="ss">:notice</span><span class="p">]</span> <span class="cp">%></span><span class="nt"></p></span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="<!-- app/views/home/index.html.erb -->
<h1>Hello World</h1>
<p><%= flash[:notice] %></p>
">Copy</button>
</div>
<p><img src="images/i18n/demo_untranslated.png" alt="rails i18n demo untranslated"></p><h3 id="abstraer-código-localizado"><a class="anchorlink" href="#abstraer-código-localizado"><span>3.1</span> Abstraer Código Localizado</a></h3><p>En nuestro código, hay dos cadenas escritas en inglés que se mostrarán en nuestra respuesta ("Hello Flash" y "Hello World"). Para internacionalizar este código, estas cadenas deben reemplazarse por llamadas al auxiliar <code>#t</code> de Rails con una clave adecuada para cada cadena:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># app/controllers/home_controller.rb</span>
<span class="k">class</span> <span class="nc">HomeController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">index</span>
<span class="n">flash</span><span class="p">[</span><span class="ss">:notice</span><span class="p">]</span> <span class="o">=</span> <span class="n">t</span><span class="p">(</span><span class="ss">:hello_flash</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class HomeController < ApplicationController
def index
flash[:notice] = t(:hello_flash)
end
end
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight erb"><span class="c"><!-- app/views/home/index.html.erb --></span>
<span class="nt"><h1></span><span class="cp"><%=</span> <span class="n">t</span> <span class="ss">:hello_world</span> <span class="cp">%></span><span class="nt"></h1></span>
<span class="nt"><p></span><span class="cp"><%=</span> <span class="n">flash</span><span class="p">[</span><span class="ss">:notice</span><span class="p">]</span> <span class="cp">%></span><span class="nt"></p></span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="<!-- app/views/home/index.html.erb -->
<h1><%= t :hello_world %></h1>
<p><%= flash[:notice] %></p>
">Copy</button>
</div>
<p>Ahora, cuando se renderice esta vista, mostrará un mensaje de error que le indicará que faltan las traducciones para las claves <code>:hello_world</code> y <code>:hello_flash</code>.</p><p><img src="images/i18n/demo_translation_missing.png" alt="rails i18n demo translation missing"></p><p>NOTA: Rails agrega un método auxiliar <code>t</code> (<code>translate</code>) a sus vistas para que no necesite escribir <code>I18n.t</code> todo el tiempo. Además, este auxiliar capturará traducciones faltantes y envolverá el mensaje de error resultante en un <code><span class="translation_missing"></code>.</p><h3 id="proporcionar-traducciones-para-cadenas-internacionalizadas"><a class="anchorlink" href="#proporcionar-traducciones-para-cadenas-internacionalizadas"><span>3.2</span> Proporcionar Traducciones para Cadenas Internacionalizadas</a></h3><p>Agregue las traducciones faltantes en los archivos de diccionario de traducción:</p><div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/en.yml</span>
<span class="na">en</span><span class="pi">:</span>
<span class="na">hello_world</span><span class="pi">:</span> <span class="s">Hello world!</span>
<span class="na">hello_flash</span><span class="pi">:</span> <span class="s">Hello flash!</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="en:
hello_world: Hello world!
hello_flash: Hello flash!
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/pirate.yml</span>
<span class="na">pirate</span><span class="pi">:</span>
<span class="na">hello_world</span><span class="pi">:</span> <span class="s">Ahoy World</span>
<span class="na">hello_flash</span><span class="pi">:</span> <span class="s">Ahoy Flash</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="pirate:
hello_world: Ahoy World
hello_flash: Ahoy Flash
">Copy</button>
</div>
<p>Debido a que la <code>default_locale</code> no ha cambiado, las traducciones usan la configuración regional <code>:en</code> y la respuesta renderiza las cadenas en inglés:</p><p><img src="images/i18n/demo_translated_en.png" alt="rails i18n demo translated to English"></p><p>Si la configuración regional se establece a través de la URL en la configuración regional pirata (<code>http://localhost:3000?locale=pirate</code>), la respuesta renderiza las cadenas piratas:</p><p><img src="images/i18n/demo_translated_pirate.png" alt="rails i18n demo translated to pirate"></p><p>NOTA: Debe reiniciar el servidor cuando agregue nuevos archivos de configuración regional.</p><p>Puede usar archivos YAML (<code>.yml</code>) o Ruby simples (<code>.rb</code>) para almacenar sus traducciones en SimpleStore. YAML es la opción preferida entre los desarrolladores de Rails. Sin embargo, tiene una gran desventaja. YAML es muy sensible al espacio en blanco y caracteres especiales, por lo que la aplicación puede no cargar su diccionario correctamente. Los archivos Ruby harán que su aplicación se bloquee en la primera solicitud, por lo que puede encontrar fácilmente qué está mal. (Si encuentra algún "problema extraño" con los diccionarios YAML, intente poner la parte relevante de su diccionario en un archivo Ruby).</p><p>Si sus traducciones están almacenadas en archivos YAML, ciertas claves deben escaparse. Son:</p>
<ul>
<li>true, on, yes</li>
<li>false, off, no</li>
</ul>
<p>Ejemplos:</p><div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/en.yml</span>
<span class="na">en</span><span class="pi">:</span>
<span class="na">success</span><span class="pi">:</span>
<span class="s1">'</span><span class="s">true'</span><span class="err">:</span> <span class="s1">'</span><span class="s">True!'</span>
<span class="s1">'</span><span class="s">on'</span><span class="err">:</span> <span class="s1">'</span><span class="s">On!'</span>
<span class="s1">'</span><span class="s">false'</span><span class="err">:</span> <span class="s1">'</span><span class="s">False!'</span>
<span class="na">failure</span><span class="pi">:</span>
<span class="na">true</span><span class="pi">:</span> <span class="s1">'</span><span class="s">True!'</span>
<span class="na">off</span><span class="pi">:</span> <span class="s1">'</span><span class="s">Off!'</span>
<span class="na">false</span><span class="pi">:</span> <span class="s1">'</span><span class="s">False!'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="en:
success:
'true': 'True!'
'on': 'On!'
'false': 'False!'
failure:
true: 'True!'
off: 'Off!'
false: 'False!'
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'success.true'</span> <span class="c1"># => 'True!'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'success.on'</span> <span class="c1"># => 'On!'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'success.false'</span> <span class="c1"># => 'False!'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'failure.false'</span> <span class="c1"># => Translation Missing</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'failure.off'</span> <span class="c1"># => Translation Missing</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'failure.true'</span> <span class="c1"># => Translation Missing</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t 'success.true' # => 'True!'
I18n.t 'success.on' # => 'On!'
I18n.t 'success.false' # => 'False!'
I18n.t 'failure.false' # => Translation Missing
I18n.t 'failure.off' # => Translation Missing
I18n.t 'failure.true' # => Translation Missing
">Copy</button>
</div>
<h3 id="pasar-variables-a-traducciones"><a class="anchorlink" href="#pasar-variables-a-traducciones"><span>3.3</span> Pasar Variables a Traducciones</a></h3><p>Una consideración clave para internacionalizar con éxito una aplicación es evitar hacer suposiciones incorrectas sobre las reglas gramaticales al abstraer código localizado. Las reglas gramaticales que parecen fundamentales en una configuración regional pueden no ser válidas en otra.</p><p>La abstracción incorrecta se muestra en el siguiente ejemplo, donde se hacen suposiciones sobre el orden de las diferentes partes de la traducción. Tenga en cuenta que Rails proporciona un auxiliar <code>number_to_currency</code> para manejar el siguiente caso.</p><div class="interstitial code">
<pre><code class="highlight erb"><span class="c"><!-- app/views/products/show.html.erb --></span>
<span class="cp"><%=</span> <span class="s2">"</span><span class="si">#{</span><span class="n">t</span><span class="p">(</span><span class="s1">'currency'</span><span class="p">)</span><span class="si">}#{</span><span class="vi">@product</span><span class="p">.</span><span class="nf">price</span><span class="si">}</span><span class="s2">"</span> <span class="cp">%></span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="<!-- app/views/products/show.html.erb -->
<%= "#{t('currency')}#{@product.price}" %>
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/en.yml</span>
<span class="na">en</span><span class="pi">:</span>
<span class="na">currency</span><span class="pi">:</span> <span class="s2">"</span><span class="s">$"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="en:
currency: "$"
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/es.yml</span>
<span class="na">es</span><span class="pi">:</span>
<span class="na">currency</span><span class="pi">:</span> <span class="s2">"</span><span class="s">€"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="es:
currency: "€"
">Copy</button>
</div>
<p>Si el precio del producto es 10, la traducción adecuada para el español es "10 €" en lugar de "€10", pero la abstracción no puede darlo.</p><p>Para crear una abstracción adecuada, la gema I18n viene con una característica llamada interpolación de variables que le permite usar variables en definiciones de traducción y pasar los valores de estas variables al método de traducción.</p><p>La abstracción adecuada se muestra en el siguiente ejemplo:</p><div class="interstitial code">
<pre><code class="highlight erb"><span class="c"><!-- app/views/products/show.html.erb --></span>
<span class="cp"><%=</span> <span class="n">t</span><span class="p">(</span><span class="s1">'product_price'</span><span class="p">,</span> <span class="ss">price: </span><span class="vi">@product</span><span class="p">.</span><span class="nf">price</span><span class="p">)</span> <span class="cp">%></span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="<!-- app/views/products/show.html.erb -->
<%= t('product_price', price: @product.price) %>
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/en.yml</span>
<span class="na">en</span><span class="pi">:</span>
<span class="na">product_price</span><span class="pi">:</span> <span class="s2">"</span><span class="s">$%{price}"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="en:
product_price: "$%{price}"
">Copy</button>
</div>
<div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/es.yml</span>
<span class="na">es</span><span class="pi">:</span>
<span class="na">product_price</span><span class="pi">:</span> <span class="s2">"</span><span class="s">%{price}</span><span class="nv"> </span><span class="s">€"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="es:
product_price: "%{price} €"
">Copy</button>
</div>
<p>Todas las decisiones gramaticales y de puntuación se toman en la definición misma, por lo que la abstracción puede dar una traducción adecuada.</p><p>NOTA: Las palabras clave <code>default</code> y <code>scope</code> están reservadas y no se pueden usar como nombres de variables. Si se usan, se genera una excepción <code>I18n::ReservedInterpolationKey</code>. Si una traducción espera una variable de interpolación, pero no se ha pasado a <code>#translate</code>, se genera una excepción <code>I18n::MissingInterpolationArgument</code>.</p><h3 id="agregar-formatos-de-fecha-hora"><a class="anchorlink" href="#agregar-formatos-de-fecha-hora"><span>3.4</span> Agregar Formatos de Fecha/Hora</a></h3><p>¡OK! Ahora agreguemos una marca de tiempo a la vista, para que podamos demostrar también la función de <strong>localización de fecha/hora</strong>. Para localizar el formato de tiempo, pase el objeto Time a <code>I18n.l</code> o (preferiblemente) use el auxiliar <code>#l</code> de Rails. Puede elegir un formato pasando la opción <code>:format</code> - por defecto se usa el formato <code>:default</code>.</p><div class="interstitial code">
<pre><code class="highlight erb"><span class="c"><!-- app/views/home/index.html.erb --></span>
<span class="nt"><h1></span><span class="cp"><%=</span> <span class="n">t</span> <span class="ss">:hello_world</span> <span class="cp">%></span><span class="nt"></h1></span>
<span class="nt"><p></span><span class="cp"><%=</span> <span class="n">flash</span><span class="p">[</span><span class="ss">:notice</span><span class="p">]</span> <span class="cp">%></span><span class="nt"></p></span>
<span class="nt"><p></span><span class="cp"><%=</span> <span class="n">l</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span><span class="p">,</span> <span class="ss">format: :short</span> <span class="cp">%></span><span class="nt"></p></span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="<!-- app/views/home/index.html.erb -->
<h1><%= t :hello_world %></h1>
<p><%= flash[:notice] %></p>
<p><%= l Time.now, format: :short %></p>
">Copy</button>
</div>
<p>Y en nuestro archivo de traducciones pirata, agreguemos un formato de tiempo (ya está en los valores predeterminados de Rails para inglés):</p><div class="interstitial code">
<pre><code class="highlight yaml"><span class="c1"># config/locales/pirate.yml</span>
<span class="na">pirate</span><span class="pi">:</span>
<span class="na">time</span><span class="pi">:</span>
<span class="na">formats</span><span class="pi">:</span>
<span class="na">short</span><span class="pi">:</span> <span class="s2">"</span><span class="s">arrrround</span><span class="nv"> </span><span class="s">%H'ish"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="pirate:
time:
formats:
short: "arrrround %H'ish"
">Copy</button>
</div>
<p>Así que eso le daría:</p><p><img src="images/i18n/demo_localized_pirate.png" alt="rails i18n demo localized time to pirate"></p><p>CONSEJO: En este momento, es posible que necesite agregar algunos formatos de fecha/hora más para que el backend de I18n funcione como se espera (al menos para la configuración regional 'pirata'). Por supuesto, hay una gran posibilidad de que alguien ya haya hecho todo el trabajo al <strong>traducir los valores predeterminados de Rails para su configuración regional</strong>. Consulte el <a href="https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale">repositorio rails-i18n en GitHub</a> para un archivo de varios archivos de configuración regional. Cuando coloca dicho(s) archivo(s) en el directorio <code>config/locales/</code>, estarán automáticamente listos para su uso.</p><h3 id="reglas-de-inflección-para-otras-configuraciones-regionales"><a class="anchorlink" href="#reglas-de-inflección-para-otras-configuraciones-regionales"><span>3.5</span> Reglas de Inflección para Otras Configuraciones Regionales</a></h3><p>Rails le permite definir reglas de inflección (como reglas para singularización y pluralización) para configuraciones regionales distintas del inglés. En <code>config/initializers/inflections.rb</code>, puede definir estas reglas para múltiples configuraciones regionales. El inicializador contiene un ejemplo predeterminado para especificar reglas adicionales para inglés; siga ese formato para otras configuraciones regionales según lo considere necesario.</p><h3 id="vistas-localizadas"><a class="anchorlink" href="#vistas-localizadas"><span>3.6</span> Vistas Localizadas</a></h3><p>Supongamos que tiene un <em>BooksController</em> en su aplicación. Su acción <em>index</em> renderiza contenido en la plantilla <code>app/views/books/index.html.erb</code>. Cuando coloca una <em>variante localizada</em> de esta plantilla: <code>index.es.html.erb</code> en el mismo directorio, Rails renderizará el contenido en esta plantilla cuando la configuración regional se establezca en <code>:es</code>. Cuando la configuración regional se establezca en la configuración regional predeterminada, se usará la vista genérica <code>index.html.erb</code>. (Las versiones futuras de Rails pueden traer esta localización <em>automágica</em> a los activos en <code>public</code>, etc.)</p><p>Puede hacer uso de esta función, por ejemplo, cuando trabaje con una gran cantidad de contenido estático, que sería torpe colocar dentro de diccionarios YAML o Ruby. Tenga en cuenta, sin embargo, que cualquier cambio que desee hacer más adelante en la plantilla debe propagarse a todas ellas.</p><h3 id="organización-de-archivos-de-configuración-regional"><a class="anchorlink" href="#organización-de-archivos-de-configuración-regional"><span>3.7</span> Organización de Archivos de Configuración Regional</a></h3><p>Cuando está utilizando el SimpleStore predeterminado enviado con la biblioteca i18n, los diccionarios se almacenan en archivos de texto plano en el disco. Poner traducciones para todas las partes de su aplicación en un archivo por configuración regional podría ser difícil de gestionar. Puede almacenar estos archivos en una jerarquía que tenga sentido para usted.</p><p>Por ejemplo, su directorio <code>config/locales</code> podría verse así:</p><div class="interstitial code">
<pre><code class="highlight plaintext">|-defaults
|---es.yml
|---en.yml
|-models
|---book
|-----es.yml
|-----en.yml
|-views
|---defaults
|-----es.yml
|-----en.yml
|---books
|-----es.yml
|-----en.yml
|---users
|-----es.yml
|-----en.yml
|---navigation
|-----es.yml
|-----en.yml
</code></pre>
<button class="clipboard-button" data-clipboard-text="|-defaults
|---es.yml
|---en.yml
|-models
|---book
|-----es.yml
|-----en.yml
|-views
|---defaults
|-----es.yml
|-----en.yml
|---books
|-----es.yml
|-----en.yml
|---users
|-----es.yml
|-----en.yml
|---navigation
|-----es.yml
|-----en.yml
">Copy</button>
</div>
<p>De esta manera, puede separar nombres de modelos y atributos de modelos del texto dentro de las vistas, y todo esto de los "predeterminados" (por ejemplo, formatos de fecha y hora). Otros almacenes para la biblioteca i18n podrían proporcionar diferentes medios de tal separación.</p><p>NOTA: El mecanismo de carga de configuraciones regionales predeterminado en Rails no carga archivos de configuración regional en diccionarios anidados, como tenemos aquí. Entonces, para que esto funcione, debemos decirle explícitamente a Rails que busque más allá:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="c1"># config/application.rb</span>
<span class="n">config</span><span class="p">.</span><span class="nf">i18n</span><span class="p">.</span><span class="nf">load_path</span> <span class="o">+=</span> <span class="no">Dir</span><span class="p">[</span><span class="no">Rails</span><span class="p">.</span><span class="nf">root</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="s1">'config'</span><span class="p">,</span> <span class="s1">'locales'</span><span class="p">,</span> <span class="s1">'**'</span><span class="p">,</span> <span class="s1">'*.{rb,yml}'</span><span class="p">)]</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')]
">Copy</button>
</div>
<h2 id="resumen-de-las-funciones-de-la-api-de-i18n"><a class="anchorlink" href="#resumen-de-las-funciones-de-la-api-de-i18n"><span>4</span> Resumen de las Funciones de la API de I18n</a></h2><p>Ahora debería tener una buena comprensión de cómo usar la biblioteca i18n y saber cómo internacionalizar una aplicación Rails básica. En los siguientes capítulos, cubriremos sus características con más profundidad.</p><p>Estos capítulos mostrarán ejemplos utilizando tanto el método <code>I18n.translate</code> como el <a href="https://edgeapi.rubyonrails.org/classes/ActionView/Helpers/TranslationHelper.html#method-i-translate">método auxiliar <code>translate</code> de la vista</a> (notando las características adicionales proporcionadas por el método auxiliar de la vista).</p><p>Se cubren características como estas:</p>
<ul>
<li>búsqueda de traducciones</li>
<li>interpolación de datos en traducciones</li>
<li>pluralización de traducciones</li>
<li>uso de traducciones HTML seguras (solo método auxiliar de vista)</li>
<li>localización de fechas, números, moneda, etc.</li>
</ul>
<h3 id="búsqueda-de-traducciones"><a class="anchorlink" href="#búsqueda-de-traducciones"><span>4.1</span> Búsqueda de Traducciones</a></h3><h4 id="búsqueda-básica-ámbitos-y-claves-anidadas"><a class="anchorlink" href="#búsqueda-básica-ámbitos-y-claves-anidadas"><span>4.1.1</span> Búsqueda Básica, Ámbitos y Claves Anidadas</a></h4><p>Las traducciones se buscan por claves que pueden ser tanto Símbolos como Cadenas, por lo que estas llamadas son equivalentes:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:message</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'message'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t :message
I18n.t 'message'
">Copy</button>
</div>
<p>El método <code>translate</code> también toma una opción <code>:scope</code> que puede contener una o más claves adicionales que se utilizarán para especificar un "namespace" o ámbito para una clave de traducción:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:record_invalid</span><span class="p">,</span> <span class="ss">scope: </span><span class="p">[</span><span class="ss">:activerecord</span><span class="p">,</span> <span class="ss">:errors</span><span class="p">,</span> <span class="ss">:messages</span><span class="p">]</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]
">Copy</button>
</div>
<p>Esto busca el mensaje <code>:record_invalid</code> en los mensajes de error de Active Record.</p><p>Además, tanto la clave como los ámbitos se pueden especificar como claves separadas por puntos, como en:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">translate</span> <span class="s2">"activerecord.errors.messages.record_invalid"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.translate "activerecord.errors.messages.record_invalid"
">Copy</button>
</div>
<p>Por lo tanto, las siguientes llamadas son equivalentes:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'activerecord.errors.messages.record_invalid'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'errors.messages.record_invalid'</span><span class="p">,</span> <span class="ss">scope: :activerecord</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:record_invalid</span><span class="p">,</span> <span class="ss">scope: </span><span class="s1">'activerecord.errors.messages'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:record_invalid</span><span class="p">,</span> <span class="ss">scope: </span><span class="p">[</span><span class="ss">:activerecord</span><span class="p">,</span> <span class="ss">:errors</span><span class="p">,</span> <span class="ss">:messages</span><span class="p">]</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t 'activerecord.errors.messages.record_invalid'
I18n.t 'errors.messages.record_invalid', scope: :activerecord
I18n.t :record_invalid, scope: 'activerecord.errors.messages'
I18n.t :record_invalid, scope: [:activerecord, :errors, :messages]
">Copy</button>
</div>
<h4 id="valores-predeterminados"><a class="anchorlink" href="#valores-predeterminados"><span>4.1.2</span> Valores Predeterminados</a></h4><p>Cuando se da una opción <code>:default</code>, su valor se devolverá si falta la traducción:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:missing</span><span class="p">,</span> <span class="ss">default: </span><span class="s1">'Not here'</span>
<span class="c1"># => 'Not here'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t :missing, default: 'Not here'
# => 'Not here'
">Copy</button>
</div>
<p>Si el valor de <code>:default</code> es un Símbolo, se usará como clave y se traducirá. Se pueden proporcionar múltiples valores como predeterminados. Se devolverá el primero que resulte en un valor.</p><p>Por ejemplo, lo siguiente primero intenta traducir la clave <code>:missing</code> y luego la clave <code>:also_missing</code>. Como ambos no dan un resultado, se devolverá la cadena "Not here":</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:missing</span><span class="p">,</span> <span class="ss">default: </span><span class="p">[</span><span class="ss">:also_missing</span><span class="p">,</span> <span class="s1">'Not here'</span><span class="p">]</span>
<span class="c1"># => 'Not here'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t :missing, default: [:also_missing, 'Not here']
# => 'Not here'
">Copy</button>
</div>
<h4 id="búsqueda-masiva-y-de-espacios-de-nombres"><a class="anchorlink" href="#búsqueda-masiva-y-de-espacios-de-nombres"><span>4.1.3</span> Búsqueda Masiva y de Espacios de Nombres</a></h4><p>Para buscar múltiples traducciones a la vez, se puede pasar una matriz de claves:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="p">[</span><span class="ss">:odd</span><span class="p">,</span> <span class="ss">:even</span><span class="p">],</span> <span class="ss">scope: </span><span class="s1">'errors.messages'</span>
<span class="c1"># => ["must be odd", "must be even"]</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t [:odd, :even], scope: 'errors.messages'
# => ["must be odd", "must be even"]
">Copy</button>
</div>
<p>Además, una clave puede traducirse a un hash (potencialmente anidado) de traducciones agrupadas. Por ejemplo, se pueden recibir <em>todos</em> los mensajes de error de Active Record como un Hash con:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'errors.messages'</span>
<span class="c1"># => {:inclusion=>"is not included in the list", :exclusion=> ... }</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t 'errors.messages'
# => {:inclusion=>"is not included in the list", :exclusion=> ... }
">Copy</button>
</div>
<p>Si desea realizar interpolación en un hash masivo de traducciones, necesita pasar <code>deep_interpolation: true</code> como un parámetro. Cuando tiene el siguiente diccionario:</p><div class="interstitial code">
<pre><code class="highlight yaml"><span class="na">en</span><span class="pi">:</span>
<span class="na">welcome</span><span class="pi">:</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Welcome!"</span>
<span class="na">content</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Welcome</span><span class="nv"> </span><span class="s">to</span><span class="nv"> </span><span class="s">the</span><span class="nv"> </span><span class="s">%{app_name}"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="en:
welcome:
title: "Welcome!"
content: "Welcome to the %{app_name}"
">Copy</button>
</div>
<p>entonces la interpolación anidada se ignorará sin la configuración:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'welcome'</span><span class="p">,</span> <span class="ss">app_name: </span><span class="s1">'book store'</span>
<span class="c1"># => {:title=>"Welcome!", :content=>"Welcome to the %{app_name}"}</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="s1">'welcome'</span><span class="p">,</span> <span class="ss">deep_interpolation: </span><span class="kp">true</span><span class="p">,</span> <span class="ss">app_name: </span><span class="s1">'book store'</span>
<span class="c1"># => {:title=>"Welcome!", :content=>"Welcome to the book store"}</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.t 'welcome', app_name: 'book store'
# => {:title=>"Welcome!", :content=>"Welcome to the %{app_name}"}
I18n.t 'welcome', deep_interpolation: true, app_name: 'book store'
# => {:title=>"Welcome!", :content=>"Welcome to the book store"}
">Copy</button>
</div>
<h4 id="búsqueda-perezosa"><a class="anchorlink" href="#búsqueda-perezosa"><span>4.1.4</span> Búsqueda "Perezosa"</a></h4><p>Rails implementa una forma conveniente de buscar la configuración regional dentro de <em>vistas</em>. Cuando tiene el siguiente diccionario:</p><div class="interstitial code">
<pre><code class="highlight yaml"><span class="na">es</span><span class="pi">:</span>
<span class="na">books</span><span class="pi">:</span>
<span class="na">index</span><span class="pi">:</span>
<span class="na">title</span><span class="pi">:</span> <span class="s2">"</span><span class="s">Título"</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="es:
books:
index:
title: "Título"
">Copy</button>
</div>
<p>puede buscar el valor <code>books.index.title</code> <strong>dentro</strong> de la plantilla <code>app/views/books/index.html.erb</code> así (note el punto):</p><div class="interstitial code">
<pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">t</span> <span class="s1">'.title'</span> <span class="cp">%></span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="<%= t '.title' %>
">Copy</button>
</div>
<p>NOTA: El ámbito automático de traducción por parcial solo está disponible desde el método auxiliar de vista <code>translate</code>.</p><p>La búsqueda "perezosa" también se puede usar en controladores:</p><div class="interstitial code">
<pre><code class="highlight yaml"><span class="na">en</span><span class="pi">:</span>
<span class="na">books</span><span class="pi">:</span>
<span class="na">create</span><span class="pi">:</span>
<span class="na">success</span><span class="pi">:</span> <span class="s">Book created!</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="en:
books:
create:
success: Book created!
">Copy</button>
</div>
<p>Esto es útil para establecer mensajes flash, por ejemplo:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">BooksController</span> <span class="o"><</span> <span class="no">ApplicationController</span>
<span class="k">def</span> <span class="nf">create</span>
<span class="c1"># ...</span>
<span class="n">redirect_to</span> <span class="n">books_url</span><span class="p">,</span> <span class="ss">notice: </span><span class="n">t</span><span class="p">(</span><span class="s1">'.success'</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="class BooksController < ApplicationController
def create
# ...
redirect_to books_url, notice: t('.success')
end
end
">Copy</button>
</div>
<h3 id="pluralización"><a class="anchorlink" href="#pluralización"><span>4.2</span> Pluralización</a></h3><p>En muchos idiomas, incluido el inglés, solo hay dos formas, una singular y una plural, para una cadena dada, por ejemplo, "1 message" y "2 messages". Otros idiomas (<a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ar">Árabe</a>, <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ja">Japonés</a>, <a href="http://www.unicode.org/cldr/charts/latest/supplemental/language_plural_rules.html#ru">Ruso</a> y muchos más) tienen gramáticas diferentes que tienen formas <a href="http://cldr.unicode.org/index/cldr-spec/plural-rules">plurales</a> adicionales o menos. Por lo tanto, la API de I18n proporciona una función de pluralización flexible.</p><p>La variable de interpolación <code>:count</code> tiene un papel especial en el que se interpola en la traducción y se utiliza para elegir una pluralización de las traducciones de acuerdo con las reglas de pluralización definidas en el backend de pluralización. Por defecto, solo se aplican las reglas de pluralización en inglés.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">backend</span><span class="p">.</span><span class="nf">store_translations</span> <span class="ss">:en</span><span class="p">,</span> <span class="ss">inbox: </span><span class="p">{</span>
<span class="ss">zero: </span><span class="s1">'no messages'</span><span class="p">,</span> <span class="c1"># opcional</span>
<span class="ss">one: </span><span class="s1">'one message'</span><span class="p">,</span>
<span class="ss">other: </span><span class="s1">'%{count} messages'</span>
<span class="p">}</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">translate</span> <span class="ss">:inbox</span><span class="p">,</span> <span class="ss">count: </span><span class="mi">2</span>
<span class="c1"># => '2 messages'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">translate</span> <span class="ss">:inbox</span><span class="p">,</span> <span class="ss">count: </span><span class="mi">1</span>
<span class="c1"># => 'one message'</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">translate</span> <span class="ss">:inbox</span><span class="p">,</span> <span class="ss">count: </span><span class="mi">0</span>
<span class="c1"># => 'no messages'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n.backend.store_translations :en, inbox: {
zero: 'no messages', # opcional
one: 'one message',
other: '%{count} messages'
}
I18n.translate :inbox, count: 2
# => '2 messages'
I18n.translate :inbox, count: 1
# => 'one message'
I18n.translate :inbox, count: 0
# => 'no messages'
">Copy</button>
</div>
<p>El algoritmo para pluralizaciones en <code>:en</code> es tan simple como:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="n">lookup_key</span> <span class="o">=</span> <span class="ss">:zero</span> <span class="k">if</span> <span class="n">count</span> <span class="o">==</span> <span class="mi">0</span> <span class="o">&&</span> <span class="n">entry</span><span class="p">.</span><span class="nf">has_key?</span><span class="p">(</span><span class="ss">:zero</span><span class="p">)</span>
<span class="n">lookup_key</span> <span class="o">||=</span> <span class="n">count</span> <span class="o">==</span> <span class="mi">1</span> <span class="p">?</span> <span class="ss">:one</span> <span class="p">:</span> <span class="ss">:other</span>
<span class="n">entry</span><span class="p">[</span><span class="n">lookup_key</span><span class="p">]</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="lookup_key = :zero if count == 0 && entry.has_key?(:zero)
lookup_key ||= count == 1 ? :one : :other
entry[lookup_key]
">Copy</button>
</div>
<p>La traducción denotada como <code>:one</code> se considera singular, y <code>:other</code> se usa como plural. Si el conteo es cero, y hay una entrada <code>:zero</code> presente, entonces se usará en lugar de <code>:other</code>.</p><p>Si la búsqueda de la clave no devuelve un Hash adecuado para la pluralización, se genera una excepción <code>I18n::InvalidPluralizationData</code>.</p><h4 id="reglas-específicas-de-configuración-regional"><a class="anchorlink" href="#reglas-específicas-de-configuración-regional"><span>4.2.1</span> Reglas Específicas de Configuración Regional</a></h4><p>La gema I18n proporciona un backend de Pluralización que se puede usar para habilitar reglas específicas de configuración regional. Inclúyala en el backend Simple, luego agregue los algoritmos de pluralización localizados al almacén de traducción, como <code>i18n.plural.rule</code>.</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="o">::</span><span class="no">Backend</span><span class="o">::</span><span class="no">Simple</span><span class="p">.</span><span class="nf">include</span><span class="p">(</span><span class="no">I18n</span><span class="o">::</span><span class="no">Backend</span><span class="o">::</span><span class="no">Pluralization</span><span class="p">)</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">backend</span><span class="p">.</span><span class="nf">store_translations</span> <span class="ss">:pt</span><span class="p">,</span> <span class="ss">i18n: </span><span class="p">{</span> <span class="ss">plural: </span><span class="p">{</span> <span class="ss">rule: </span><span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">n</span><span class="o">|</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">].</span><span class="nf">include?</span><span class="p">(</span><span class="n">n</span><span class="p">)</span> <span class="p">?</span> <span class="ss">:one</span> <span class="p">:</span> <span class="ss">:other</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">backend</span><span class="p">.</span><span class="nf">store_translations</span> <span class="ss">:pt</span><span class="p">,</span> <span class="ss">apples: </span><span class="p">{</span> <span class="ss">one: </span><span class="s1">'one or none'</span><span class="p">,</span> <span class="ss">other: </span><span class="s1">'more than one'</span> <span class="p">}</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:apples</span><span class="p">,</span> <span class="ss">count: </span><span class="mi">0</span><span class="p">,</span> <span class="ss">locale: :pt</span>
<span class="c1"># => 'one or none'</span>
</code></pre>
<button class="clipboard-button" data-clipboard-text="I18n::Backend::Simple.include(I18n::Backend::Pluralization)
I18n.backend.store_translations :pt, i18n: { plural: { rule: lambda { |n| [0, 1].include?(n) ? :one : :other } } }
I18n.backend.store_translations :pt, apples: { one: 'one or none', other: 'more than one' }
I18n.t :apples, count: 0, locale: :pt
# => 'one or none'
">Copy</button>
</div>
<p>Alternativamente, la gema separada <a href="https://github.com/svenfuchs/rails-i18n">rails-i18n</a> se puede usar para proporcionar un conjunto más completo de reglas de pluralización específicas de configuración regional.</p><h3 id="establecer-y-pasar-una-configuración-regional"><a class="anchorlink" href="#establecer-y-pasar-una-configuración-regional"><span>4.3</span> Establecer y Pasar una Configuración Regional</a></h3><p>La configuración regional se puede establecer pseudo-globalmente en <code>I18n.locale</code> (que usa <code>Thread.current</code> de la misma manera que, por ejemplo, <code>Time.zone</code>) o se puede pasar como una opción a <code>#translate</code> y <code>#localize</code>.</p><p>Si no se pasa una configuración regional, se usa <code>I18n.locale</code>:</p><div class="interstitial code">
<pre><code class="highlight ruby"><span class="no">I18n</span><span class="p">.</span><span class="nf">locale</span> <span class="o">=</span> <span class="ss">:de</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">t</span> <span class="ss">:foo</span>
<span class="no">I18n</span><span class="p">.</span><span class="nf">l</span> <span class="no">Time</span><span class="p">.</span><span class="nf">now</span>