gettext 3.3.3 → 3.3.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (122) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +4 -0
  3. data/doc/text/news.md +231 -0
  4. data/gettext.gemspec +1 -1
  5. data/lib/gettext/locale_path.rb +12 -8
  6. data/lib/gettext/mo.rb +7 -5
  7. data/lib/gettext/tools/msginit.rb +216 -50
  8. data/lib/gettext/tools/msgmerge.rb +13 -0
  9. data/lib/gettext/tools/parser/erb.rb +9 -1
  10. data/lib/gettext/tools/parser/glade.rb +38 -40
  11. data/lib/gettext/tools/parser/gtk_builder_ui_definitions.rb +6 -6
  12. data/lib/gettext/tools/parser/ruby.rb +50 -29
  13. data/lib/gettext/version.rb +2 -2
  14. data/locale/bg/LC_MESSAGES/gettext.mo +0 -0
  15. data/locale/bs/LC_MESSAGES/gettext.mo +0 -0
  16. data/locale/ca/LC_MESSAGES/gettext.mo +0 -0
  17. data/locale/cs/LC_MESSAGES/gettext.mo +0 -0
  18. data/locale/de/LC_MESSAGES/gettext.mo +0 -0
  19. data/locale/el/LC_MESSAGES/gettext.mo +0 -0
  20. data/locale/eo/LC_MESSAGES/gettext.mo +0 -0
  21. data/locale/es/LC_MESSAGES/gettext.mo +0 -0
  22. data/locale/et/LC_MESSAGES/gettext.mo +0 -0
  23. data/locale/fr/LC_MESSAGES/gettext.mo +0 -0
  24. data/locale/hr/LC_MESSAGES/gettext.mo +0 -0
  25. data/locale/hu/LC_MESSAGES/gettext.mo +0 -0
  26. data/locale/it/LC_MESSAGES/gettext.mo +0 -0
  27. data/locale/ja/LC_MESSAGES/gettext.mo +0 -0
  28. data/locale/ko/LC_MESSAGES/gettext.mo +0 -0
  29. data/locale/lv/LC_MESSAGES/gettext.mo +0 -0
  30. data/locale/nb/LC_MESSAGES/gettext.mo +0 -0
  31. data/locale/nl/LC_MESSAGES/gettext.mo +0 -0
  32. data/locale/pt_BR/LC_MESSAGES/gettext.mo +0 -0
  33. data/locale/ru/LC_MESSAGES/gettext.mo +0 -0
  34. data/locale/sr/LC_MESSAGES/gettext.mo +0 -0
  35. data/locale/uk/LC_MESSAGES/gettext.mo +0 -0
  36. data/locale/vi/LC_MESSAGES/gettext.mo +0 -0
  37. data/locale/zh/LC_MESSAGES/gettext.mo +0 -0
  38. data/locale/zh_TW/LC_MESSAGES/gettext.mo +0 -0
  39. data/po/bg/gettext.edit.po +36 -554
  40. data/po/bg/gettext.po +0 -423
  41. data/po/bs/gettext.edit.po +36 -554
  42. data/po/bs/gettext.po +0 -423
  43. data/po/ca/gettext.edit.po +36 -554
  44. data/po/ca/gettext.po +0 -423
  45. data/po/cs/gettext.edit.po +36 -554
  46. data/po/cs/gettext.po +0 -423
  47. data/po/de/gettext.edit.po +36 -554
  48. data/po/de/gettext.po +0 -423
  49. data/po/el/gettext.edit.po +36 -554
  50. data/po/el/gettext.po +0 -423
  51. data/po/eo/gettext.edit.po +36 -554
  52. data/po/eo/gettext.po +0 -423
  53. data/po/es/gettext.edit.po +36 -554
  54. data/po/es/gettext.po +0 -423
  55. data/po/et/gettext.edit.po +36 -554
  56. data/po/et/gettext.po +0 -423
  57. data/po/fr/gettext.edit.po +36 -554
  58. data/po/fr/gettext.po +0 -423
  59. data/po/gettext.pot +37 -619
  60. data/po/hr/gettext.edit.po +36 -554
  61. data/po/hr/gettext.po +0 -423
  62. data/po/hu/gettext.edit.po +36 -554
  63. data/po/hu/gettext.po +0 -423
  64. data/po/it/gettext.edit.po +36 -554
  65. data/po/it/gettext.po +0 -423
  66. data/po/ja/gettext.edit.po +36 -554
  67. data/po/ja/gettext.po +0 -423
  68. data/po/ko/gettext.edit.po +36 -554
  69. data/po/ko/gettext.po +0 -423
  70. data/po/lv/gettext.edit.po +36 -554
  71. data/po/lv/gettext.po +0 -423
  72. data/po/nb/gettext.edit.po +36 -554
  73. data/po/nb/gettext.po +0 -423
  74. data/po/nl/gettext.edit.po +36 -554
  75. data/po/nl/gettext.po +0 -423
  76. data/po/pt_BR/gettext.edit.po +36 -554
  77. data/po/pt_BR/gettext.po +0 -423
  78. data/po/ru/gettext.edit.po +36 -554
  79. data/po/ru/gettext.po +0 -423
  80. data/po/sr/gettext.edit.po +36 -554
  81. data/po/sr/gettext.po +0 -423
  82. data/po/sv/gettext.edit.po +34 -555
  83. data/po/sv/gettext.po +0 -423
  84. data/po/uk/gettext.edit.po +36 -554
  85. data/po/uk/gettext.po +0 -423
  86. data/po/vi/gettext.edit.po +36 -554
  87. data/po/vi/gettext.po +0 -423
  88. data/po/zh/gettext.edit.po +36 -554
  89. data/po/zh/gettext.po +0 -423
  90. data/po/zh_TW/gettext.edit.po +36 -554
  91. data/po/zh_TW/gettext.po +0 -423
  92. data/test/fixtures/_.rb +1 -1
  93. data/test/fixtures/_/pipe.rb +32 -0
  94. data/test/fixtures/erb/minus.rhtml +12 -0
  95. data/test/fixtures/{gladeparser.glade → glade/2.glade} +0 -0
  96. data/test/fixtures/glade/3.glade +63 -0
  97. data/test/fixtures/gtk_builder_ui_definitions.ui~ +68 -0
  98. data/test/fixtures/multi_text_domain.rb +12 -12
  99. data/test/fixtures/np_.rb +1 -1
  100. data/test/fixtures/ns_.rb +1 -1
  101. data/test/fixtures/p_.rb +1 -1
  102. data/test/fixtures/ruby/percent_lower_i.rb +1 -0
  103. data/test/fixtures/ruby/percent_lower_w.rb +1 -0
  104. data/test/fixtures/ruby/percent_upper_i.rb +1 -0
  105. data/test/fixtures/ruby/percent_upper_w.rb +1 -0
  106. data/test/fixtures/s_.rb +1 -1
  107. data/test/fixtures/simple.rb +1 -1
  108. data/test/fixtures/upper_nn_.rb +77 -0
  109. data/test/po/_.pot +20 -4
  110. data/test/po/ja/_.edit.po +24 -0
  111. data/test/po/np_.pot +8 -5
  112. data/test/po/ns_.pot +6 -4
  113. data/test/po/p_.pot +3 -3
  114. data/test/po/s_.pot +6 -4
  115. data/test/run-test.rb +0 -1
  116. data/test/test_parser.rb +42 -17
  117. data/test/tools/parser/test_glade.rb +91 -0
  118. data/test/tools/parser/test_gtk_builder_ui_definitions.rb +19 -1
  119. data/test/tools/parser/test_ruby.rb +42 -0
  120. data/test/tools/test_msginit.rb +77 -3
  121. data/test/tools/test_msgmerge.rb +34 -0
  122. metadata +37 -28
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a2b035c2e33e7e5d59eb90ca4bc2ec5f002300cd597bb7170b265ee3dea1017b
4
- data.tar.gz: c964321d37fb3e9608527d08c96a3aef18791fc4ce41f9efdc950e49086cdf53
3
+ metadata.gz: 854c34e40028ef9e71045cbd1c8f77a4846c5f668de2cef716017b52d05515b2
4
+ data.tar.gz: bc0a5bcb8a1a30ed0b5de8272bae275a996f5ef5e6533a281997a67bf99f3f95
5
5
  SHA512:
