vagrant-unbundled 2.2.18.0 → 2.2.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (176) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +15 -0
  3. data/Gemfile.lock +6 -6
  4. data/contrib/zsh/generate_zsh_completion.rb +2 -2
  5. data/lib/vagrant/errors.rb +8 -0
  6. data/plugins/commands/upload/command.rb +1 -1
  7. data/plugins/guests/atomic/guest.rb +1 -1
  8. data/plugins/guests/coreos/cap/configure_networks.rb +65 -0
  9. data/plugins/guests/darwin/cap/mount_smb_shared_folder.rb +6 -3
  10. data/plugins/guests/suse/cap/halt.rb +5 -1
  11. data/plugins/guests/windows/cap/rsync.rb +5 -1
  12. data/plugins/hosts/darwin/cap/path.rb +4 -0
  13. data/plugins/hosts/darwin/cap/version.rb +23 -0
  14. data/plugins/hosts/darwin/plugin.rb +5 -0
  15. data/plugins/hosts/windows/cap/ssh.rb +1 -1
  16. data/plugins/providers/virtualbox/action/network.rb +39 -2
  17. data/plugins/provisioners/chef/cap/freebsd/chef_installed.rb +5 -3
  18. data/plugins/provisioners/chef/cap/linux/chef_installed.rb +5 -3
  19. data/plugins/provisioners/chef/cap/omnios/chef_installed.rb +7 -5
  20. data/plugins/provisioners/chef/cap/windows/chef_installed.rb +3 -2
  21. data/templates/locales/en.yml +25 -0
  22. data/vagrant.gemspec +1 -1
  23. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/CONTRIBUTING.md +23 -0
  24. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/CONTRIBUTORS.md +140 -0
  25. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/LICENSE.md +20 -0
  26. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/README.md +492 -0
  27. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/data/cacert.pem +3232 -0
  28. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/excon.gemspec +45 -0
  29. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/connection.rb +599 -0
  30. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/constants.rb +172 -0
  31. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/error.rb +229 -0
  32. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/extensions/uri.rb +34 -0
  33. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/headers.rb +85 -0
  34. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/instrumentors/logging_instrumentor.rb +48 -0
  35. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/instrumentors/standard_instrumentor.rb +21 -0
  36. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/base.rb +31 -0
  37. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/capture_cookies.rb +32 -0
  38. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/decompress.rb +44 -0
  39. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/escape_path.rb +12 -0
  40. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/expects.rb +25 -0
  41. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/idempotent.rb +57 -0
  42. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/instrumentor.rb +49 -0
  43. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/mock.rb +61 -0
  44. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/redirect_follower.rb +87 -0
  45. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/middlewares/response_parser.rb +16 -0
  46. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/pretty_printer.rb +39 -0
  47. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/response.rb +234 -0
  48. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/socket.rb +297 -0
  49. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/ssl_socket.rb +194 -0
  50. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/test/plugin/server/exec.rb +26 -0
  51. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/test/plugin/server/puma.rb +23 -0
  52. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/test/plugin/server/unicorn.rb +40 -0
  53. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/test/plugin/server/webrick.rb +26 -0
  54. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/test/server.rb +106 -0
  55. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/unix_socket.rb +42 -0
  56. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/utils.rb +143 -0
  57. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon/version.rb +4 -0
  58. data/vendor/bundle/ruby/3.0.0/gems/excon-0.89.0/lib/excon.rb +255 -0
  59. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/MIT-LICENSE +20 -0
  60. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/README.md +122 -0
  61. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/base.rb +289 -0
  62. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/cache.rb +113 -0
  63. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/cache_file.rb +36 -0
  64. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/cascade.rb +56 -0
  65. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/chain.rb +130 -0
  66. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/fallbacks.rb +97 -0
  67. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/flatten.rb +118 -0
  68. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/gettext.rb +85 -0
  69. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/interpolation_compiler.rb +123 -0
  70. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/key_value.rb +206 -0
  71. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/memoize.rb +54 -0
  72. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/metadata.rb +71 -0
  73. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/pluralization.rb +55 -0
  74. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/simple.rb +108 -0
  75. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend/transliterator.rb +108 -0
  76. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/backend.rb +21 -0
  77. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/config.rb +165 -0
  78. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/core_ext/hash.rb +59 -0
  79. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/exceptions.rb +111 -0
  80. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/gettext/helpers.rb +75 -0
  81. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/gettext/po_parser.rb +329 -0
  82. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/gettext.rb +28 -0
  83. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/interpolate/ruby.rb +39 -0
  84. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/locale/fallbacks.rb +99 -0
  85. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/locale/tag/parents.rb +24 -0
  86. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/locale/tag/rfc4646.rb +74 -0
  87. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/locale/tag/simple.rb +39 -0
  88. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/locale/tag.rb +28 -0
  89. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/locale.rb +8 -0
  90. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/middleware.rb +17 -0
  91. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/basics.rb +60 -0
  92. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/defaults.rb +52 -0
  93. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/interpolation.rb +163 -0
  94. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/link.rb +66 -0
  95. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/localization/date.rb +117 -0
  96. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/localization/date_time.rb +103 -0
  97. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/localization/procs.rb +117 -0
  98. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/localization/time.rb +103 -0
  99. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/localization.rb +19 -0
  100. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/lookup.rb +81 -0
  101. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/pluralization.rb +35 -0
  102. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests/procs.rb +60 -0
  103. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/tests.rb +14 -0
  104. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n/version.rb +5 -0
  105. data/vendor/bundle/ruby/3.0.0/gems/i18n-1.8.11/lib/i18n.rb +415 -0
  106. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/Code-of-Conduct.md +73 -0
  107. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/Contributing.md +132 -0
  108. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/History.md +269 -0
  109. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/Licence.md +25 -0
  110. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/Manifest.txt +31 -0
  111. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/README.rdoc +194 -0
  112. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/Rakefile +270 -0
  113. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/type/columnar.rb +57 -0
  114. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/type.rb +634 -0
  115. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/_columnar.rb +137 -0
  116. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/cache.rb +58 -0
  117. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/columnar.rb +3 -0
  118. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/container.rb +96 -0
  119. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/deprecations.rb +36 -0
  120. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/full.rb +19 -0
  121. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/loader.rb +159 -0
  122. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/logger.rb +37 -0
  123. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types/registry.rb +90 -0
  124. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime/types.rb +233 -0
  125. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/lib/mime-types.rb +3 -0
  126. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/bad-fixtures/malformed +9 -0
  127. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/fixture/json.json +1 -0
  128. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/fixture/old-data +9 -0
  129. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/fixture/yaml.yaml +55 -0
  130. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/minitest_helper.rb +11 -0
  131. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/test_mime_type.rb +621 -0
  132. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/test_mime_types.rb +169 -0
  133. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/test_mime_types_cache.rb +118 -0
  134. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/test_mime_types_class.rb +159 -0
  135. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/test_mime_types_lazy.rb +49 -0
  136. data/vendor/bundle/ruby/3.0.0/gems/mime-types-3.4.1/test/test_mime_types_loader.rb +32 -0
  137. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/Code-of-Conduct.md +75 -0
  138. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/Contributing.md +241 -0
  139. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/History.md +494 -0
  140. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/Licence.md +24 -0
  141. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/Manifest.txt +34 -0
  142. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/README.md +73 -0
  143. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/Rakefile +155 -0
  144. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/content_type_mime.db +878 -0
  145. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/ext_mime.db +1198 -0
  146. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime-types.json +1 -0
  147. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.content_type.column +2376 -0
  148. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.docs.column +2376 -0
  149. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.encoding.column +2376 -0
  150. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.flags.column +2376 -0
  151. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.friendly.column +2376 -0
  152. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.pext.column +2376 -0
  153. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.use_instead.column +2376 -0
  154. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/data/mime.xrefs.column +2376 -0
  155. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/lib/mime/types/data.rb +21 -0
  156. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/lib/mime-types-data.rb +3 -0
  157. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/application.yaml +17254 -0
  158. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/audio.yaml +1716 -0
  159. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/chemical.yaml +71 -0
  160. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/conference.yaml +9 -0
  161. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/drawing.yaml +15 -0
  162. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/font.yaml +65 -0
  163. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/image.yaml +1251 -0
  164. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/message.yaml +200 -0
  165. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/model.yaml +390 -0
  166. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/multipart.yaml +179 -0
  167. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/provisional-standard-types.yaml +129 -0
  168. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/text.yaml +1166 -0
  169. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/video.yaml +1121 -0
  170. data/vendor/bundle/ruby/3.0.0/gems/mime-types-data-3.2021.1115/types/world.yaml +8 -0
  171. data/vendor/bundle/ruby/3.0.0/specifications/excon-0.89.0.gemspec +58 -0
  172. data/vendor/bundle/ruby/3.0.0/specifications/i18n-1.8.11.gemspec +32 -0
  173. data/vendor/bundle/ruby/3.0.0/specifications/mime-types-3.4.1.gemspec +63 -0
  174. data/vendor/bundle/ruby/3.0.0/specifications/mime-types-data-3.2021.1115.gemspec +54 -0
  175. data/version.txt +1 -1
  176. metadata +157 -4