6
- metadata.gz: ff63d36681ef49c5d9ae4478da15f671046b67422477f01a3f408c6a6ee653688354d1502c44f0923691b706fdf2ca8de0fa267715c31f85ac8cb4c531ac7c5f
7
- data.tar.gz: 41cc509f2ab0502e3220ca39e37c201a056cbf372aca206fc3f3eb240b49308388c64f09b80aa26397f5cd92d35f750a09cd5f279ca7cd887bea134e119f0514
6
+ metadata.gz: 6978df6c5a2e52c5eb9b1101bb89fd2ec3febec663bf1418b054929572a333935cd02cfba15b93818ae3b89971b2fb442b2f8f48c0370fd516bacd7085eac915
7
+ data.tar.gz: a7fbb7a6b3e93a374440ad2ae3c69f43aeb238c54479825c45e8b14f5f90408fa05b2c06db05078af531defecc7b181bda30e0a2e53068718422ba66bbd7ae94
data/Rakefile CHANGED
@@ -86,6 +86,10 @@ end
86
86
  xgettext_options = ["--add-comments=TRANSLATORS:"]
87
87
  GetText::Tools::Task.define do |task|
88
88
  task.spec = spec
89
+ task.files = task.files.reject do |file|
90
+ file.start_with?("samples/") or
91
+ file.start_with?("test/")
92
+ end
89
93
  task.xgettext_options.concat(xgettext_options)