@@ -0,0 +1,289 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+ require 'json'
5
+ require 'i18n/core_ext/hash'
6
+
7
+ module I18n
8
+ module Backend
9
+ module Base
10
+ using I18n::HashRefinements
11
+ include I18n::Backend::Transliterator
12
+
13
+ # Accepts a list of paths to translation files. Loads translations from
14
+ # plain Ruby (*.rb), YAML files (*.yml), or JSON files (*.json). See #load_rb, #load_yml, and #load_json
15
+ # for details.
16
+ def load_translations(*filenames)
17
+ filenames = I18n.load_path if filenames.empty?
18
+ filenames.flatten.each { |filename| load_file(filename) }
19
+ end
20
+
21
+ # This method receives a locale, a data hash and options for storing translations.
22
+ # Should be implemented
23
+ def store_translations(locale, data, options = EMPTY_HASH)
24
+ raise NotImplementedError
25
+ end
26
+
27
+ def translate(locale, key, options = EMPTY_HASH)
28
+ raise I18n::ArgumentError if (key.is_a?(String) || key.is_a?(Symbol)) && key.empty?
29
+ raise InvalidLocale.new(locale) unless locale
30
+ return nil if key.nil? && !options.key?(:default)
31
+
32
+ entry = lookup(locale, key, options[:scope], options) unless key.nil?
33
+
34
+ if entry.nil? && options.key?(:default)
35
+ entry = default(locale, key, options[:default], options)
36
+ else
37
+ entry = resolve(locale, key, entry, options)
38
+ end
39
+
40
+ count = options[:count]
41
+
42
+ if entry.nil? && (subtrees? || !count)
43
+ if (options.key?(:default) && !options[:default].nil?) || !options.key?(:default)
44
+ throw(:exception, I18n::MissingTranslation.new(locale, key, options))
45
+ end
46
+ end
47
+
48
+ entry = entry.dup if entry.is_a?(String)
49
+ entry = pluralize(locale, entry, count) if count
50
+
51
+ if entry.nil? && !subtrees?
52
+ throw(:exception, I18n::MissingTranslation.new(locale, key, options))
53
+ end
54
+
55
+ deep_interpolation = options[:deep_interpolation]
56
+ values = options.except(*RESERVED_KEYS)
57
+ if values
58
+ entry = if deep_interpolation
59
+ deep_interpolate(locale, entry, values)
60
+ else
61
+ interpolate(locale, entry, values)
62
+ end
63
+ end
64
+ entry
65
+ end
66
+
67
+ def exists?(locale, key, options = EMPTY_HASH)
68
+ lookup(locale, key) != nil
69
+ end
70
+
71
+ # Acts the same as +strftime+, but uses a localized version of the
72
+ # format string. Takes a key from the date/time formats translations as
73
+ # a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
74
+ def localize(locale, object, format = :default, options = EMPTY_HASH)
75
+ if object.nil? && options.include?(:default)
76
+ return options[:default]
77
+ end
78
+ raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
79
+
80
+ if Symbol === format
81
+ key = format
82
+ type = object.respond_to?(:sec) ? 'time' : 'date'
83
+ options = options.merge(:raise => true, :object => object, :locale => locale)
84
+ format = I18n.t(:"#{type}.formats.#{key}", **options)
85
+ end
86
+
87
+ format = translate_localization_format(locale, object, format, options)
88
+ object.strftime(format)
89
+ end
90
+
91
+ # Returns an array of locales for which translations are available
92
+ # ignoring the reserved translation meta data key :i18n.
93
+ def available_locales
94
+ raise NotImplementedError
95
+ end
96
+
97
+ def reload!
98
+ eager_load! if eager_loaded?
99
+ end
100
+
101
+ def eager_load!
102
+ @eager_loaded = true
103
+ end
104
+
105
+ protected
106
+
107
+ def eager_loaded?
108
+ @eager_loaded ||= false
109
+ end
110
+
111
+ # The method which actually looks up for the translation in the store.
112
+ def lookup(locale, key, scope = [], options = EMPTY_HASH)
113
+ raise NotImplementedError
114
+ end
115
+
116
+ def subtrees?
117
+ true
118
+ end
119
+
120
+ # Evaluates defaults.
121
+ # If given subject is an Array, it walks the array and returns the
122
+ # first translation that can be resolved. Otherwise it tries to resolve
123
+ # the translation directly.
124
+ def default(locale, object, subject, options = EMPTY_HASH)
125
+ options = options.reject { |key, value| key == :default }
126
+ case subject
127
+ when Array
128
+ subject.each do |item|
129
+ result = resolve(locale, object, item, options)
130
+ return result unless result.nil?
131
+ end and nil
132
+ else
133
+ resolve(locale, object, subject, options)
134
+ end
135
+ end
136
+
137
+ # Resolves a translation.
138
+ # If the given subject is a Symbol, it will be translated with the
139
+ # given options. If it is a Proc then it will be evaluated. All other
140
+ # subjects will be returned directly.
141
+ def resolve(locale, object, subject, options = EMPTY_HASH)
142
+ return subject if options[:resolve] == false
143
+ result = catch(:exception) do
144
+ case subject
145
+ when Symbol
146
+ I18n.translate(subject, **options.merge(:locale => locale, :throw => true))
147
+ when Proc
148
+ date_or_time = options.delete(:object) || object
149
+ resolve(locale, object, subject.call(date_or_time, **options))
150
+ else
151
+ subject
152
+ end
153
+ end
154
+ result unless result.is_a?(MissingTranslation)
155
+ end
156
+
157
+ # Picks a translation from a pluralized mnemonic subkey according to English
158
+ # pluralization rules :
159
+ # - It will pick the :one subkey if count is equal to 1.
160
+ # - It will pick the :other subkey otherwise.
161
+ # - It will pick the :zero subkey in the special case where count is
162
+ # equal to 0 and there is a :zero subkey present. This behaviour is
163
+ # not standard with regards to the CLDR pluralization rules.
164
+ # Other backends can implement more flexible or complex pluralization rules.
165
+ def pluralize(locale, entry, count)
166
+ entry = entry.reject { |k, _v| k == :attributes } if entry.is_a?(Hash)
167
+ return entry unless entry.is_a?(Hash) && count && entry.values.none? { |v| v.is_a?(Hash) }
168
+
169
+ key = pluralization_key(entry, count)
170
+ raise InvalidPluralizationData.new(entry, count, key) unless entry.has_key?(key)
171
+ entry[key]
172
+ end
173
+
174
+ # Interpolates values into a given subject.
175
+ #
176
+ # if the given subject is a string then:
177
+ # method interpolates "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X'
178
+ # # => "file test.txt opened by %{user}"
179
+ #
180
+ # if the given subject is an array then:
181
+ # each element of the array is recursively interpolated (until it finds a string)
182
+ # method interpolates ["yes, %{user}", ["maybe no, %{user}, "no, %{user}"]], :user => "bartuz"
183
+ # # => "["yes, bartuz",["maybe no, bartuz", "no, bartuz"]]"
184
+ def interpolate(locale, subject, values = EMPTY_HASH)
185
+ return subject if values.empty?
186
+
187
+ case subject
188
+ when ::String then I18n.interpolate(subject, values)
189
+ when ::Array then subject.map { |element| interpolate(locale, element, values) }
190
+ else
191
+ subject
192
+ end
193
+ end
194
+
195
+ # Deep interpolation
196
+ #
197
+ # deep_interpolate { people: { ann: "Ann is %{ann}", john: "John is %{john}" } },
198
+ # ann: 'good', john: 'big'
199
+ # #=> { people: { ann: "Ann is good", john: "John is big" } }
200
+ def deep_interpolate(locale, data, values = EMPTY_HASH)
201
+ return data if values.empty?
202
+
203
+ case data
204
+ when ::String
205
+ I18n.interpolate(data, values)
206
+ when ::Hash
207
+ data.each_with_object({}) do |(k, v), result|
208
+ result[k] = deep_interpolate(locale, v, values)
209
+ end
210
+ when ::Array
211
+ data.map do |v|
212
+ deep_interpolate(locale, v, values)
213
+ end
214
+ else
215
+ data
216
+ end
217
+ end
218
+
219
+ # Loads a single translations file by delegating to #load_rb or
220
+ # #load_yml depending on the file extension and directly merges the
221
+ # data to the existing translations. Raises I18n::UnknownFileType
222
+ # for all other file extensions.
223
+ def load_file(filename)
224
+ type = File.extname(filename).tr('.', '').downcase
225
+ raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true)
226
+ data = send(:"load_#{type}", filename)
227
+ unless data.is_a?(Hash)
228
+ raise InvalidLocaleData.new(filename, 'expects it to return a hash, but does not')
229
+ end
230
+ data.each { |locale, d| store_translations(locale, d || {}) }
231
+ end
232
+
233
+ # Loads a plain Ruby translations file. eval'ing the file must yield
234
+ # a Hash containing translation data with locales as toplevel keys.
235
+ def load_rb(filename)
236
+ eval(IO.read(filename), binding, filename)
237
+ end
238
+
239
+ # Loads a YAML translations file. The data must have locales as
240
+ # toplevel keys.
241
+ def load_yml(filename)
242
+ begin
243
+ if YAML.respond_to?(:unsafe_load_file) # Psych 4.0 way
244
+ YAML.unsafe_load_file(filename)
245
+ else
246
+ YAML.load_file(filename)
247
+ end
248
+ rescue TypeError, ScriptError, StandardError => e
249
+ raise InvalidLocaleData.new(filename, e.inspect)
250
+ end
251
+ end
252
+ alias_method :load_yaml, :load_yml
253
+
254
+ # Loads a JSON translations file. The data must have locales as
255
+ # toplevel keys.
256
+ def load_json(filename)
257
+ begin
258
+ ::JSON.parse(File.read(filename))
259
+ rescue TypeError, StandardError => e
260
+ raise InvalidLocaleData.new(filename, e.inspect)
261
+ end
262
+ end
263
+
264
+ def translate_localization_format(locale, object, format, options)
265
+ format.to_s.gsub(/%(|\^)[aAbBpP]/) do |match|
266
+ case match
267
+ when '%a' then I18n.t!(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday]
268
+ when '%^a' then I18n.t!(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday].upcase
269
+ when '%A' then I18n.t!(:"date.day_names", :locale => locale, :format => format)[object.wday]
270
+ when '%^A' then I18n.t!(:"date.day_names", :locale => locale, :format => format)[object.wday].upcase
271
+ when '%b' then I18n.t!(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon]
272
+ when '%^b' then I18n.t!(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon].upcase
273
+ when '%B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon]
274
+ when '%^B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon].upcase
275
+ when '%p' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour
276
+ when '%P' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour
277
+ end
278
+ end
279
+ rescue MissingTranslationData => e
280
+ e.message
281
+ end
282
+
283
+ def pluralization_key(entry, count)
284
+ key = :zero if count == 0 && entry.has_key?(:zero)
285
+ key ||= count == 1 ? :one : :other
286
+ end
287
+ end
288
+ end
289
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This module allows you to easily cache all responses from the backend - thus
4
+ # speeding up the I18n aspects of your application quite a bit.
5
+ #
6
+ # To enable caching you can simply include the Cache module to the Simple
7
+ # backend - or whatever other backend you are using:
8
+ #
9
+ # I18n::Backend::Simple.send(:include, I18n::Backend::Cache)
10
+ #
11
+ # You will also need to set a cache store implementation that you want to use:
12
+ #
13
+ # I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store)
14
+ #
15
+ # You can use any cache implementation you want that provides the same API as
16
+ # ActiveSupport::Cache (only the methods #fetch and #write are being used).
17
+ #
18
+ # The cache_key implementation by default assumes you pass values that return
19
+ # a valid key from #hash (see
20
+ # https://www.ruby-doc.org/core/classes/Object.html#M000337). However, you can
21
+ # configure your own digest method via which responds to #hexdigest (see
22
+ # https://ruby-doc.org/stdlib/libdoc/openssl/rdoc/OpenSSL/Digest.html):
23
+ #
24
+ # I18n.cache_key_digest = OpenSSL::Digest::SHA256.new
25
+ #
26
+ # If you use a lambda as a default value in your translation like this:
27
+ #
28
+ # I18n.t(:"date.order", :default => lambda {[:month, :day, :year]})
29
+ #
30
+ # Then you will always have a cache miss, because each time this method
31
+ # is called the lambda will have a different hash value. If you know
32
+ # the result of the lambda is a constant as in the example above, then
33
+ # to cache this you can make the lambda a constant, like this:
34
+ #
35
+ # DEFAULT_DATE_ORDER = lambda {[:month, :day, :year]}
36
+ # ...
37
+ # I18n.t(:"date.order", :default => DEFAULT_DATE_ORDER)
38
+ #
39
+ # If the lambda may result in different values for each call then consider
40
+ # also using the Memoize backend.
41
+ #
42
+ module I18n
43
+ class << self
44
+ @@cache_store = nil
45
+ @@cache_namespace = nil
46
+ @@cache_key_digest = nil
47
+
48
+ def cache_store
49
+ @@cache_store
50
+ end
51
+
52
+ def cache_store=(store)
53
+ @@cache_store = store
54
+ end
55
+
56
+ def cache_namespace
57
+ @@cache_namespace
58
+ end
59
+
60
+ def cache_namespace=(namespace)
61
+ @@cache_namespace = namespace
62
+ end
63
+
64
+ def cache_key_digest
65
+ @@cache_key_digest
66
+ end
67
+
68
+ def cache_key_digest=(key_digest)
69
+ @@cache_key_digest = key_digest
70
+ end
71
+
72
+ def perform_caching?
73
+ !cache_store.nil?
74
+ end
75
+ end
76
+
77
+ module Backend
78
+ # TODO Should the cache be cleared if new translations are stored?
79
+ module Cache
80
+ def translate(locale, key, options = EMPTY_HASH)
81
+ I18n.perform_caching? ? fetch(cache_key(locale, key, options)) { super } : super
82
+ end
83
+
84
+ protected
85
+
86
+ def fetch(cache_key, &block)
87
+ result = _fetch(cache_key, &block)
88
+ throw(:exception, result) if result.is_a?(MissingTranslation)
89
+ result = result.dup if result.frozen? rescue result
90
+ result
91
+ end
92
+
93
+ def _fetch(cache_key, &block)
94
+ result = I18n.cache_store.read(cache_key)
95
+ return result unless result.nil?
96
+ result = catch(:exception, &block)
97
+ I18n.cache_store.write(cache_key, result) unless result.is_a?(Proc)
98
+ result
99
+ end
100
+
101
+ def cache_key(locale, key, options)
102
+ # This assumes that only simple, native Ruby values are passed to I18n.translate.
103
+ "i18n/#{I18n.cache_namespace}/#{locale}/#{digest_item(key)}/#{digest_item(options)}"
104
+ end
105
+
106
+ private
107
+
108
+ def digest_item(key)
109
+ I18n.cache_key_digest ? I18n.cache_key_digest.hexdigest(key.to_s) : key.to_s.hash
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module I18n
6
+ module Backend
7
+ # Overwrites the Base load_file method to cache loaded file contents.
8
+ module CacheFile
9
+ # Optionally provide path_roots array to normalize filename paths,
10
+ # to make the cached i18n data portable across environments.
11
+ attr_accessor :path_roots
12
+
13
+ protected
14
+
15
+ # Track loaded translation files in the `i18n.load_file` scope,
16
+ # and skip loading the file if its contents are still up-to-date.
17
+ def load_file(filename)
18
+ initialized = !respond_to?(:initialized?) || initialized?
19
+ key = I18n::Backend::Flatten.escape_default_separator(normalized_path(filename))
20
+ old_mtime, old_digest = initialized && lookup(:i18n, key, :load_file)
21
+ return if (mtime = File.mtime(filename).to_i) == old_mtime ||
22
+ (digest = OpenSSL::Digest::SHA256.file(filename).hexdigest) == old_digest
23
+ super
24
+ store_translations(:i18n, load_file: { key => [mtime, digest] })
25
+ end
26
+
27
+ # Translate absolute filename to relative path for i18n key.
28
+ def normalized_path(file)
29
+ return file unless path_roots
30
+ path = path_roots.find(&file.method(:start_with?)) ||
31
+ raise(InvalidLocaleData.new(file, 'outside expected path roots'))
32
+ file.sub(path, path_roots.index(path).to_s)
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ # The Cascade module adds the ability to do cascading lookups to backends that
4
+ # are compatible to the Simple backend.
5
+ #
6
+ # By cascading lookups we mean that for any key that can not be found the
7
+ # Cascade module strips one segment off the scope part of the key and then
8
+ # tries to look up the key in that scope.
9
+ #
10
+ # E.g. when a lookup for the key :"foo.bar.baz" does not yield a result then
11
+ # the segment :bar will be stripped off the scope part :"foo.bar" and the new
12
+ # scope :foo will be used to look up the key :baz. If that does not succeed
13
+ # then the remaining scope segment :foo will be omitted, too, and again the
14
+ # key :baz will be looked up (now with no scope).
15
+ #
16
+ # To enable a cascading lookup one passes the :cascade option:
17
+ #
18
+ # I18n.t(:'foo.bar.baz', :cascade => true)
19
+ #
20
+ # This will return the first translation found for :"foo.bar.baz", :"foo.baz"
21
+ # or :baz in this order.
22
+ #
23
+ # The cascading lookup takes precedence over resolving any given defaults.
24
+ # I.e. defaults will kick in after the cascading lookups haven't succeeded.
25
+ #
26
+ # This behavior is useful for libraries like ActiveRecord validations where
27
+ # the library wants to give users a bunch of more or less fine-grained options
28
+ # of scopes for a particular key.
29
+ #
30
+ # Thanks to Clemens Kofler for the initial idea and implementation! See
31
+ # http://github.com/clemens/i18n-cascading-backend
32
+
33
+ module I18n
34
+ module Backend
35
+ module Cascade
36
+ def lookup(locale, key, scope = [], options = EMPTY_HASH)
37
+ return super unless cascade = options[:cascade]
38
+
39
+ cascade = { :step => 1 } unless cascade.is_a?(Hash)
40
+ step = cascade[:step] || 1
41
+ offset = cascade[:offset] || 1
42
+ separator = options[:separator] || I18n.default_separator
43
+ skip_root = cascade.has_key?(:skip_root) ? cascade[:skip_root] : true
44
+
45
+ scope = I18n.normalize_keys(nil, key, scope, separator)
46
+ key = (scope.slice!(-offset, offset) || []).join(separator)
47
+
48
+ begin
49
+ result = super
50
+ return result unless result.nil?
51
+ scope = scope.dup
52
+ end while (!scope.empty? || !skip_root) && scope.slice!(-step, step)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,130 @@
1
+ # frozen_string_literal: true
2
+
3
+ module I18n
4
+ module Backend
5
+ # Backend that chains multiple other backends and checks each of them when
6
+ # a translation needs to be looked up. This is useful when you want to use
7
+ # standard translations with a Simple backend but store custom application
8
+ # translations in a database or other backends.
9
+ #
10
+ # To use the Chain backend instantiate it and set it to the I18n module.
11
+ # You can add chained backends through the initializer or backends
12
+ # accessor:
13
+ #
14
+ # # preserves the existing Simple backend set to I18n.backend
15
+ # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n.backend)
16
+ #
17
+ # The implementation assumes that all backends added to the Chain implement
18
+ # a lookup method with the same API as Simple backend does.
19
+ class Chain
20
+ using I18n::HashRefinements
21
+
22
+ module Implementation
23
+ include Base
24
+
25
+ attr_accessor :backends
26
+
27
+ def initialize(*backends)
28
+ self.backends = backends
29
+ end
30
+
31
+ def initialized?
32
+ backends.all? do |backend|
33
+ backend.instance_eval do
34
+ return false unless initialized?
35
+ end
36
+ end
37
+ true
38
+ end
39
+
40
+ def reload!
41
+ backends.each { |backend| backend.reload! }
42
+ end
43
+
44
+ def eager_load!
45
+ backends.each { |backend| backend.eager_load! }
46
+ end
47
+
48
+ def store_translations(locale, data, options = EMPTY_HASH)
49
+ backends.first.store_translations(locale, data, options)
50
+ end
51
+
52
+ def available_locales
53
+ backends.map { |backend| backend.available_locales }.flatten.uniq
54
+ end
55
+
56
+ def translate(locale, key, default_options = EMPTY_HASH)
57
+ namespace = nil
58
+ options = default_options.except(:default)
59
+
60
+ backends.each do |backend|
61
+ catch(:exception) do
62
+ options = default_options if backend == backends.last
63
+ translation = backend.translate(locale, key, options)
64
+ if namespace_lookup?(translation, options)
65
+ namespace = _deep_merge(translation, namespace || {})
66
+ elsif !translation.nil? || (options.key?(:default) && options[:default].nil?)
67
+ return translation
68
+ end
69
+ end
70
+ end
71
+
72
+ return namespace if namespace
73
+ throw(:exception, I18n::MissingTranslation.new(locale, key, options))
74
+ end
75
+
76
+ def exists?(locale, key, options = EMPTY_HASH)
77
+ backends.any? do |backend|
78
+ backend.exists?(locale, key, options)
79
+ end
80
+ end
81
+
82
+ def localize(locale, object, format = :default, options = EMPTY_HASH)
83
+ backends.each do |backend|
84
+ catch(:exception) do
85
+ result = backend.localize(locale, object, format, options) and return result
86
+ end
87
+ end
88
+ throw(:exception, I18n::MissingTranslation.new(locale, format, options))
89
+ end
90
+
91
+ protected
92
+ def init_translations
93
+ backends.each do |backend|
94
+ backend.send(:init_translations)
95
+ end
96
+ end
97
+
98
+ def translations
99
+ backends.reverse.each_with_object({}) do |backend, memo|
100
+ partial_translations = backend.instance_eval do
101
+ init_translations unless initialized?
102
+ translations
103
+ end
104
+ memo.deep_merge!(partial_translations) { |_, a, b| b || a }
105
+ end
106
+ end
107
+
108
+ def namespace_lookup?(result, options)
109
+ result.is_a?(Hash) && !options.has_key?(:count)
110
+ end
111
+
112
+ private
113
+ # This is approximately what gets used in ActiveSupport.
114
+ # However since we are not guaranteed to run in an ActiveSupport context
115
+ # it is wise to have our own copy. We underscore it
116
+ # to not pollute the namespace of the including class.
117
+ def _deep_merge(hash, other_hash)
118
+ copy = hash.dup
119
+ other_hash.each_pair do |k,v|
120
+ value_from_other = hash[k]
121
+ copy[k] = value_from_other.is_a?(Hash) && v.is_a?(Hash) ? _deep_merge(value_from_other, v) : v
122
+ end
123
+ copy
124
+ end
125
+ end
126
+
127
+ include Implementation
128
+ end
129
+ end
130
+ end