90
94
  end
91
95
 
data/doc/text/news.md CHANGED
@@ -1,5 +1,82 @@
1
1
  # News
2
2
 
3
+ ## 3.3.8: 2021-06-09 {#version-3-3-8}
4
+
5
+ ### Improvements
6
+
7
+ * msginit: Added support for generating plural forms with
8
+ Unicode's CLDR plural rules data.
9
+ [GitHub#85][Suggested by Michaël Hoste]
10
+
11
+ * rxgettext ui: Added support for GtkBuilder UI definitions format
12
+ with `.glade` extension.
13
+ [GitHub#74][Reported by dorle-o]
14
+
15
+ ### Fixes
16
+
17
+ * rxgettext ruby: Fixed a bug that `Nn_` isn't extracted.
18
+ [GitHub#86][Reported by Kai Ramuenke]
19
+
20
+ ### Thanks
21
+
22
+ * Kai Ramuenke
23
+
24
+ * Michaël Hoste
25
+
26
+ * dorle-o
27
+
28
+ ## 3.3.7: 2021-01-18 {#version-3-3-7}
29
+
30
+ ### Improvements
31
+
32
+ * msgmerge: Added `--no-report-warning` option.
33
+ [GitHub#81][Reported by Akim Demaille]
34
+
35
+ ### Thanks
36
+
37
+ * Akim Demaille
38
+
39
+ ## 3.3.6: 2020-08-04 {#version-3-3-6}
40
+
41
+ ### Improvements
42
+
43
+ * erb: Added support for `-%>`.
44
+ [GitHub#77][Reported by lremes]
45
+
46
+ * Removed ChangeLog.
47
+ [GitHub#76][Reported by Will Stephenson]
48
+
49
+ * Don't assume `RbConfig::CONFIG["datadir"]` is available. For
50
+ example, TruffleRuby doesn't provide it.
51
+
52
+ ### Thanks
53
+
54
+ * lremes
55
+
56
+ * Will Stephenson
57
+
58
+ ## 3.3.5: 2020-02-15 {#version-3-3-5}
59
+
60
+ ### Improvements
61
+
62
+ * Added support for `|` method.
63
+ [GitHub#73][Reported by dorle-o]
64
+
65
+ ### Thanks
66
+
67
+ * dorle-o
68
+
69
+ ## 3.3.4: 2020-02-12 {#version-3-3-4}
70
+
71
+ ### Improvements
72
+
73
+ * Added support for `%W`.
74
+ [GitHub#72][Reported by Michaël Hoste]
75
+
76
+ ### Thanks
77
+
78
+ * Michaël Hoste
79
+
3
80
  ## 3.3.3: 2020-02-05 {#version-3-3-3}
4
81
 
5
82
  ### Improvements
@@ -828,3 +905,157 @@ Ruby 1.9 support release.
828
905
  * Gunnar Wolf
829
906
  * Ivan Pirlik
830
907
  * Tatsuki Sugiura
908
+
909
+ ## 2.2.1: 2012-05-20
910
+
911
+ ### Changes
912
+
913
+ * Supported non ASCII string in msgid. [GitHub#1]
914
+ [Patch by Urban Hafner]
915
+ * Stopped overriding String#% on Ruby 1.9.
916
+ * Fixed a bug that "\" is too escaped.
917
+ * Removed GetText.bindtext dependency from GetText::PoParser.
918
+ * Ranamed GetText::MOFile to GetText::MoFile but GetText::MOFile
919
+ is still available.
920
+
921
+ ### Thanks
922
+
923
+ * Urban Hafner
924
+
925
+ ## 2.2.0: 2012-03-11
926
+
927
+ ### Changes
928
+
929
+ * Supported ruby-1.9. [Patch by hallelujah]
930
+ * Supported $SAFE=1. [Patch by bon]
931
+ * Improved argument check. [Suggested by Morus Walter]
932
+ * Supported ruby-1.8.6 again. [Bug#27447] [Reported by Mamoru Tasaka]
933
+ * Fixed Ukrainan translation path. [Bug#28277] [Reported by Gunnar Wolf]
934
+ * Fixed a bug that only the last path in GETTEXT_PATH environment
935
+ variable is used. [Bug#28345] [Reported by Ivan Pirlik]
936
+ * Fixed a bug that Ruby-GetText-Package modifies $LOAD_PATH. [Bug#28094]
937
+ [Reported by Tatsuki Sugiura]
938
+
939
+ ### Thanks
940
+
941
+ * hallelujah
942
+ * bon
943
+ * Morus Walter
944
+ * Mamoru Tasaka
945
+ * Gunnar Wolf
946
+ * Ivan Pirlik
947
+ * Tatsuki Sugiura
948
+
949
+
950
+ ## 2.1.0: 2009-11-14
951
+
952
+ ### Changes
953
+
954
+ * Implemented parsing of translator comments (GNU gettext feature)
955
+ [by Vladimir Dobriakov]
956
+ * Refactor the directory structure.
957
+ * Move files for runtime to lib/gettext/runtime/*.
958
+ * Move files for development(rgettext/rmsgfmt) to
959
+ lib/gettext/tools/*.
960
+ * Refactor parsers for po. po-message object is defined as GetText::PoMessage
961
+ class. [by Vladimir Dobriakov, Masao Mutoh]
962
+ * Speed up when lots of objects are created to share the textdomain in each
963
+ objects. [Reported by Gaël Séchaud.]
964
+ * Fix "%{foo.bar}" %{"foo.bar".to_sym => "a"} doesn't work.
965
+ [Bug#26663, Reported by Danilo Castilho]
966
+ * lib/gettext.rb: Fixed to work unless gem. [Reported by Vladimir Dobriakov]
967
+ * Fixed a wrong String literal in a CGI sample.
968
+ [Bug #26531, by Eugene Mikhailov]
969
+ * Update license information(explicit to use ruby's or LGPL).
970
+ [Pointed out by Masateru Yoshikawa]
971
+ * Code cleanup.
972
+ * Update minor version.
973
+
974
+ ## 2.0.4: 2009-05-23
975
+
976
+ ### Changes
977
+
978
+ * Fix String#% return nil when the string have no place holders. [by okkez]
979
+ * Update pofiles and remove old messages.
980
+ * suppress some warnings on Ruby 1.9.x. [by Nobuhiro IMAI]
981
+ * Fix not to run tests on Win32.
982
+
983
+ ## 2.0.3: 2009-05-09
984
+
985
+ ### Changes
986
+
987
+ * Fixed the dependencies. [Reported by Hans de Graaff]
988
+
989
+ ## 2.0.2: 2009-05-04
990
+
991
+ ### Changes
992
+
993
+ * Support ruby-1.9.1 style format string such as `%<foo>d`.
994
+ * Apply new `Locale.set_app_language_tags` and Locale.candidates.
995
+ [Suggested by Vladimir Dobriakov]
996
+ * Enhance to support ruby-1.9.x [by OZAWA Sakuro]
997
+ * poparser work with proper encoding.
998
+ * string.rb: #bytesize alias to #size in older ruby version such as 1.8.5.
999
+ * Fixed bugs
1000
+ * `n_()` to work when Plural-Forms line in po-file is not correct.
1001
+ [Reported by Sava Chankov (Bug#25570)]
1002
+ * GetText::Locale.default_rules_path : $LOAD_PATH is not well parsed.
1003
+ [by hallelujah]
1004
+ * locale_path.rb: Fixed warning message.
1005
+
1006
+ ### Thanks
1007
+
1008
+ * hallelujah
1009
+ * Sava Chankov
1010
+ * OZAWA Sakuro
1011
+ * Vladimir Dobriakov
1012
+
1013
+ ## 2.0.1: 2009-04-17
1014
+
1015
+ ### Changes
1016
+
1017
+ * Fixed bugs
1018
+ * doesn't work with ruby-1.8.5. [Reported by Dan Coutu]
1019
+ * GetText.locale= can't keep the locale. [Reported by Adam Ilan]
1020
+ * Break backward compatibility of bindtextdomain
1021
+ [Reported by Mamoru Tasaka(#24947), Mathieu Blondel]
1022
+ * Other trivial fixes/improvement.
1023
+ * 1.8 times faster than 2.0.0.
1024
+ * GetText::LocalePath is separated from GetText::TextDomainManager.
1025
+ Improve to find the locale path.
1026
+ * Enhance to support ruby-1.9.x [by OZAWA Sakuro]
1027
+
1028
+ ### Thanks
1029
+
1030
+ * OZAWA Sakuro
1031
+ * Tietew
1032
+ * Adam Ilan
1033
+ * Mamoru Tasaka
1034
+ * Mathieu Blondel
1035
+
1036
+ ## 2.0.0: 2009-03-21
1037
+
1038
+ ### Changes
1039
+
1040
+ * Separate this library to locale and rails-support to locale,
1041
+ locale\_rails, gettext\_activerecord, gettext\_rails.
1042
+ * Depends on locale(ruby-locale).
1043
+ * Removes to support rails.
1044
+ * A lot of referctoring, improvements.
1045
+ * Thread safe.
1046
+ * New APIs for gettext/tools instead of gettext/utils.
1047
+ * Move to github.com.
1048
+
1049
+ ### Special thanks
1050
+
1051
+ * Michael Grosser: A lot of improvement.
1052
+
1053
+ ### Thanks
1054
+
1055
+ * Tietew
1056
+ * Kazuhiro NISHIYAMA
1057
+ * Fabio M.A.
1058
+ * Tuptus
1059
+ * Morus Walter
1060
+ * Vladimir Dobriakov
1061
+ * Ramsey
data/gettext.gemspec CHANGED
@@ -30,13 +30,13 @@ So you can use GNU gettext tools for maintaining.
30
30
  s.required_ruby_version = ">= 2.5.0"
31
31
 
32
32
  s.add_runtime_dependency("locale", ">= 2.0.5")
33
+ s.add_runtime_dependency("red-datasets")
33
34
  s.add_runtime_dependency("text", ">= 1.3.0")
34
35
  s.add_development_dependency("rake")
35
36
  s.add_development_dependency("racc")
36
37
  s.add_development_dependency("yard")
37
38
  s.add_development_dependency("kramdown")
38
39
  s.add_development_dependency("test-unit")
39
- s.add_development_dependency("test-unit-notify")
40
40
  s.add_development_dependency("test-unit-rr")
41
41
  s.license = "Ruby or LGPLv3+"
42
42
  end
@@ -17,14 +17,18 @@ module GetText
17
17
  class LocalePath
18
18
  # The default locale paths.
19
19
  CONFIG_PREFIX = RbConfig::CONFIG['prefix'].gsub(/\/local/, "")
20
- DEFAULT_RULES = [
21
- "./locale/%{lang}/LC_MESSAGES/%{name}.mo",
22
- "./locale/%{lang}/%{name}.mo",
23
- "#{RbConfig::CONFIG['datadir']}/locale/%{lang}/LC_MESSAGES/%{name}.mo",
24
- "#{RbConfig::CONFIG['datadir'].gsub(/\/local/, "")}/locale/%{lang}/LC_MESSAGES/%{name}.mo",
25
- "#{CONFIG_PREFIX}/share/locale/%{lang}/LC_MESSAGES/%{name}.mo",
26
- "#{CONFIG_PREFIX}/local/share/locale/%{lang}/LC_MESSAGES/%{name}.mo"
27
- ].uniq
20
+ default_rules_candidates = [
21
+ "./locale/%{lang}/LC_MESSAGES/%{name}.mo",
22
+ "./locale/%{lang}/%{name}.mo",
23
+ ]
24
+ data_dir = RbConfig::CONFIG["datadir"]
25
+ if data_dir
26
+ default_rules_candidates << "#{data_dir}/locale/%{lang}/LC_MESSAGES/%{name}.mo"
27
+ default_rules_candidates << "#{data_dir.gsub(/\/local/, "")}/locale/%{lang}/LC_MESSAGES/%{name}.mo"
28
+ end
29
+ default_rules_candidates << "#{CONFIG_PREFIX}/share/locale/%{lang}/LC_MESSAGES/%{name}.mo"
30
+ default_rules_candidates << "#{CONFIG_PREFIX}/local/share/locale/%{lang}/LC_MESSAGES/%{name}.mo"
31
+ DEFAULT_RULES = default_rules_candidates.uniq
28
32
 
29
33
  class << self
30
34
  # Add default locale path. Usually you should use GetText.add_default_locale_path instead.
data/lib/gettext/mo.rb CHANGED
@@ -278,11 +278,13 @@ module GetText
278
278
 
279
279
  def load_from_file(filename)
280
280
  @filename = filename
281
- begin
282
- File.open(filename, 'rb'){|f| load_from_stream(f)}
283
- rescue => e
284
- e.set_backtrace("File: #{@filename}")
285
- raise e
281
+ File.open(filename, 'rb') do |f|
282
+ begin
283
+ load_from_stream(f)
284
+ rescue => e
285
+ e.set_backtrace(["#{filename}:#{f.lineno}"] + e.backtrace)
286
+ raise e
287
+ end
286
288
  end
287
289
  end
288
290
 
@@ -1,7 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  #
3
3
  # Copyright (C) 2012 Haruka Yoshihara <yoshihara@clear-code.com>
4
- # Copyright (C) 2012-2014 Kouhei Sutou <kou@clear-code.com>
4
+ # Copyright (C) 2012-2021 Sutou Kouhei <kou@clear-code.com>
5
5
  #
6
6
  # License: Ruby's or LGPL
7
7
  #
@@ -19,11 +19,14 @@
19
19
  # along with this program. If not, see <http://www.gnu.org/licenses/>.
20
20
 
21
21
  require "etc"
22
+ require "optparse"
23
+
24
+ require "datasets"
25
+ require "locale/info"
26
+
22
27
  require "gettext"
23
28
  require "gettext/po_parser"
24
29
  require "gettext/tools/msgmerge"
25
- require "locale/info"
26
- require "optparse"
27
30
 
28
31
  module GetText
29
32
  module Tools
@@ -320,53 +323,8 @@ module GetText
320
323
  end
321
324
 
322
325
  def plural_forms(language)
323
- case language
324
- when "ja", "vi", "ko", /\Azh.*\z/
325
- nplural = "1"
326
- plural_expression = "0"
327
- when "en", "de", "nl", "sv", "da", "no", "fo", "es", "pt",
328
- "it", "bg", "el", "fi", "et", "he", "eo", "hu", "tr",
329
- "ca", "nb"
330
- nplural = "2"
331
- plural_expression = "n != 1"
332
- when "pt_BR", "fr"
333
- nplural = "2"
334
- plural_expression = "n>1"
335
- when "lv"
336
- nplural = "3"
337
- plural_expression = "n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2"
338
- when "ga"
339
- nplural = "3"
340
- plural_expression = "n==1 ? 0 : n==2 ? 1 : 2"
341
- when "ro"
342
- nplural = "3"
343
- plural_expression = "n==1 ? 0 : " +
344
- "(n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2"
345
- when "lt", "bs"
346
- nplural = "3"
347
- plural_expression = "n%10==1 && n%100!=11 ? 0 : " +
348
- "n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2"
349
- when "ru", "uk", "sr", "hr"
350
- nplural = "3"
351
- plural_expression = "n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +
352
- "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2"
353
- when "cs", "sk"
354
- nplural = "3"
355
- plural_expression = "(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2"
356
- when "pl"
357
- nplural = "3"
358
- plural_expression = "n==1 ? 0 : n%10>=2 && " +
359
- "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2"
360
- when "sl"
361
- nplural = "4"
362
- plural_expression = "n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 " +
363
- "|| n%100==4 ? 2 : 3"
364
- else
365
- nplural = nil
366
- plural_expression = nil
367
- end
368
-
369
- "nplurals=#{nplural}; plural=#{plural_expression};"
326
+ converter = CLDRPluralsConverter.new(language)
327
+ converter.convert
370
328
  end
371
329
 
372
330
  DESCRIPTION_TITLE = /^SOME DESCRIPTIVE TITLE\.$/
@@ -408,6 +366,214 @@ module GetText
408
366
  def year
409
367
  now.year
410
368
  end
369
+
370
+ class CLDRPluralsConverter
371
+ def initialize(language)
372
+ @language = language
373
+
374
+ end
375
+
376
+ def convert
377
+ n_plurals = nil
378
+ expression = nil
379
+ plurals = Datasets::CLDRPlurals.new
380
+ plurals.each do |locale|
381
+ next unless locale.name == @language
382
+ n_plurals, expression = convert_plural_rules(locale.rules)
383
+ break
384
+ end
385
+ "nplurals=#{n_plurals}; plural=#{expression};"
386
+ end
387
+
388
+ private
389
+ def convert_plural_rules(rules)
390
+ n_plurals = 1
391
+ conditions = []
392
+ order = [
393
+ "one",
394
+ "zero",
395
+ "two",
396
+ "few",
397
+ "many",
398
+ "other",
399
+ ]
400
+ rules = rules.reject do |rule|
401
+ rule.integer_samples.nil?
402
+ end
403
+ rules = rules.sort_by do |rule|
404
+ order.index(rule.count)
405
+ end
406
+ rules[0..-2].each do |rule|
407
+ next if rule.condition.nil?
408
+ condition = convert_plural_condition(rule.condition)
409
+ next if condition.nil?
410
+ next if condition == false
411
+ n_plurals += 1
412
+ conditions << condition
413
+ end
414
+ expression = ""
415
+ case conditions.size
416
+ when 0
417
+ expression << "0"
418
+ when 1
419
+ condition = conditions[0]
420
+ case condition
421
+ when "(n == 1)"
422
+ expression << "n != 1"
423
+ when "(n <= 1)"
424
+ expression << "n > 1"
425
+ else
426
+ expression << "#{condition} ? 1 : 0"
427
+ end
428
+ else
429
+ (conditions.size + 1).times do |i|
430
+ if i == conditions.size
431
+ expression << i.to_s
432
+ else
433
+ condition = conditions[i]
434
+ expression << "#{condition} ? #{i} : "
435
+ end
436
+ end
437
+ end
438
+ [n_plurals, expression]
439
+ end
440
+
441
+ def convert_plural_condition(condition)
442
+ case condition[0]
443
+ when :and
444
+ gettext_condition = nil
445
+ condition[1..-1].each do |sub_condition|
446
+ sub_gettext_condition = convert_plural_condition(sub_condition)
447
+ case sub_gettext_condition
448
+ when String
449
+ if gettext_condition.is_a?(String)
450
+ gettext_condition << " && #{sub_gettext_condition}"
451
+ else
452
+ gettext_condition = sub_gettext_condition
453
+ end
454
+ when TrueClass
455
+ unless gettext_condition.is_a?(String)
456
+ gettext_condition = true
457
+ end
458
+ when FalseClass
459
+ return false
460
+ else
461
+ raise "unknown value #{sub_gettext_condition.inspect}"
462
+ end
463
+ end
464
+ gettext_condition
465
+ when :or
466
+ gettext_condition = false
467
+ condition[1..-1].each do |sub_condition|
468
+ sub_gettext_condition = convert_plural_condition(sub_condition)
469
+ case sub_gettext_condition
470
+ when String
471
+ if gettext_condition.is_a?(String)
472
+ gettext_condition << " || #{sub_gettext_condition}"
473
+ else
474
+ gettext_condition = sub_gettext_condition
475
+ end
476
+ when TrueClass
477
+ return true
478
+ when FalseClass
479
+ else
480
+ raise "unknown value #{sub_gettext_condition.inspect}"
481
+ end
482
+ end
483
+ gettext_condition
484
+ when :equal
485
+ left = convert_plural_condition(condition[1])
486
+ right = condition[2]
487
+ case left
488
+ when String
489
+ right = compact_equal_values(right)
490
+ gettext_conditions = right.collect do |right_value|
491
+ case right_value
492
+ when Range
493
+ if right_value.begin.zero?
494
+ "(#{left} <= #{right_value.end})"
495
+ else
496
+ "(#{left} >= #{right_value.begin} && " +
497
+ "#{left} <= #{right_value.end})"
498
+ end
499
+ else
500
+ "(#{left} == #{right_value})"
501
+ end
502
+ end
503
+ if gettext_conditions.size == 1
504
+ gettext_conditions[0]
505
+ else
506
+ gettext_conditions.join(" || ")
507
+ end
508
+ when 0
509
+ if right.include?(0)
510
+ true
511
+ else
512
+ false
513
+ end
514
+ else
515
+ false
516
+ end
517
+ when :not_equal
518
+ left = convert_plural_condition(condition[1])
519
+ right = condition[2]
520
+ case left
521
+ when String
522
+ right = compact_equal_values(right)
523
+ gettext_conditions = right.collect do |right_value|
524
+ case right_value
525
+ when Range
526
+ "(#{left} < #{right_value.begin} || " +
527
+ "#{left} > #{right_value.end})"
528
+ else
529
+ "(#{left} != #{right_value})"
530
+ end
531
+ end
532
+ if gettext_conditions.size == 1
533
+ gettext_conditions[0]
534
+ else
535
+ gettext_conditions = gettext_conditions.collect do |gettext_condition|
536
+ "(#{gettext_condition})"
537
+ end
538
+ gettext_conditions.join(" && ")
539
+ end
540
+ when 0
541
+ if right.include?(0)
542
+ false
543
+ else
544
+ true
545
+ end
546
+ else
547
+ false
548
+ end
549
+ when :mod
550
+ left = convert_plural_condition(condition[1])
551
+ right = condition[2]
552
+ case left
553
+ when "n"
554
+ "(n % #{right})"
555
+ else
556
+ false
557
+ end
558
+ when "n", "i"
559
+ "n"
560
+ when "v", "w"
561
+ 0
562
+ when "f", "t", "c", "e"
563
+ false
564
+ else
565
+ raise "unknown operator: #{condition[0].inspect}"
566
+ end
567
+ end
568
+
569
+ def compact_equal_values(values)
570
+ if values == [0, 1]
571
+ [0..1]
572
+ else
573
+ values
574
+ end
575
+ end
576
+ end
411
577
  end
412
578
  end
413
579
  end