pax_global_header00006660000000000000000000000064141403357030014512gustar00rootroot0000000000000052 comment=cb4a4be9a13ae03b7b6d0678a3ad00dd790ee240 i18n-1.8.11/000077500000000000000000000000001414033570300123615ustar00rootroot00000000000000i18n-1.8.11/.github/000077500000000000000000000000001414033570300137215ustar00rootroot00000000000000i18n-1.8.11/.github/ISSUE_TEMPLATE/000077500000000000000000000000001414033570300161045ustar00rootroot00000000000000i18n-1.8.11/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000006611414033570300206010ustar00rootroot00000000000000--- name: Bug report about: Create a bug report title: "[BUG]" labels: '' assignees: '' --- ## What I tried to do * Fill this out! ## What I expected to happen * Fill this out! ## What actually happened * Fill this out! ## Versions of i18n, rails, and anything else you think is necessary * Fill this out! ---- Bonus points for providing an application or a small code example which reproduces the issue. Thanks! :heart: i18n-1.8.11/.github/workflows/000077500000000000000000000000001414033570300157565ustar00rootroot00000000000000i18n-1.8.11/.github/workflows/ruby.yml000066400000000000000000000051521414033570300174650ustar00rootroot00000000000000name: Ruby on: # Trigger the workflow on push or pull request, # but only for the master branch push: branches: - master pull_request: branches: - master jobs: build: strategy: fail-fast: false matrix: ruby_version: [3.0, 2.7, 2.6, 2.5, 2.4, 2.3, jruby] gemfile: [ Gemfile, gemfiles/Gemfile.rails-5.0.x, gemfiles/Gemfile.rails-5.1.x, gemfiles/Gemfile.rails-5.2.x, gemfiles/Gemfile.rails-6.0.x, gemfiles/Gemfile.rails-6.1.x, gemfiles/Gemfile.rails-main, ] exclude: # Ruby 3.x is not supported by Rails 5.2.x - ruby_version: 3.0 gemfile: gemfiles/Gemfile.rails-5.2.x # Ruby 3.x is not supported by Rails 5.1.x - ruby_version: 3.0 gemfile: gemfiles/Gemfile.rails-5.1.x # Ruby 3.x is not supported by Rails 5.0.x - ruby_version: 3.0 gemfile: gemfiles/Gemfile.rails-5.0.x # Ruby 2.6.x is not supported by Rails main - ruby_version: 2.6 gemfile: gemfiles/Gemfile.rails-main # Ruby 2.5.x is not supported by Rails main - ruby_version: 2.5 gemfile: gemfiles/Gemfile.rails-main # Ruby 2.4.x is not supported by Rails main - ruby_version: 2.4 gemfile: gemfiles/Gemfile.rails-main # Ruby 2.4.x is not supported by Rails 6.1.x - ruby_version: 2.4 gemfile: gemfiles/Gemfile.rails-6.1.x # Ruby 2.4.x is not supported by Rails 6.0.x - ruby_version: 2.4 gemfile: gemfiles/Gemfile.rails-6.0.x # Ruby 2.3.x is not supported by Rails 6.1.x - ruby_version: 2.3 gemfile: gemfiles/Gemfile.rails-6.1.x # Ruby 2.3.x is not supported by Rails main - ruby_version: 2.3 gemfile: gemfiles/Gemfile.rails-main # Ruby 2.3.x is not supported by Rails 6.0.x - ruby_version: 2.3 gemfile: gemfiles/Gemfile.rails-6.0.x # JRuby is not supported by Rails main - ruby_version: jruby gemfile: gemfiles/Gemfile.rails-main runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Set up Ruby uses: eregon/use-ruby-action@master with: ruby-version: ${{ matrix.ruby_version }} - name: Build and test with Rake env: BUNDLE_GEMFILE: ${{ matrix.gemfile }} run: | gem install bundler bundle install --jobs 4 --retry 3 bundle exec rake i18n-1.8.11/.gitignore000066400000000000000000000002251414033570300143500ustar00rootroot00000000000000.DS_Store test/rails/fixtures nbproject/ vendor/**/* *.swp pkg .bundle .rvmrc .ruby-version .ruby-gemset .tool-versions Gemfile.lock gemfiles/*.lock i18n-1.8.11/CHANGELOG.md000066400000000000000000000001601414033570300141670ustar00rootroot00000000000000# Changelog has moved For changes, please see our [Releases page](https://github.com/svenfuchs/i18n/releases). i18n-1.8.11/Gemfile000066400000000000000000000002671414033570300136610ustar00rootroot00000000000000source 'https://rubygems.org' gemspec gem 'mocha', '~> 1.7.0' gem 'test_declarative', '0.0.6' gem 'rake', '~> 13' gem 'minitest', '~> 5.14' gem 'json' gem 'activesupport' gem 'pry' i18n-1.8.11/MIT-LICENSE000066400000000000000000000020451414033570300140160ustar00rootroot00000000000000Copyright (c) 2008 The Ruby I18n team Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.i18n-1.8.11/README.md000066400000000000000000000064371414033570300136520ustar00rootroot00000000000000# Ruby I18n [![Build Status](https://github.com/ruby-i18n/i18n/workflows/Ruby/badge.svg)](https://github.com/ruby-i18n/i18n/actions?query=workflow%3ARuby) Ruby internationalization and localization (i18n) solution. Currently maintained by @radar. ## Usage ### Rails You will most commonly use this library within a Rails app. [See the Rails Guide](https://guides.rubyonrails.org/i18n.html) for an example of its usage. ### Ruby (without Rails) If you want to use this library without Rails, you can simply add `i18n` to your `Gemfile`: ```ruby gem 'i18n' ``` Then configure I18n with some translations, and a default locale: ```ruby I18n.load_path << Dir[File.expand_path("config/locales") + "/*.yml"] I18n.default_locale = :en # (note that `en` is already the default!) ``` A simple translation file in your project might live at `config/locales/en.yml` and look like: ```yml en: test: "This is a test" ``` You can then access this translation by doing: ```ruby I18n.t(:test) ``` You can switch locales in your project by setting `I18n.locale` to a different value: ```ruby I18n.locale = :de I18n.t(:test) # => "Dies ist ein Test" ``` ## Features * Translation and localization * Interpolation of values to translations * Pluralization (CLDR compatible) * Customizable transliteration to ASCII * Flexible defaults * Bulk lookup * Lambdas as translation data * Custom key/scope separator * Custom exception handlers * Extensible architecture with a swappable backend ## Pluggable Features * Cache * Pluralization: lambda pluralizers stored as translation data * Locale fallbacks, RFC4647 compliant (optionally: RFC4646 locale validation) * [Gettext support](https://github.com/ruby-i18n/i18n/wiki/Gettext) * Translation metadata ## Alternative Backend * Chain * ActiveRecord (optionally: ActiveRecord::Missing and ActiveRecord::StoreProcs) * KeyValue (uses active_support/json and cannot store procs) For more information and lots of resources see [the 'Resources' page on the wiki](https://github.com/ruby-i18n/i18n/wiki/Resources). ## Tests You can run tests both with * `rake test` or just `rake` * run any test file directly, e.g. `ruby -Ilib:test test/api/simple_test.rb` You can run all tests against all Gemfiles with * `ruby test/run_all.rb` The structure of the test suite is a bit unusual as it uses modules to reuse particular tests in different test cases. The reason for this is that we need to enforce the I18n API across various combinations of extensions. E.g. the Simple backend alone needs to support the same API as any combination of feature and/or optimization modules included to the Simple backend. We test this by reusing the same API definition (implemented as test methods) in test cases with different setups. You can find the test cases that enforce the API in test/api. And you can find the API definition test methods in test/api/tests. All other test cases (e.g. as defined in test/backend, test/core_ext) etc. follow the usual test setup and should be easy to grok. ## More Documentation Additional documentation can be found here: https://github.com/ruby-i18n/i18n/wiki ## Contributors * @radar * @carlosantoniodasilva * @josevalim * @knapo * @tigrish * [and many more](https://github.com/ruby-i18n/i18n/graphs/contributors) ## License MIT License. See the included MIT-LICENSE file. i18n-1.8.11/Rakefile000066400000000000000000000004231414033570300140250ustar00rootroot00000000000000require 'bundler/gem_tasks' require 'rake/testtask' task :default => [:test] Rake::TestTask.new(:test) do |t| t.libs << 'lib' t.libs << 'test' t.pattern = "test/**/*_test.rb" t.verbose = true t.warning = true end Rake::Task['test'].comment = "Run all i18n tests" i18n-1.8.11/benchmark/000077500000000000000000000000001414033570300143135ustar00rootroot00000000000000i18n-1.8.11/benchmark/example.yml000066400000000000000000000114401414033570300164710ustar00rootroot00000000000000en: first: "First" activemodel: errors: messages: :"activerecord.errors.messages" activerecord: errors: messages: inclusion: "is not included in the list" exclusion: "is reserved" invalid: "is invalid" confirmation: "doesn't match confirmation" accepted: "must be accepted" empty: "can't be empty" blank: "can't be blank" too_long: "is too long (maximum is %{count} characters)" too_short: "is too short (minimum is %{count} characters)" wrong_length: "is the wrong length (should be %{count} characters)" taken: "has already been taken" not_a_number: "is not a number" greater_than: "must be greater than %{count}" greater_than_or_equal_to: "must be greater than or equal to %{count}" equal_to: "must be equal to %{count}" less_than: "must be less than %{count}" less_than_or_equal_to: "must be less than or equal to %{count}" odd: "must be odd" even: "must be even" record_invalid: "Validation failed: %{errors}" models: user: blank: "This is a custom blank message for %{model}: %{attribute}" attributes: login: blank: "This is a custom blank message for User login" models: user: "Dude" attributes: admins: user: login: "Handle" date: formats: # Use the strftime parameters for formats. # When no format has been given, it uses default. # You can provide other formats here if you like! default: "%Y-%m-%d" short: "%b %d" long: "%B %d, %Y" day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] # Don't forget the nil at the beginning; there's no such thing as a 0th month month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] # Used in date_select and datime_select. order: - :year, - :month, - :day time: formats: default: "%a, %d %b %Y %H:%M:%S %z" short: "%d %b %H:%M" long: "%B %d, %Y %H:%M" am: "am" pm: "pm" support: array: words_connector: ", " two_words_connector: " and " last_word_connector: ", and " activemodel: errors: messages: inclusion: "is not included in the list" exclusion: "is reserved" invalid: "is invalid" confirmation: "doesn't match confirmation" accepted: "must be accepted" empty: "can't be empty" blank: "can't be blank" too_long: "is too long (maximum is %{count} characters)" too_short: "is too short (minimum is %{count} characters)" wrong_length: "is the wrong length (should be %{count} characters)" taken: "has already been taken" not_a_number: "is not a number" greater_than: "must be greater than %{count}" greater_than_or_equal_to: "must be greater than or equal to %{count}" equal_to: "must be equal to %{count}" less_than: "must be less than %{count}" less_than_or_equal_to: "must be less than or equal to %{count}" odd: "must be odd" even: "must be even" record_invalid: "Validation failed: %{errors}" models: user: blank: "This is a custom blank message for %{model}: %{attribute}" attributes: login: blank: "This is a custom blank message for User login" models: user: "Dude" attributes: user: login: "Handle" model_data: date: formats: # Use the strftime parameters for formats. # When no format has been given, it uses default. # You can provide other formats here if you like! default: "%Y-%m-%d" short: "%b %d" long: "%B %d, %Y" day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] # Don't forget the nil at the beginning; there's no such thing as a 0th month month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] # Used in date_select and datime_select. order: - :year - :month - :day time: formats: default: "%a, %d %b %Y %H:%M:%S %z" short: "%d %b %H:%M" long: "%B %d, %Y %H:%M" am: "am" pm: "pm" support: array: words_connector: ", " two_words_connector: " and " last_word_connector: ", and " i18n-1.8.11/benchmark/run.rb000066400000000000000000000056551414033570300154570ustar00rootroot00000000000000#!/usr/bin/ruby $:.unshift File.expand_path('../../lib', __FILE__) require 'bundler/setup' require 'i18n' require 'benchmark' require 'yaml' N = (ARGV.shift || 1000).to_i YAML_HASH = YAML.load_file(File.expand_path("example.yml", File.dirname(__FILE__))) module Backends Simple = I18n::Backend::Simple.new Interpolation = Class.new(I18n::Backend::Simple) do include I18n::Backend::InterpolationCompiler end.new begin require 'active_support' KeyValue = I18n::Backend::KeyValue.new({}, true) puts "Running KeyValue with ActiveSupport #{ActiveSupport::VERSION::STRING}" rescue LoadError puts 'Skipping KeyValue since ActiveSupport could not be loaded.' end end ORDER = %w(Simple Interpolation KeyValue) ORDER.map!(&:to_sym) if RUBY_VERSION > '1.9' module Benchmark WIDTH = 20 def self.rt(label = "", n=N, &blk) print label.ljust(WIDTH) time, objects = measure_objects(n, &blk) time = time.respond_to?(:real) ? time.real : time print format("%8.2f ms %8d objects\n", time * 1000, objects) rescue Exception => e print "FAILED: #{e.message}" end if ObjectSpace.respond_to?(:allocated_objects) def self.measure_objects(n, &blk) obj = ObjectSpace.allocated_objects t = Benchmark.realtime { n.times(&blk) } [t, ObjectSpace.allocated_objects - obj] end else def self.measure_objects(n, &blk) [Benchmark.measure { n.times(&blk) }, 0] end end end benchmarker = lambda do |backend_name| I18n.backend = Backends.const_get(backend_name) puts "=> #{backend_name}\n\n" Benchmark.rt "store", 1 do I18n.backend.store_translations(*YAML_HASH.to_a.first) end I18n.backend.translate :en, :first Benchmark.rt "available_locales" do I18n.backend.available_locales end Benchmark.rt "t (depth=3)" do I18n.backend.translate :en, :"activerecord.models.user" end Benchmark.rt "t (depth=5)" do I18n.backend.translate :en, :"activerecord.attributes.admins.user.login" end Benchmark.rt "t (depth=7)" do I18n.backend.translate :en, :"activerecord.errors.models.user.attributes.login.blank" end Benchmark.rt "t w/ default" do I18n.backend.translate :en, :"activerecord.models.another", :default => "Another" end Benchmark.rt "t w/ interpolation" do I18n.backend.translate :en, :"activerecord.errors.models.user.blank", :model => "User", :attribute => "name" end Benchmark.rt "t w/ link" do I18n.backend.translate :en, :"activemodel.errors.messages.blank" end Benchmark.rt "t subtree" do I18n.backend.translate :en, :"activerecord.errors.messages" end puts end # Run! puts puts "Running benchmarks with N = #{N}\n\n" (ORDER & Backends.constants).each(&benchmarker) Backends.constants.each do |backend_name| backend = Backends.const_get(backend_name) backend.reload! backend.extend I18n::Backend::Memoize end puts "Running memoized benchmarks with N = #{N}\n\n" (ORDER & Backends.constants).each(&benchmarker) i18n-1.8.11/gemfiles/000077500000000000000000000000001414033570300141545ustar00rootroot00000000000000i18n-1.8.11/gemfiles/Gemfile.rails-5.0.x000066400000000000000000000003361414033570300173300ustar00rootroot00000000000000source 'https://rubygems.org' gemspec :path => '..' gem 'activesupport', '~> 5.0.0' gem 'mocha', '~> 1.7.0' gem 'test_declarative', '0.0.6' gem 'rake', '~> 13' gem 'minitest', '~> 5.14' platforms :mri do gem 'oj' end i18n-1.8.11/gemfiles/Gemfile.rails-5.1.x000066400000000000000000000003251414033570300173270ustar00rootroot00000000000000source 'https://rubygems.org' gemspec :path => '..' gem 'activesupport', '~> 5.1.0' gem 'mocha', '~> 1.7.0' gem 'test_declarative', '0.0.6' gem 'rake' gem 'minitest', '~> 5.14' platforms :mri do gem 'oj' end i18n-1.8.11/gemfiles/Gemfile.rails-5.2.x000066400000000000000000000003251414033570300173300ustar00rootroot00000000000000source 'https://rubygems.org' gemspec :path => '..' gem 'activesupport', '~> 5.2.0' gem 'mocha', '~> 1.7.0' gem 'test_declarative', '0.0.6' gem 'rake' gem 'minitest', '~> 5.14' platforms :mri do gem 'oj' end i18n-1.8.11/gemfiles/Gemfile.rails-6.0.x000066400000000000000000000003251414033570300173270ustar00rootroot00000000000000source 'https://rubygems.org' gemspec :path => '..' gem 'activesupport', '~> 6.0.0' gem 'mocha', '~> 1.7.0' gem 'test_declarative', '0.0.6' gem 'rake' gem 'minitest', '~> 5.14' platforms :mri do gem 'oj' end i18n-1.8.11/gemfiles/Gemfile.rails-6.1.x000066400000000000000000000003231414033570300173260ustar00rootroot00000000000000source 'https://rubygems.org' gemspec :path => '..' gem 'activesupport', '~> 6.1' gem 'mocha', '~> 1.7.0' gem 'test_declarative', '0.0.6' gem 'rake' gem 'minitest', '~> 5.14' platforms :mri do gem 'oj' end i18n-1.8.11/gemfiles/Gemfile.rails-main000066400000000000000000000003571414033570300175070ustar00rootroot00000000000000source 'https://rubygems.org' gemspec :path => '..' gem 'activesupport', github: 'rails/rails', branch: 'main' gem 'mocha', '~> 1.7.0' gem 'test_declarative', '0.0.6' gem 'rake' gem 'minitest', '~> 5.1' platforms :mri do gem 'oj' end i18n-1.8.11/i18n.gemspec000066400000000000000000000022771414033570300145150ustar00rootroot00000000000000# encoding: utf-8 $: << File.expand_path('../lib', __FILE__) require 'i18n/version' Gem::Specification.new do |s| s.name = "i18n" s.version = I18n::VERSION s.authors = ["Sven Fuchs", "Joshua Harvey", "Matt Aimonetti", "Stephan Soller", "Saimon Moore", "Ryan Bigg"] s.email = "rails-i18n@googlegroups.com" s.homepage = "https://github.com/ruby-i18n/i18n" s.summary = "New wave Internationalization support for Ruby" s.description = "New wave Internationalization support for Ruby." s.license = "MIT" s.metadata = { 'bug_tracker_uri' => 'https://github.com/ruby-i18n/i18n/issues', 'changelog_uri' => 'https://github.com/ruby-i18n/i18n/releases', 'documentation_uri' => 'https://guides.rubyonrails.org/i18n.html', 'source_code_uri' => 'https://github.com/ruby-i18n/i18n', } s.files = Dir.glob("lib/**/*") + %w(README.md MIT-LICENSE) s.platform = Gem::Platform::RUBY s.require_path = 'lib' s.required_rubygems_version = '>= 1.3.5' s.required_ruby_version = '>= 2.3.0' s.add_dependency 'concurrent-ruby', '~> 1.0' end i18n-1.8.11/lib/000077500000000000000000000000001414033570300131275ustar00rootroot00000000000000i18n-1.8.11/lib/i18n.rb000066400000000000000000000345311414033570300142410ustar00rootroot00000000000000# frozen_string_literal: true require 'concurrent/map' require 'concurrent/hash' require 'i18n/version' require 'i18n/exceptions' require 'i18n/interpolate/ruby' module I18n autoload :Backend, 'i18n/backend' autoload :Config, 'i18n/config' autoload :Gettext, 'i18n/gettext' autoload :Locale, 'i18n/locale' autoload :Tests, 'i18n/tests' autoload :Middleware, 'i18n/middleware' RESERVED_KEYS = %i[ cascade deep_interpolation default exception_handler fallback fallback_in_progress format object raise resolve scope separator throw ].freeze RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/ EMPTY_HASH = {}.freeze def self.new_double_nested_cache # :nodoc: Concurrent::Map.new { |h, k| h[k] = Concurrent::Map.new } end module Base # Gets I18n configuration object. def config Thread.current[:i18n_config] ||= I18n::Config.new end # Sets I18n configuration object. def config=(value) Thread.current[:i18n_config] = value end # Write methods which delegates to the configuration object %w(locale backend default_locale available_locales default_separator exception_handler load_path enforce_available_locales).each do |method| module_eval <<-DELEGATORS, __FILE__, __LINE__ + 1 def #{method} config.#{method} end def #{method}=(value) config.#{method} = (value) end DELEGATORS end # Tells the backend to reload translations. Used in situations like the # Rails development environment. Backends can implement whatever strategy # is useful. def reload! config.clear_available_locales_set config.backend.reload! end # Tells the backend to load translations now. Used in situations like the # Rails production environment. Backends can implement whatever strategy # is useful. def eager_load! config.backend.eager_load! end # Translates, pluralizes and interpolates a given key using a given locale, # scope, and default, as well as interpolation values. # # *LOOKUP* # # Translation data is organized as a nested hash using the upper-level keys # as namespaces. E.g., ActionView ships with the translation: # :date => {:formats => {:short => "%b %d"}}. # # Translations can be looked up at any level of this hash using the key argument # and the scope option. E.g., in this example I18n.t :date # returns the whole translations hash {:formats => {:short => "%b %d"}}. # # Key can be either a single key or a dot-separated key (both Strings and Symbols # work). E.g., the short format can be looked up using both: # I18n.t 'date.formats.short' # I18n.t :'date.formats.short' # # Scope can be either a single key, a dot-separated key or an array of keys # or dot-separated keys. Keys and scopes can be combined freely. So these # examples will all look up the same short date format: # I18n.t 'date.formats.short' # I18n.t 'formats.short', :scope => 'date' # I18n.t 'short', :scope => 'date.formats' # I18n.t 'short', :scope => %w(date formats) # # *INTERPOLATION* # # Translations can contain interpolation variables which will be replaced by # values passed to #translate as part of the options hash, with the keys matching # the interpolation variable names. # # E.g., with a translation :foo => "foo %{bar}" the option # value for the key +bar+ will be interpolated into the translation: # I18n.t :foo, :bar => 'baz' # => 'foo baz' # # *PLURALIZATION* # # Translation data can contain pluralized translations. Pluralized translations # are arrays of singular/plural versions of translations like ['Foo', 'Foos']. # # Note that I18n::Backend::Simple only supports an algorithm for English # pluralization rules. Other algorithms can be supported by custom backends. # # This returns the singular version of a pluralized translation: # I18n.t :foo, :count => 1 # => 'Foo' # # These both return the plural version of a pluralized translation: # I18n.t :foo, :count => 0 # => 'Foos' # I18n.t :foo, :count => 2 # => 'Foos' # # The :count option can be used both for pluralization and interpolation. # E.g., with the translation # :foo => ['%{count} foo', '%{count} foos'], count will # be interpolated to the pluralized translation: # I18n.t :foo, :count => 1 # => '1 foo' # # *DEFAULTS* # # This returns the translation for :foo or default if no translation was found: # I18n.t :foo, :default => 'default' # # This returns the translation for :foo or the translation for :bar if no # translation for :foo was found: # I18n.t :foo, :default => :bar # # Returns the translation for :foo or the translation for :bar # or default if no translations for :foo and :bar were found. # I18n.t :foo, :default => [:bar, 'default'] # # *BULK LOOKUP* # # This returns an array with the translations for :foo and :bar. # I18n.t [:foo, :bar] # # Can be used with dot-separated nested keys: # I18n.t [:'baz.foo', :'baz.bar'] # # Which is the same as using a scope option: # I18n.t [:foo, :bar], :scope => :baz # # *LAMBDAS* # # Both translations and defaults can be given as Ruby lambdas. Lambdas will be # called and passed the key and options. # # E.g. assuming the key :salutation resolves to: # lambda { |key, options| options[:gender] == 'm' ? "Mr. #{options[:name]}" : "Mrs. #{options[:name]}" } # # Then I18n.t(:salutation, :gender => 'w', :name => 'Smith') will result in "Mrs. Smith". # # Note that the string returned by lambda will go through string interpolation too, # so the following lambda would give the same result: # lambda { |key, options| options[:gender] == 'm' ? "Mr. %{name}" : "Mrs. %{name}" } # # It is recommended to use/implement lambdas in an "idempotent" way. E.g. when # a cache layer is put in front of I18n.translate it will generate a cache key # from the argument values passed to #translate. Therefore your lambdas should # always return the same translations/values per unique combination of argument # values. # # *Ruby 2.7+ keyword arguments warning* # # This method uses keyword arguments. # There is a breaking change in ruby that produces warning with ruby 2.7 and won't work as expected with ruby 3.0 # The "hash" parameter must be passed as keyword argument. # # Good: # I18n.t(:salutation, :gender => 'w', :name => 'Smith') # I18n.t(:salutation, **{ :gender => 'w', :name => 'Smith' }) # I18n.t(:salutation, **any_hash) # # Bad: # I18n.t(:salutation, { :gender => 'w', :name => 'Smith' }) # I18n.t(:salutation, any_hash) # def translate(key = nil, throw: false, raise: false, locale: nil, **options) # TODO deprecate :raise locale ||= config.locale raise Disabled.new('t') if locale == false enforce_available_locales!(locale) backend = config.backend result = catch(:exception) do if key.is_a?(Array) key.map { |k| backend.translate(locale, k, options) } else backend.translate(locale, key, options) end end if result.is_a?(MissingTranslation) handle_exception((throw && :throw || raise && :raise), result, locale, key, options) else result end end alias :t :translate # Wrapper for translate that adds :raise => true. With # this option, if no translation is found, it will raise I18n::MissingTranslationData def translate!(key, **options) translate(key, **options, raise: true) end alias :t! :translate! # Returns true if a translation exists for a given key, otherwise returns false. def exists?(key, _locale = nil, locale: _locale, **options) locale ||= config.locale raise Disabled.new('exists?') if locale == false raise I18n::ArgumentError if key.is_a?(String) && key.empty? config.backend.exists?(locale, key, options) end # Transliterates UTF-8 characters to ASCII. By default this method will # transliterate only Latin strings to an ASCII approximation: # # I18n.transliterate("Ærøskøbing") # # => "AEroskobing" # # I18n.transliterate("日本語") # # => "???" # # It's also possible to add support for per-locale transliterations. I18n # expects transliteration rules to be stored at # i18n.transliterate.rule. # # Transliteration rules can either be a Hash or a Proc. Procs must accept a # single string argument. Hash rules inherit the default transliteration # rules, while Procs do not. # # *Examples* # # Setting a Hash in .yml: # # i18n: # transliterate: # rule: # ü: "ue" # ö: "oe" # # Setting a Hash using Ruby: # # store_translations(:de, :i18n => { # :transliterate => { # :rule => { # "ü" => "ue", # "ö" => "oe" # } # } # ) # # Setting a Proc: # # translit = lambda {|string| MyTransliterator.transliterate(string) } # store_translations(:xx, :i18n => {:transliterate => {:rule => translit}) # # Transliterating strings: # # I18n.locale = :en # I18n.transliterate("Jürgen") # => "Jurgen" # I18n.locale = :de # I18n.transliterate("Jürgen") # => "Juergen" # I18n.transliterate("Jürgen", :locale => :en) # => "Jurgen" # I18n.transliterate("Jürgen", :locale => :de) # => "Juergen" def transliterate(key, throw: false, raise: false, locale: nil, replacement: nil, **options) locale ||= config.locale raise Disabled.new('transliterate') if locale == false enforce_available_locales!(locale) config.backend.transliterate(locale, key, replacement) rescue I18n::ArgumentError => exception handle_exception((throw && :throw || raise && :raise), exception, locale, key, options) end # Localizes certain objects, such as dates and numbers to local formatting. def localize(object, locale: nil, format: nil, **options) locale ||= config.locale raise Disabled.new('l') if locale == false enforce_available_locales!(locale) format ||= :default config.backend.localize(locale, object, format, options) end alias :l :localize # Executes block with given I18n.locale set. def with_locale(tmp_locale = nil) if tmp_locale == nil yield else current_locale = self.locale self.locale = tmp_locale begin yield ensure self.locale = current_locale end end end # Merges the given locale, key and scope into a single array of keys. # Splits keys that contain dots into multiple keys. Makes sure all # keys are Symbols. def normalize_keys(locale, key, scope, separator = nil) separator ||= I18n.default_separator keys = [] keys.concat normalize_key(locale, separator) keys.concat normalize_key(scope, separator) keys.concat normalize_key(key, separator) keys end # Returns true when the passed locale, which can be either a String or a # Symbol, is in the list of available locales. Returns false otherwise. def locale_available?(locale) I18n.config.available_locales_set.include?(locale) end # Raises an InvalidLocale exception when the passed locale is not available. def enforce_available_locales!(locale) if locale != false && config.enforce_available_locales raise I18n::InvalidLocale.new(locale) if !locale_available?(locale) end end def available_locales_initialized? config.available_locales_initialized? end private # Any exceptions thrown in translate will be sent to the @@exception_handler # which can be a Symbol, a Proc or any other Object unless they're forced to # be raised or thrown (MissingTranslation). # # If exception_handler is a Symbol then it will simply be sent to I18n as # a method call. A Proc will simply be called. In any other case the # method #call will be called on the exception_handler object. # # Examples: # # I18n.exception_handler = :custom_exception_handler # this is the default # I18n.custom_exception_handler(exception, locale, key, options) # will be called like this # # I18n.exception_handler = lambda { |*args| ... } # a lambda # I18n.exception_handler.call(exception, locale, key, options) # will be called like this # # I18n.exception_handler = I18nExceptionHandler.new # an object # I18n.exception_handler.call(exception, locale, key, options) # will be called like this def handle_exception(handling, exception, locale, key, options) case handling when :raise raise exception.respond_to?(:to_exception) ? exception.to_exception : exception when :throw throw :exception, exception else case handler = options[:exception_handler] || config.exception_handler when Symbol send(handler, exception, locale, key, options) else handler.call(exception, locale, key, options) end end end @@normalized_key_cache = I18n.new_double_nested_cache def normalize_key(key, separator) @@normalized_key_cache[separator][key] ||= case key when Array key.flat_map { |k| normalize_key(k, separator) } else keys = key.to_s.split(separator) keys.delete('') keys.map! do |k| case k when /\A[-+]?[1-9]\d*\z/ # integer k.to_i when 'true' true when 'false' false else k.to_sym end end keys end end end extend Base end i18n-1.8.11/lib/i18n/000077500000000000000000000000001414033570300137065ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/backend.rb000066400000000000000000000017461414033570300156320ustar00rootroot00000000000000# frozen_string_literal: true module I18n module Backend autoload :Base, 'i18n/backend/base' autoload :InterpolationCompiler, 'i18n/backend/interpolation_compiler' autoload :Cache, 'i18n/backend/cache' autoload :CacheFile, 'i18n/backend/cache_file' autoload :Cascade, 'i18n/backend/cascade' autoload :Chain, 'i18n/backend/chain' autoload :Fallbacks, 'i18n/backend/fallbacks' autoload :Flatten, 'i18n/backend/flatten' autoload :Gettext, 'i18n/backend/gettext' autoload :KeyValue, 'i18n/backend/key_value' autoload :Memoize, 'i18n/backend/memoize' autoload :Metadata, 'i18n/backend/metadata' autoload :Pluralization, 'i18n/backend/pluralization' autoload :Simple, 'i18n/backend/simple' autoload :Transliterator, 'i18n/backend/transliterator' end end i18n-1.8.11/lib/i18n/backend/000077500000000000000000000000001414033570300152755ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/backend/base.rb000066400000000000000000000266731414033570300165520ustar00rootroot00000000000000# frozen_string_literal: true require 'yaml' require 'json' require 'i18n/core_ext/hash' module I18n module Backend module Base using I18n::HashRefinements include I18n::Backend::Transliterator # Accepts a list of paths to translation files. Loads translations from # plain Ruby (*.rb), YAML files (*.yml), or JSON files (*.json). See #load_rb, #load_yml, and #load_json # for details. def load_translations(*filenames) filenames = I18n.load_path if filenames.empty? filenames.flatten.each { |filename| load_file(filename) } end # This method receives a locale, a data hash and options for storing translations. # Should be implemented def store_translations(locale, data, options = EMPTY_HASH) raise NotImplementedError end def translate(locale, key, options = EMPTY_HASH) raise I18n::ArgumentError if (key.is_a?(String) || key.is_a?(Symbol)) && key.empty? raise InvalidLocale.new(locale) unless locale return nil if key.nil? && !options.key?(:default) entry = lookup(locale, key, options[:scope], options) unless key.nil? if entry.nil? && options.key?(:default) entry = default(locale, key, options[:default], options) else entry = resolve(locale, key, entry, options) end count = options[:count] if entry.nil? && (subtrees? || !count) if (options.key?(:default) && !options[:default].nil?) || !options.key?(:default) throw(:exception, I18n::MissingTranslation.new(locale, key, options)) end end entry = entry.dup if entry.is_a?(String) entry = pluralize(locale, entry, count) if count if entry.nil? && !subtrees? throw(:exception, I18n::MissingTranslation.new(locale, key, options)) end deep_interpolation = options[:deep_interpolation] values = options.except(*RESERVED_KEYS) if values entry = if deep_interpolation deep_interpolate(locale, entry, values) else interpolate(locale, entry, values) end end entry end def exists?(locale, key, options = EMPTY_HASH) lookup(locale, key) != nil end # Acts the same as +strftime+, but uses a localized version of the # format string. Takes a key from the date/time formats translations as # a format argument (e.g., :short in :'date.formats'). def localize(locale, object, format = :default, options = EMPTY_HASH) if object.nil? && options.include?(:default) return options[:default] end raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime) if Symbol === format key = format type = object.respond_to?(:sec) ? 'time' : 'date' options = options.merge(:raise => true, :object => object, :locale => locale) format = I18n.t(:"#{type}.formats.#{key}", **options) end format = translate_localization_format(locale, object, format, options) object.strftime(format) end # Returns an array of locales for which translations are available # ignoring the reserved translation meta data key :i18n. def available_locales raise NotImplementedError end def reload! eager_load! if eager_loaded? end def eager_load! @eager_loaded = true end protected def eager_loaded? @eager_loaded ||= false end # The method which actually looks up for the translation in the store. def lookup(locale, key, scope = [], options = EMPTY_HASH) raise NotImplementedError end def subtrees? true end # Evaluates defaults. # If given subject is an Array, it walks the array and returns the # first translation that can be resolved. Otherwise it tries to resolve # the translation directly. def default(locale, object, subject, options = EMPTY_HASH) options = options.reject { |key, value| key == :default } case subject when Array subject.each do |item| result = resolve(locale, object, item, options) return result unless result.nil? end and nil else resolve(locale, object, subject, options) end end # Resolves a translation. # If the given subject is a Symbol, it will be translated with the # given options. If it is a Proc then it will be evaluated. All other # subjects will be returned directly. def resolve(locale, object, subject, options = EMPTY_HASH) return subject if options[:resolve] == false result = catch(:exception) do case subject when Symbol I18n.translate(subject, **options.merge(:locale => locale, :throw => true)) when Proc date_or_time = options.delete(:object) || object resolve(locale, object, subject.call(date_or_time, **options)) else subject end end result unless result.is_a?(MissingTranslation) end # Picks a translation from a pluralized mnemonic subkey according to English # pluralization rules : # - It will pick the :one subkey if count is equal to 1. # - It will pick the :other subkey otherwise. # - It will pick the :zero subkey in the special case where count is # equal to 0 and there is a :zero subkey present. This behaviour is # not standard with regards to the CLDR pluralization rules. # Other backends can implement more flexible or complex pluralization rules. def pluralize(locale, entry, count) entry = entry.reject { |k, _v| k == :attributes } if entry.is_a?(Hash) return entry unless entry.is_a?(Hash) && count && entry.values.none? { |v| v.is_a?(Hash) } key = pluralization_key(entry, count) raise InvalidPluralizationData.new(entry, count, key) unless entry.has_key?(key) entry[key] end # Interpolates values into a given subject. # # if the given subject is a string then: # method interpolates "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X' # # => "file test.txt opened by %{user}" # # if the given subject is an array then: # each element of the array is recursively interpolated (until it finds a string) # method interpolates ["yes, %{user}", ["maybe no, %{user}, "no, %{user}"]], :user => "bartuz" # # => "["yes, bartuz",["maybe no, bartuz", "no, bartuz"]]" def interpolate(locale, subject, values = EMPTY_HASH) return subject if values.empty? case subject when ::String then I18n.interpolate(subject, values) when ::Array then subject.map { |element| interpolate(locale, element, values) } else subject end end # Deep interpolation # # deep_interpolate { people: { ann: "Ann is %{ann}", john: "John is %{john}" } }, # ann: 'good', john: 'big' # #=> { people: { ann: "Ann is good", john: "John is big" } } def deep_interpolate(locale, data, values = EMPTY_HASH) return data if values.empty? case data when ::String I18n.interpolate(data, values) when ::Hash data.each_with_object({}) do |(k, v), result| result[k] = deep_interpolate(locale, v, values) end when ::Array data.map do |v| deep_interpolate(locale, v, values) end else data end end # Loads a single translations file by delegating to #load_rb or # #load_yml depending on the file extension and directly merges the # data to the existing translations. Raises I18n::UnknownFileType # for all other file extensions. def load_file(filename) type = File.extname(filename).tr('.', '').downcase raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true) data = send(:"load_#{type}", filename) unless data.is_a?(Hash) raise InvalidLocaleData.new(filename, 'expects it to return a hash, but does not') end data.each { |locale, d| store_translations(locale, d || {}) } end # Loads a plain Ruby translations file. eval'ing the file must yield # a Hash containing translation data with locales as toplevel keys. def load_rb(filename) eval(IO.read(filename), binding, filename) end # Loads a YAML translations file. The data must have locales as # toplevel keys. def load_yml(filename) begin if YAML.respond_to?(:unsafe_load_file) # Psych 4.0 way YAML.unsafe_load_file(filename) else YAML.load_file(filename) end rescue TypeError, ScriptError, StandardError => e raise InvalidLocaleData.new(filename, e.inspect) end end alias_method :load_yaml, :load_yml # Loads a JSON translations file. The data must have locales as # toplevel keys. def load_json(filename) begin ::JSON.parse(File.read(filename)) rescue TypeError, StandardError => e raise InvalidLocaleData.new(filename, e.inspect) end end def translate_localization_format(locale, object, format, options) format.to_s.gsub(/%(|\^)[aAbBpP]/) do |match| case match when '%a' then I18n.t!(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday] when '%^a' then I18n.t!(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday].upcase when '%A' then I18n.t!(:"date.day_names", :locale => locale, :format => format)[object.wday] when '%^A' then I18n.t!(:"date.day_names", :locale => locale, :format => format)[object.wday].upcase when '%b' then I18n.t!(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon] when '%^b' then I18n.t!(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon].upcase when '%B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon] when '%^B' then I18n.t!(:"date.month_names", :locale => locale, :format => format)[object.mon].upcase when '%p' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour when '%P' then I18n.t!(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour end end rescue MissingTranslationData => e e.message end def pluralization_key(entry, count) key = :zero if count == 0 && entry.has_key?(:zero) key ||= count == 1 ? :one : :other end end end end i18n-1.8.11/lib/i18n/backend/cache.rb000066400000000000000000000067001414033570300166700ustar00rootroot00000000000000# frozen_string_literal: true # This module allows you to easily cache all responses from the backend - thus # speeding up the I18n aspects of your application quite a bit. # # To enable caching you can simply include the Cache module to the Simple # backend - or whatever other backend you are using: # # I18n::Backend::Simple.send(:include, I18n::Backend::Cache) # # You will also need to set a cache store implementation that you want to use: # # I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store) # # You can use any cache implementation you want that provides the same API as # ActiveSupport::Cache (only the methods #fetch and #write are being used). # # The cache_key implementation by default assumes you pass values that return # a valid key from #hash (see # https://www.ruby-doc.org/core/classes/Object.html#M000337). However, you can # configure your own digest method via which responds to #hexdigest (see # https://ruby-doc.org/stdlib/libdoc/openssl/rdoc/OpenSSL/Digest.html): # # I18n.cache_key_digest = OpenSSL::Digest::SHA256.new # # If you use a lambda as a default value in your translation like this: # # I18n.t(:"date.order", :default => lambda {[:month, :day, :year]}) # # Then you will always have a cache miss, because each time this method # is called the lambda will have a different hash value. If you know # the result of the lambda is a constant as in the example above, then # to cache this you can make the lambda a constant, like this: # # DEFAULT_DATE_ORDER = lambda {[:month, :day, :year]} # ... # I18n.t(:"date.order", :default => DEFAULT_DATE_ORDER) # # If the lambda may result in different values for each call then consider # also using the Memoize backend. # module I18n class << self @@cache_store = nil @@cache_namespace = nil @@cache_key_digest = nil def cache_store @@cache_store end def cache_store=(store) @@cache_store = store end def cache_namespace @@cache_namespace end def cache_namespace=(namespace) @@cache_namespace = namespace end def cache_key_digest @@cache_key_digest end def cache_key_digest=(key_digest) @@cache_key_digest = key_digest end def perform_caching? !cache_store.nil? end end module Backend # TODO Should the cache be cleared if new translations are stored? module Cache def translate(locale, key, options = EMPTY_HASH) I18n.perform_caching? ? fetch(cache_key(locale, key, options)) { super } : super end protected def fetch(cache_key, &block) result = _fetch(cache_key, &block) throw(:exception, result) if result.is_a?(MissingTranslation) result = result.dup if result.frozen? rescue result result end def _fetch(cache_key, &block) result = I18n.cache_store.read(cache_key) return result unless result.nil? result = catch(:exception, &block) I18n.cache_store.write(cache_key, result) unless result.is_a?(Proc) result end def cache_key(locale, key, options) # This assumes that only simple, native Ruby values are passed to I18n.translate. "i18n/#{I18n.cache_namespace}/#{locale}/#{digest_item(key)}/#{digest_item(options)}" end private def digest_item(key) I18n.cache_key_digest ? I18n.cache_key_digest.hexdigest(key.to_s) : key.to_s.hash end end end end i18n-1.8.11/lib/i18n/backend/cache_file.rb000066400000000000000000000025551414033570300176730ustar00rootroot00000000000000# frozen_string_literal: true require 'openssl' module I18n module Backend # Overwrites the Base load_file method to cache loaded file contents. module CacheFile # Optionally provide path_roots array to normalize filename paths, # to make the cached i18n data portable across environments. attr_accessor :path_roots protected # Track loaded translation files in the `i18n.load_file` scope, # and skip loading the file if its contents are still up-to-date. def load_file(filename) initialized = !respond_to?(:initialized?) || initialized? key = I18n::Backend::Flatten.escape_default_separator(normalized_path(filename)) old_mtime, old_digest = initialized && lookup(:i18n, key, :load_file) return if (mtime = File.mtime(filename).to_i) == old_mtime || (digest = OpenSSL::Digest::SHA256.file(filename).hexdigest) == old_digest super store_translations(:i18n, load_file: { key => [mtime, digest] }) end # Translate absolute filename to relative path for i18n key. def normalized_path(file) return file unless path_roots path = path_roots.find(&file.method(:start_with?)) || raise(InvalidLocaleData.new(file, 'outside expected path roots')) file.sub(path, path_roots.index(path).to_s) end end end end i18n-1.8.11/lib/i18n/backend/cascade.rb000066400000000000000000000042271414033570300172120ustar00rootroot00000000000000# frozen_string_literal: true # The Cascade module adds the ability to do cascading lookups to backends that # are compatible to the Simple backend. # # By cascading lookups we mean that for any key that can not be found the # Cascade module strips one segment off the scope part of the key and then # tries to look up the key in that scope. # # E.g. when a lookup for the key :"foo.bar.baz" does not yield a result then # the segment :bar will be stripped off the scope part :"foo.bar" and the new # scope :foo will be used to look up the key :baz. If that does not succeed # then the remaining scope segment :foo will be omitted, too, and again the # key :baz will be looked up (now with no scope). # # To enable a cascading lookup one passes the :cascade option: # # I18n.t(:'foo.bar.baz', :cascade => true) # # This will return the first translation found for :"foo.bar.baz", :"foo.baz" # or :baz in this order. # # The cascading lookup takes precedence over resolving any given defaults. # I.e. defaults will kick in after the cascading lookups haven't succeeded. # # This behavior is useful for libraries like ActiveRecord validations where # the library wants to give users a bunch of more or less fine-grained options # of scopes for a particular key. # # Thanks to Clemens Kofler for the initial idea and implementation! See # http://github.com/clemens/i18n-cascading-backend module I18n module Backend module Cascade def lookup(locale, key, scope = [], options = EMPTY_HASH) return super unless cascade = options[:cascade] cascade = { :step => 1 } unless cascade.is_a?(Hash) step = cascade[:step] || 1 offset = cascade[:offset] || 1 separator = options[:separator] || I18n.default_separator skip_root = cascade.has_key?(:skip_root) ? cascade[:skip_root] : true scope = I18n.normalize_keys(nil, key, scope, separator) key = (scope.slice!(-offset, offset) || []).join(separator) begin result = super return result unless result.nil? scope = scope.dup end while (!scope.empty? || !skip_root) && scope.slice!(-step, step) end end end end i18n-1.8.11/lib/i18n/backend/chain.rb000066400000000000000000000103701414033570300167050ustar00rootroot00000000000000# frozen_string_literal: true module I18n module Backend # Backend that chains multiple other backends and checks each of them when # a translation needs to be looked up. This is useful when you want to use # standard translations with a Simple backend but store custom application # translations in a database or other backends. # # To use the Chain backend instantiate it and set it to the I18n module. # You can add chained backends through the initializer or backends # accessor: # # # preserves the existing Simple backend set to I18n.backend # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n.backend) # # The implementation assumes that all backends added to the Chain implement # a lookup method with the same API as Simple backend does. class Chain using I18n::HashRefinements module Implementation include Base attr_accessor :backends def initialize(*backends) self.backends = backends end def initialized? backends.all? do |backend| backend.instance_eval do return false unless initialized? end end true end def reload! backends.each { |backend| backend.reload! } end def eager_load! backends.each { |backend| backend.eager_load! } end def store_translations(locale, data, options = EMPTY_HASH) backends.first.store_translations(locale, data, options) end def available_locales backends.map { |backend| backend.available_locales }.flatten.uniq end def translate(locale, key, default_options = EMPTY_HASH) namespace = nil options = default_options.except(:default) backends.each do |backend| catch(:exception) do options = default_options if backend == backends.last translation = backend.translate(locale, key, options) if namespace_lookup?(translation, options) namespace = _deep_merge(translation, namespace || {}) elsif !translation.nil? || (options.key?(:default) && options[:default].nil?) return translation end end end return namespace if namespace throw(:exception, I18n::MissingTranslation.new(locale, key, options)) end def exists?(locale, key, options = EMPTY_HASH) backends.any? do |backend| backend.exists?(locale, key, options) end end def localize(locale, object, format = :default, options = EMPTY_HASH) backends.each do |backend| catch(:exception) do result = backend.localize(locale, object, format, options) and return result end end throw(:exception, I18n::MissingTranslation.new(locale, format, options)) end protected def init_translations backends.each do |backend| backend.send(:init_translations) end end def translations backends.reverse.each_with_object({}) do |backend, memo| partial_translations = backend.instance_eval do init_translations unless initialized? translations end memo.deep_merge!(partial_translations) { |_, a, b| b || a } end end def namespace_lookup?(result, options) result.is_a?(Hash) && !options.has_key?(:count) end private # This is approximately what gets used in ActiveSupport. # However since we are not guaranteed to run in an ActiveSupport context # it is wise to have our own copy. We underscore it # to not pollute the namespace of the including class. def _deep_merge(hash, other_hash) copy = hash.dup other_hash.each_pair do |k,v| value_from_other = hash[k] copy[k] = value_from_other.is_a?(Hash) && v.is_a?(Hash) ? _deep_merge(value_from_other, v) : v end copy end end include Implementation end end end i18n-1.8.11/lib/i18n/backend/fallbacks.rb000066400000000000000000000073631414033570300175550ustar00rootroot00000000000000# frozen_string_literal: true # I18n locale fallbacks are useful when you want your application to use # translations from other locales when translations for the current locale are # missing. E.g. you might want to use :en translations when translations in # your applications main locale :de are missing. # # To enable locale fallbacks you can simply include the Fallbacks module to # the Simple backend - or whatever other backend you are using: # # I18n::Backend::Simple.include(I18n::Backend::Fallbacks) module I18n @@fallbacks = nil class << self # Returns the current fallbacks implementation. Defaults to +I18n::Locale::Fallbacks+. def fallbacks @@fallbacks ||= I18n::Locale::Fallbacks.new Thread.current[:i18n_fallbacks] || @@fallbacks end # Sets the current fallbacks implementation. Use this to set a different fallbacks implementation. def fallbacks=(fallbacks) @@fallbacks = fallbacks.is_a?(Array) ? I18n::Locale::Fallbacks.new(fallbacks) : fallbacks Thread.current[:i18n_fallbacks] = @@fallbacks end end module Backend module Fallbacks # Overwrites the Base backend translate method so that it will try each # locale given by I18n.fallbacks for the given locale. E.g. for the # locale :"de-DE" it might try the locales :"de-DE", :de and :en # (depends on the fallbacks implementation) until it finds a result with # the given options. If it does not find any result for any of the # locales it will then throw MissingTranslation as usual. # # The default option takes precedence over fallback locales only when # it's a Symbol. When the default contains a String, Proc or Hash # it is evaluated last after all the fallback locales have been tried. def translate(locale, key, options = EMPTY_HASH) return super unless options.fetch(:fallback, true) return super if options[:fallback_in_progress] default = extract_non_symbol_default!(options) if options[:default] fallback_options = options.merge(:fallback_in_progress => true) I18n.fallbacks[locale].each do |fallback| begin catch(:exception) do result = super(fallback, key, fallback_options) unless result.nil? on_fallback(locale, fallback, key, options) if locale.to_s != fallback.to_s return result end end rescue I18n::InvalidLocale # we do nothing when the locale is invalid, as this is a fallback anyways. end end return if options.key?(:default) && options[:default].nil? return super(locale, nil, options.merge(:default => default)) if default throw(:exception, I18n::MissingTranslation.new(locale, key, options)) end def extract_non_symbol_default!(options) defaults = [options[:default]].flatten first_non_symbol_default = defaults.detect{|default| !default.is_a?(Symbol)} if first_non_symbol_default options[:default] = defaults[0, defaults.index(first_non_symbol_default)] end return first_non_symbol_default end def exists?(locale, key, options = EMPTY_HASH) return super unless options.fetch(:fallback, true) I18n.fallbacks[locale].each do |fallback| begin return true if super(fallback, key) rescue I18n::InvalidLocale # we do nothing when the locale is invalid, as this is a fallback anyways. end end false end private # Overwrite on_fallback to add specified logic when the fallback succeeds. def on_fallback(_original_locale, _fallback_locale, _key, _optoins) nil end end end end i18n-1.8.11/lib/i18n/backend/flatten.rb000066400000000000000000000074711414033570300172700ustar00rootroot00000000000000# frozen_string_literal: true module I18n module Backend # This module contains several helpers to assist flattening translations. # You may want to flatten translations for: # # 1) speed up lookups, as in the Memoize backend; # 2) In case you want to store translations in a data store, as in ActiveRecord backend; # # You can check both backends above for some examples. # This module also keeps all links in a hash so they can be properly resolved when flattened. module Flatten SEPARATOR_ESCAPE_CHAR = "\001" FLATTEN_SEPARATOR = "." # normalize_keys the flatten way. This method is significantly faster # and creates way less objects than the one at I18n.normalize_keys. # It also handles escaping the translation keys. def self.normalize_flat_keys(locale, key, scope, separator) keys = [scope, key] keys.flatten! keys.compact! separator ||= I18n.default_separator if separator != FLATTEN_SEPARATOR from_str = "#{FLATTEN_SEPARATOR}#{separator}" to_str = "#{SEPARATOR_ESCAPE_CHAR}#{FLATTEN_SEPARATOR}" keys.map! { |k| k.to_s.tr from_str, to_str } end keys.join(".") end # Receives a string and escape the default separator. def self.escape_default_separator(key) #:nodoc: key.to_s.tr(FLATTEN_SEPARATOR, SEPARATOR_ESCAPE_CHAR) end # Shortcut to I18n::Backend::Flatten.normalize_flat_keys # and then resolve_links. def normalize_flat_keys(locale, key, scope, separator) key = I18n::Backend::Flatten.normalize_flat_keys(locale, key, scope, separator) resolve_link(locale, key) end # Store flattened links. def links @links ||= I18n.new_double_nested_cache end # Flatten keys for nested Hashes by chaining up keys: # # >> { "a" => { "b" => { "c" => "d", "e" => "f" }, "g" => "h" }, "i" => "j"}.wind # => { "a.b.c" => "d", "a.b.e" => "f", "a.g" => "h", "i" => "j" } # def flatten_keys(hash, escape, prev_key=nil, &block) hash.each_pair do |key, value| key = escape_default_separator(key) if escape curr_key = [prev_key, key].compact.join(FLATTEN_SEPARATOR).to_sym yield curr_key, value flatten_keys(value, escape, curr_key, &block) if value.is_a?(Hash) end end # Receives a hash of translations (where the key is a locale and # the value is another hash) and return a hash with all # translations flattened. # # Nested hashes are included in the flattened hash just if subtree # is true and Symbols are automatically stored as links. def flatten_translations(locale, data, escape, subtree) hash = {} flatten_keys(data, escape) do |key, value| if value.is_a?(Hash) hash[key] = value if subtree else store_link(locale, key, value) if value.is_a?(Symbol) hash[key] = value end end hash end protected def store_link(locale, key, link) links[locale.to_sym][key.to_s] = link.to_s end def resolve_link(locale, key) key, locale = key.to_s, locale.to_sym links = self.links[locale] if links.key?(key) links[key] elsif link = find_link(locale, key) store_link(locale, key, key.gsub(*link)) else key end end def find_link(locale, key) #:nodoc: links[locale].each_pair do |from, to| return [from, to] if key[0, from.length] == from end && nil end def escape_default_separator(key) #:nodoc: I18n::Backend::Flatten.escape_default_separator(key) end end end end i18n-1.8.11/lib/i18n/backend/gettext.rb000066400000000000000000000055061414033570300173140ustar00rootroot00000000000000# frozen_string_literal: true require 'i18n/gettext' require 'i18n/gettext/po_parser' module I18n module Backend # Experimental support for using Gettext po files to store translations. # # To use this you can simply include the module to the Simple backend - or # whatever other backend you are using. # # I18n::Backend::Simple.include(I18n::Backend::Gettext) # # Now you should be able to include your Gettext translation (*.po) files to # the +I18n.load_path+ so they're loaded to the backend and you can use them as # usual: # # I18n.load_path += Dir["path/to/locales/*.po"] # # Following the Gettext convention this implementation expects that your # translation files are named by their locales. E.g. the file en.po would # contain the translations for the English locale. # # To translate text you must use one of the translate methods provided by # I18n::Gettext::Helpers. # # include I18n::Gettext::Helpers # puts _("some string") # # Without it strings containing periods (".") will not be translated. module Gettext using I18n::HashRefinements class PoData < Hash def set_comment(msgid_or_sym, comment) # ignore end end protected def load_po(filename) locale = ::File.basename(filename, '.po').to_sym data = normalize(locale, parse(filename)) { locale => data } end def parse(filename) GetText::PoParser.new.parse(::File.read(filename), PoData.new) end def normalize(locale, data) data.inject({}) do |result, (key, value)| unless key.nil? || key.empty? key = key.gsub(I18n::Gettext::CONTEXT_SEPARATOR, '|') key, value = normalize_pluralization(locale, key, value) if key.index("\000") parts = key.split('|').reverse normalized = parts.inject({}) do |_normalized, part| { part => _normalized.empty? ? value : _normalized } end result.deep_merge!(normalized) end result end end def normalize_pluralization(locale, key, value) # FIXME po_parser includes \000 chars that can not be turned into Symbols key = key.gsub("\000", I18n::Gettext::PLURAL_SEPARATOR).split(I18n::Gettext::PLURAL_SEPARATOR).first keys = I18n::Gettext.plural_keys(locale) values = value.split("\000") raise "invalid number of plurals: #{values.size}, keys: #{keys.inspect} on #{locale} locale for msgid #{key.inspect} with values #{values.inspect}" if values.size != keys.size result = {} values.each_with_index { |_value, ix| result[keys[ix]] = _value } [key, result] end end end end i18n-1.8.11/lib/i18n/backend/interpolation_compiler.rb000066400000000000000000000073241414033570300224110ustar00rootroot00000000000000# frozen_string_literal: true # The InterpolationCompiler module contains optimizations that can tremendously # speed up the interpolation process on the Simple backend. # # It works by defining a pre-compiled method on stored translation Strings that # already bring all the knowledge about contained interpolation variables etc. # so that the actual recurring interpolation will be very fast. # # To enable pre-compiled interpolations you can simply include the # InterpolationCompiler module to the Simple backend: # # I18n::Backend::Simple.include(I18n::Backend::InterpolationCompiler) # # Note that InterpolationCompiler does not yield meaningful results and consequently # should not be used with Ruby 1.9 (YARV) but improves performance everywhere else # (jRuby, Rubinius). module I18n module Backend module InterpolationCompiler module Compiler extend self TOKENIZER = /(%%\{[^\}]+\}|%\{[^\}]+\})/ INTERPOLATION_SYNTAX_PATTERN = /(%)?(%\{([^\}]+)\})/ def compile_if_an_interpolation(string) if interpolated_str?(string) string.instance_eval <<-RUBY_EVAL, __FILE__, __LINE__ def i18n_interpolate(v = {}) "#{compiled_interpolation_body(string)}" end RUBY_EVAL end string end def interpolated_str?(str) str.kind_of?(::String) && str =~ INTERPOLATION_SYNTAX_PATTERN end protected # tokenize("foo %{bar} baz %%{buz}") # => ["foo ", "%{bar}", " baz ", "%%{buz}"] def tokenize(str) str.split(TOKENIZER) end def compiled_interpolation_body(str) tokenize(str).map do |token| (matchdata = token.match(INTERPOLATION_SYNTAX_PATTERN)) ? handle_interpolation_token(token, matchdata) : escape_plain_str(token) end.join end def handle_interpolation_token(interpolation, matchdata) escaped, pattern, key = matchdata.values_at(1, 2, 3) escaped ? pattern : compile_interpolation_token(key.to_sym) end def compile_interpolation_token(key) "\#{#{interpolate_or_raise_missing(key)}}" end def interpolate_or_raise_missing(key) escaped_key = escape_key_sym(key) RESERVED_KEYS.include?(key) ? reserved_key(escaped_key) : interpolate_key(escaped_key) end def interpolate_key(key) [direct_key(key), nil_key(key), missing_key(key)].join('||') end def direct_key(key) "((t = v[#{key}]) && t.respond_to?(:call) ? t.call : t)" end def nil_key(key) "(v.has_key?(#{key}) && '')" end def missing_key(key) "I18n.config.missing_interpolation_argument_handler.call(#{key}, v, self)" end def reserved_key(key) "raise(ReservedInterpolationKey.new(#{key}, self))" end def escape_plain_str(str) str.gsub(/"|\\|#/) {|x| "\\#{x}"} end def escape_key_sym(key) # rely on Ruby to do all the hard work :) key.to_sym.inspect end end def interpolate(locale, string, values) if string.respond_to?(:i18n_interpolate) string.i18n_interpolate(values) elsif values super else string end end def store_translations(locale, data, options = EMPTY_HASH) compile_all_strings_in(data) super end protected def compile_all_strings_in(data) data.each_value do |value| Compiler.compile_if_an_interpolation(value) compile_all_strings_in(value) if value.kind_of?(Hash) end end end end end i18n-1.8.11/lib/i18n/backend/key_value.rb000066400000000000000000000136431414033570300176150ustar00rootroot00000000000000# frozen_string_literal: true require 'i18n/backend/base' module I18n begin require 'oj' class JSON class << self def encode(value) Oj::Rails.encode(value) end def decode(value) Oj.load(value) end end end rescue LoadError require 'active_support/json' JSON = ActiveSupport::JSON end module Backend # This is a basic backend for key value stores. It receives on # initialization the store, which should respond to three methods: # # * store#[](key) - Used to get a value # * store#[]=(key, value) - Used to set a value # * store#keys - Used to get all keys # # Since these stores only supports string, all values are converted # to JSON before being stored, allowing it to also store booleans, # hashes and arrays. However, this store does not support Procs. # # As the ActiveRecord backend, Symbols are just supported when loading # translations from the filesystem or through explicit store translations. # # Also, avoid calling I18n.available_locales since it's a somehow # expensive operation in most stores. # # == Example # # To setup I18n to use TokyoCabinet in memory is quite straightforward: # # require 'rufus/tokyo/cabinet' # gem install rufus-tokyo # I18n.backend = I18n::Backend::KeyValue.new(Rufus::Tokyo::Cabinet.new('*')) # # == Performance # # You may make this backend even faster by including the Memoize module. # However, notice that you should properly clear the cache if you change # values directly in the key-store. # # == Subtrees # # In most backends, you are allowed to retrieve part of a translation tree: # # I18n.backend.store_translations :en, :foo => { :bar => :baz } # I18n.t "foo" #=> { :bar => :baz } # # This backend supports this feature by default, but it slows down the storage # of new data considerably and makes hard to delete entries. That said, you are # allowed to disable the storage of subtrees on initialization: # # I18n::Backend::KeyValue.new(@store, false) # # This is useful if you are using a KeyValue backend chained to a Simple backend. class KeyValue using I18n::HashRefinements module Implementation attr_accessor :store include Base, Flatten def initialize(store, subtrees=true) @store, @subtrees = store, subtrees end def initialized? !@store.nil? end def store_translations(locale, data, options = EMPTY_HASH) escape = options.fetch(:escape, true) flatten_translations(locale, data, escape, @subtrees).each do |key, value| key = "#{locale}.#{key}" case value when Hash if @subtrees && (old_value = @store[key]) old_value = JSON.decode(old_value) value = old_value.deep_symbolize_keys.deep_merge!(value) if old_value.is_a?(Hash) end when Proc raise "Key-value stores cannot handle procs" end @store[key] = JSON.encode(value) unless value.is_a?(Symbol) end end def available_locales locales = @store.keys.map { |k| k =~ /\./; $` } locales.uniq! locales.compact! locales.map! { |k| k.to_sym } locales end protected # Queries the translations from the key-value store and converts # them into a hash such as the one returned from loading the # haml files def translations @translations = @store.keys.clone.map do |main_key| main_value = JSON.decode(@store[main_key]) main_key.to_s.split(".").reverse.inject(main_value) do |value, key| {key.to_sym => value} end end.inject{|hash, elem| hash.deep_merge!(elem)}.deep_symbolize_keys end def init_translations # NO OP # This call made also inside Simple Backend and accessed by # other plugins like I18n-js and babilu and # to use it along with the Chain backend we need to # provide a uniform API even for protected methods :S end def subtrees? @subtrees end def lookup(locale, key, scope = [], options = EMPTY_HASH) key = normalize_flat_keys(locale, key, scope, options[:separator]) value = @store["#{locale}.#{key}"] value = JSON.decode(value) if value if value.is_a?(Hash) value.deep_symbolize_keys elsif !value.nil? value elsif !@subtrees SubtreeProxy.new("#{locale}.#{key}", @store) end end def pluralize(locale, entry, count) if subtrees? super else return entry unless entry.is_a?(Hash) key = pluralization_key(entry, count) entry[key] end end end class SubtreeProxy def initialize(master_key, store) @master_key = master_key @store = store @subtree = nil end def has_key?(key) @subtree && @subtree.has_key?(key) || self[key] end def [](key) unless @subtree && value = @subtree[key] value = @store["#{@master_key}.#{key}"] if value value = JSON.decode(value) (@subtree ||= {})[key] = value end end value end def is_a?(klass) Hash == klass || super end alias :kind_of? :is_a? def instance_of?(klass) Hash == klass || super end def nil? @subtree.nil? end def inspect @subtree.inspect end end include Implementation end end end i18n-1.8.11/lib/i18n/backend/memoize.rb000066400000000000000000000027141414033570300172730ustar00rootroot00000000000000# frozen_string_literal: true # Memoize module simply memoizes the values returned by lookup using # a flat hash and can tremendously speed up the lookup process in a backend. # # To enable it you can simply include the Memoize module to your backend: # # I18n::Backend::Simple.include(I18n::Backend::Memoize) # # Notice that it's the responsibility of the backend to define whenever the # cache should be cleaned. module I18n module Backend module Memoize def available_locales @memoized_locales ||= super end def store_translations(locale, data, options = EMPTY_HASH) reset_memoizations!(locale) super end def reload! reset_memoizations! super end def eager_load! memoized_lookup available_locales super end protected def lookup(locale, key, scope = nil, options = EMPTY_HASH) flat_key = I18n::Backend::Flatten.normalize_flat_keys(locale, key, scope, options[:separator]).to_sym flat_hash = memoized_lookup[locale.to_sym] flat_hash.key?(flat_key) ? flat_hash[flat_key] : (flat_hash[flat_key] = super) end def memoized_lookup @memoized_lookup ||= I18n.new_double_nested_cache end def reset_memoizations!(locale=nil) @memoized_locales = nil (locale ? memoized_lookup[locale.to_sym] : memoized_lookup).clear end end end end i18n-1.8.11/lib/i18n/backend/metadata.rb000066400000000000000000000042521414033570300174050ustar00rootroot00000000000000# frozen_string_literal: true # I18n translation metadata is useful when you want to access information # about how a translation was looked up, pluralized or interpolated in # your application. # # msg = I18n.t(:message, :default => 'Hi!', :scope => :foo) # msg.translation_metadata # # => { :key => :message, :scope => :foo, :default => 'Hi!' } # # If a :count option was passed to #translate it will be set to the metadata. # Likewise, if any interpolation variables were passed they will also be set. # # To enable translation metadata you can simply include the Metadata module # into the Simple backend class - or whatever other backend you are using: # # I18n::Backend::Simple.include(I18n::Backend::Metadata) # module I18n module Backend module Metadata class << self def included(base) Object.class_eval do def translation_metadata unless self.frozen? @translation_metadata ||= {} else {} end end def translation_metadata=(translation_metadata) @translation_metadata = translation_metadata unless self.frozen? end end unless Object.method_defined?(:translation_metadata) end end def translate(locale, key, options = EMPTY_HASH) metadata = { :locale => locale, :key => key, :scope => options[:scope], :default => options[:default], :separator => options[:separator], :values => options.reject { |name, _value| RESERVED_KEYS.include?(name) } } with_metadata(metadata) { super } end def interpolate(locale, entry, values = EMPTY_HASH) metadata = entry.translation_metadata.merge(:original => entry) with_metadata(metadata) { super } end def pluralize(locale, entry, count) with_metadata(:count => count) { super } end protected def with_metadata(metadata, &block) result = yield result.translation_metadata = result.translation_metadata.merge(metadata) if result result end end end end i18n-1.8.11/lib/i18n/backend/pluralization.rb000066400000000000000000000041161414033570300205210ustar00rootroot00000000000000# frozen_string_literal: true # I18n Pluralization are useful when you want your application to # customize pluralization rules. # # To enable locale specific pluralizations you can simply include the # Pluralization module to the Simple backend - or whatever other backend you # are using. # # I18n::Backend::Simple.include(I18n::Backend::Pluralization) # # You also need to make sure to provide pluralization algorithms to the # backend, i.e. include them to your I18n.load_path accordingly. module I18n module Backend module Pluralization # Overwrites the Base backend translate method so that it will check the # translation meta data space (:i18n) for a locale specific pluralization # rule and use it to pluralize the given entry. I.e. the library expects # pluralization rules to be stored at I18n.t(:'i18n.plural.rule') # # Pluralization rules are expected to respond to #call(count) and # return a pluralization key. Valid keys depend on the translation data # hash (entry) but it is generally recommended to follow CLDR's style, # i.e., return one of the keys :zero, :one, :few, :many, :other. # # The :zero key is always picked directly when count equals 0 AND the # translation data has the key :zero. This way translators are free to # either pick a special :zero translation even for languages where the # pluralizer does not return a :zero key. def pluralize(locale, entry, count) return entry unless entry.is_a?(Hash) && count pluralizer = pluralizer(locale) if pluralizer.respond_to?(:call) key = count == 0 && entry.has_key?(:zero) ? :zero : pluralizer.call(count) raise InvalidPluralizationData.new(entry, count, key) unless entry.has_key?(key) entry[key] else super end end protected def pluralizers @pluralizers ||= {} end def pluralizer(locale) pluralizers[locale] ||= I18n.t(:'i18n.plural.rule', :locale => locale, :resolve => false) end end end end i18n-1.8.11/lib/i18n/backend/simple.rb000066400000000000000000000067171414033570300171260ustar00rootroot00000000000000# frozen_string_literal: true require 'i18n/backend/base' module I18n module Backend # A simple backend that reads translations from YAML files and stores them in # an in-memory hash. Relies on the Base backend. # # The implementation is provided by a Implementation module allowing to easily # extend Simple backend's behavior by including modules. E.g.: # # module I18n::Backend::Pluralization # def pluralize(*args) # # extended pluralization logic # super # end # end # # I18n::Backend::Simple.include(I18n::Backend::Pluralization) class Simple using I18n::HashRefinements module Implementation include Base def initialized? @initialized ||= false end # Stores translations for the given locale in memory. # This uses a deep merge for the translations hash, so existing # translations will be overwritten by new ones only at the deepest # level of the hash. def store_translations(locale, data, options = EMPTY_HASH) if I18n.enforce_available_locales && I18n.available_locales_initialized? && !I18n.locale_available?(locale) return data end locale = locale.to_sym translations[locale] ||= Concurrent::Hash.new data = data.deep_symbolize_keys translations[locale].deep_merge!(data) end # Get available locales from the translations hash def available_locales init_translations unless initialized? translations.inject([]) do |locales, (locale, data)| locales << locale unless data.size <= 1 && (data.empty? || data.has_key?(:i18n)) locales end end # Clean up translations hash and set initialized to false on reload! def reload! @initialized = false @translations = nil super end def eager_load! init_translations unless initialized? super end def translations(do_init: false) # To avoid returning empty translations, # call `init_translations` init_translations if do_init && !initialized? @translations ||= Concurrent::Hash.new { |h, k| h[k] = Concurrent::Hash.new } end protected def init_translations load_translations @initialized = true end # Looks up a translation from the translations hash. Returns nil if # either key is nil, or locale, scope or key do not exist as a key in the # nested translations hash. Splits keys or scopes containing dots # into multiple keys, i.e. currency.format is regarded the same as # %w(currency format). def lookup(locale, key, scope = [], options = EMPTY_HASH) init_translations unless initialized? keys = I18n.normalize_keys(locale, key, scope, options[:separator]) keys.inject(translations) do |result, _key| return nil unless result.is_a?(Hash) unless result.has_key?(_key) _key = _key.to_s.to_sym return nil unless result.has_key?(_key) end result = result[_key] result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol) result end end end include Implementation end end end i18n-1.8.11/lib/i18n/backend/transliterator.rb000066400000000000000000000107561414033570300207100ustar00rootroot00000000000000# encoding: utf-8 # frozen_string_literal: true module I18n module Backend module Transliterator DEFAULT_REPLACEMENT_CHAR = "?" # Given a locale and a UTF-8 string, return the locale's ASCII # approximation for the string. def transliterate(locale, string, replacement = nil) @transliterators ||= {} @transliterators[locale] ||= Transliterator.get I18n.t(:'i18n.transliterate.rule', :locale => locale, :resolve => false, :default => {}) @transliterators[locale].transliterate(string, replacement) end # Get a transliterator instance. def self.get(rule = nil) if !rule || rule.kind_of?(Hash) HashTransliterator.new(rule) elsif rule.kind_of? Proc ProcTransliterator.new(rule) else raise I18n::ArgumentError, "Transliteration rule must be a proc or a hash." end end # A transliterator which accepts a Proc as its transliteration rule. class ProcTransliterator def initialize(rule) @rule = rule end def transliterate(string, replacement = nil) @rule.call(string) end end # A transliterator which accepts a Hash of characters as its translation # rule. class HashTransliterator DEFAULT_APPROXIMATIONS = { "À"=>"A", "Á"=>"A", "Â"=>"A", "Ã"=>"A", "Ä"=>"A", "Å"=>"A", "Æ"=>"AE", "Ç"=>"C", "È"=>"E", "É"=>"E", "Ê"=>"E", "Ë"=>"E", "Ì"=>"I", "Í"=>"I", "Î"=>"I", "Ï"=>"I", "Ð"=>"D", "Ñ"=>"N", "Ò"=>"O", "Ó"=>"O", "Ô"=>"O", "Õ"=>"O", "Ö"=>"O", "×"=>"x", "Ø"=>"O", "Ù"=>"U", "Ú"=>"U", "Û"=>"U", "Ü"=>"U", "Ý"=>"Y", "Þ"=>"Th", "ß"=>"ss", "à"=>"a", "á"=>"a", "â"=>"a", "ã"=>"a", "ä"=>"a", "å"=>"a", "æ"=>"ae", "ç"=>"c", "è"=>"e", "é"=>"e", "ê"=>"e", "ë"=>"e", "ì"=>"i", "í"=>"i", "î"=>"i", "ï"=>"i", "ð"=>"d", "ñ"=>"n", "ò"=>"o", "ó"=>"o", "ô"=>"o", "õ"=>"o", "ö"=>"o", "ø"=>"o", "ù"=>"u", "ú"=>"u", "û"=>"u", "ü"=>"u", "ý"=>"y", "þ"=>"th", "ÿ"=>"y", "Ā"=>"A", "ā"=>"a", "Ă"=>"A", "ă"=>"a", "Ą"=>"A", "ą"=>"a", "Ć"=>"C", "ć"=>"c", "Ĉ"=>"C", "ĉ"=>"c", "Ċ"=>"C", "ċ"=>"c", "Č"=>"C", "č"=>"c", "Ď"=>"D", "ď"=>"d", "Đ"=>"D", "đ"=>"d", "Ē"=>"E", "ē"=>"e", "Ĕ"=>"E", "ĕ"=>"e", "Ė"=>"E", "ė"=>"e", "Ę"=>"E", "ę"=>"e", "Ě"=>"E", "ě"=>"e", "Ĝ"=>"G", "ĝ"=>"g", "Ğ"=>"G", "ğ"=>"g", "Ġ"=>"G", "ġ"=>"g", "Ģ"=>"G", "ģ"=>"g", "Ĥ"=>"H", "ĥ"=>"h", "Ħ"=>"H", "ħ"=>"h", "Ĩ"=>"I", "ĩ"=>"i", "Ī"=>"I", "ī"=>"i", "Ĭ"=>"I", "ĭ"=>"i", "Į"=>"I", "į"=>"i", "İ"=>"I", "ı"=>"i", "IJ"=>"IJ", "ij"=>"ij", "Ĵ"=>"J", "ĵ"=>"j", "Ķ"=>"K", "ķ"=>"k", "ĸ"=>"k", "Ĺ"=>"L", "ĺ"=>"l", "Ļ"=>"L", "ļ"=>"l", "Ľ"=>"L", "ľ"=>"l", "Ŀ"=>"L", "ŀ"=>"l", "Ł"=>"L", "ł"=>"l", "Ń"=>"N", "ń"=>"n", "Ņ"=>"N", "ņ"=>"n", "Ň"=>"N", "ň"=>"n", "ʼn"=>"'n", "Ŋ"=>"NG", "ŋ"=>"ng", "Ō"=>"O", "ō"=>"o", "Ŏ"=>"O", "ŏ"=>"o", "Ő"=>"O", "ő"=>"o", "Œ"=>"OE", "œ"=>"oe", "Ŕ"=>"R", "ŕ"=>"r", "Ŗ"=>"R", "ŗ"=>"r", "Ř"=>"R", "ř"=>"r", "Ś"=>"S", "ś"=>"s", "Ŝ"=>"S", "ŝ"=>"s", "Ş"=>"S", "ş"=>"s", "Š"=>"S", "š"=>"s", "Ţ"=>"T", "ţ"=>"t", "Ť"=>"T", "ť"=>"t", "Ŧ"=>"T", "ŧ"=>"t", "Ũ"=>"U", "ũ"=>"u", "Ū"=>"U", "ū"=>"u", "Ŭ"=>"U", "ŭ"=>"u", "Ů"=>"U", "ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w", "Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z", "Ž"=>"Z", "ž"=>"z" }.freeze def initialize(rule = nil) @rule = rule add_default_approximations add rule if rule end def transliterate(string, replacement = nil) replacement ||= DEFAULT_REPLACEMENT_CHAR string.gsub(/[^\x00-\x7f]/u) do |char| approximations[char] || replacement end end private def approximations @approximations ||= {} end def add_default_approximations DEFAULT_APPROXIMATIONS.each do |key, value| approximations[key] = value end end # Add transliteration rules to the approximations hash. def add(hash) hash.each do |key, value| approximations[key.to_s] = value.to_s end end end end end end i18n-1.8.11/lib/i18n/config.rb000066400000000000000000000130411414033570300154770ustar00rootroot00000000000000# frozen_string_literal: true require 'set' module I18n class Config # The only configuration value that is not global and scoped to thread is :locale. # It defaults to the default_locale. def locale defined?(@locale) && @locale != nil ? @locale : default_locale end # Sets the current locale pseudo-globally, i.e. in the Thread.current hash. def locale=(locale) I18n.enforce_available_locales!(locale) @locale = locale && locale.to_sym end # Returns the current backend. Defaults to +Backend::Simple+. def backend @@backend ||= Backend::Simple.new end # Sets the current backend. Used to set a custom backend. def backend=(backend) @@backend = backend end # Returns the current default locale. Defaults to :'en' def default_locale @@default_locale ||= :en end # Sets the current default locale. Used to set a custom default locale. def default_locale=(locale) I18n.enforce_available_locales!(locale) @@default_locale = locale && locale.to_sym end # Returns an array of locales for which translations are available. # Unless you explicitely set these through I18n.available_locales= # the call will be delegated to the backend. def available_locales @@available_locales ||= nil @@available_locales || backend.available_locales end # Caches the available locales list as both strings and symbols in a Set, so # that we can have faster lookups to do the available locales enforce check. def available_locales_set #:nodoc: @@available_locales_set ||= available_locales.inject(Set.new) do |set, locale| set << locale.to_s << locale.to_sym end end # Sets the available locales. def available_locales=(locales) @@available_locales = Array(locales).map { |locale| locale.to_sym } @@available_locales = nil if @@available_locales.empty? @@available_locales_set = nil end # Returns true if the available_locales have been initialized def available_locales_initialized? ( !!defined?(@@available_locales) && !!@@available_locales ) end # Clears the available locales set so it can be recomputed again after I18n # gets reloaded. def clear_available_locales_set #:nodoc: @@available_locales_set = nil end # Returns the current default scope separator. Defaults to '.' def default_separator @@default_separator ||= '.' end # Sets the current default scope separator. def default_separator=(separator) @@default_separator = separator end # Returns the current exception handler. Defaults to an instance of # I18n::ExceptionHandler. def exception_handler @@exception_handler ||= ExceptionHandler.new end # Sets the exception handler. def exception_handler=(exception_handler) @@exception_handler = exception_handler end # Returns the current handler for situations when interpolation argument # is missing. MissingInterpolationArgument will be raised by default. def missing_interpolation_argument_handler @@missing_interpolation_argument_handler ||= lambda do |missing_key, provided_hash, string| raise MissingInterpolationArgument.new(missing_key, provided_hash, string) end end # Sets the missing interpolation argument handler. It can be any # object that responds to #call. The arguments that will be passed to #call # are the same as for MissingInterpolationArgument initializer. Use +Proc.new+ # if you don't care about arity. # # == Example: # You can supress raising an exception and return string instead: # # I18n.config.missing_interpolation_argument_handler = Proc.new do |key| # "#{key} is missing" # end def missing_interpolation_argument_handler=(exception_handler) @@missing_interpolation_argument_handler = exception_handler end # Allow clients to register paths providing translation data sources. The # backend defines acceptable sources. # # E.g. the provided SimpleBackend accepts a list of paths to translation # files which are either named *.rb and contain plain Ruby Hashes or are # named *.yml and contain YAML data. So for the SimpleBackend clients may # register translation files like this: # I18n.load_path << 'path/to/locale/en.yml' def load_path @@load_path ||= [] end # Sets the load path instance. Custom implementations are expected to # behave like a Ruby Array. def load_path=(load_path) @@load_path = load_path @@available_locales_set = nil backend.reload! end # Whether or not to verify if locales are in the list of available locales. # Defaults to true. @@enforce_available_locales = true def enforce_available_locales @@enforce_available_locales end def enforce_available_locales=(enforce_available_locales) @@enforce_available_locales = enforce_available_locales end # Returns the current interpolation patterns. Defaults to # I18n::DEFAULT_INTERPOLATION_PATTERNS. def interpolation_patterns @@interpolation_patterns ||= I18n::DEFAULT_INTERPOLATION_PATTERNS.dup end # Sets the current interpolation patterns. Used to set a interpolation # patterns. # # E.g. using {{}} as a placeholder like "{{hello}}, world!": # # I18n.config.interpolation_patterns << /\{\{(\w+)\}\}/ def interpolation_patterns=(interpolation_patterns) @@interpolation_patterns = interpolation_patterns end end end i18n-1.8.11/lib/i18n/core_ext/000077500000000000000000000000001414033570300155165ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/core_ext/hash.rb000066400000000000000000000027361414033570300167760ustar00rootroot00000000000000module I18n module HashRefinements refine Hash do using I18n::HashRefinements def except(*keys) dup.except!(*keys) end unless method_defined?(:except) def except!(*keys) keys.each { |key| delete(key) } self end def deep_symbolize_keys each_with_object({}) do |(key, value), result| result[symbolize_key(key)] = deep_symbolize_keys_in_object(value) result end end # deep_merge from activesupport 5 # Copyright (c) 2005-2019 David Heinemeier Hansson def deep_merge(other_hash, &block) dup.deep_merge!(other_hash, &block) end # deep_merge! from activesupport 5 # Copyright (c) 2005-2019 David Heinemeier Hansson def deep_merge!(other_hash, &block) merge!(other_hash) do |key, this_val, other_val| if this_val.is_a?(Hash) && other_val.is_a?(Hash) this_val.deep_merge(other_val, &block) elsif block_given? block.call(key, this_val, other_val) else other_val end end end def symbolize_key(key) key.respond_to?(:to_sym) ? key.to_sym : key end private def deep_symbolize_keys_in_object(value) case value when Hash value.deep_symbolize_keys when Array value.map { |e| deep_symbolize_keys_in_object(e) } else value end end end end end i18n-1.8.11/lib/i18n/exceptions.rb000066400000000000000000000063101414033570300164140ustar00rootroot00000000000000# frozen_string_literal: true require 'cgi' module I18n class ExceptionHandler def call(exception, _locale, _key, _options) if exception.is_a?(MissingTranslation) exception.message else raise exception end end end class ArgumentError < ::ArgumentError; end class Disabled < ArgumentError def initialize(method) super(<<~MESSAGE) I18n.#{method} is currently disabled, likely because your application is still in its loading phase. This method is meant to display text in the user locale, so calling it before the user locale has been set is likely to display text from the wrong locale to some users. If you have a legitimate reason to access i18n data outside of the user flow, you can do so by passing the desired locale explictly with the `locale` argument, e.g. `I18n.#{method}(..., locale: :en)` MESSAGE end end class InvalidLocale < ArgumentError attr_reader :locale def initialize(locale) @locale = locale super "#{locale.inspect} is not a valid locale" end end class InvalidLocaleData < ArgumentError attr_reader :filename def initialize(filename, exception_message) @filename, @exception_message = filename, exception_message super "can not load translations from #{filename}: #{exception_message}" end end class MissingTranslation < ArgumentError module Base attr_reader :locale, :key, :options def initialize(locale, key, options = EMPTY_HASH) @key, @locale, @options = key, locale, options.dup options.each { |k, v| self.options[k] = v.inspect if v.is_a?(Proc) } end def keys @keys ||= I18n.normalize_keys(locale, key, options[:scope]).tap do |keys| keys << 'no key' if keys.size < 2 end end def message "translation missing: #{keys.join('.')}" end alias :to_s :message def to_exception MissingTranslationData.new(locale, key, options) end end include Base end class MissingTranslationData < ArgumentError include MissingTranslation::Base end class InvalidPluralizationData < ArgumentError attr_reader :entry, :count, :key def initialize(entry, count, key) @entry, @count, @key = entry, count, key super "translation data #{entry.inspect} can not be used with :count => #{count}. key '#{key}' is missing." end end class MissingInterpolationArgument < ArgumentError attr_reader :key, :values, :string def initialize(key, values, string) @key, @values, @string = key, values, string super "missing interpolation argument #{key.inspect} in #{string.inspect} (#{values.inspect} given)" end end class ReservedInterpolationKey < ArgumentError attr_reader :key, :string def initialize(key, string) @key, @string = key, string super "reserved key #{key.inspect} used in #{string.inspect}" end end class UnknownFileType < ArgumentError attr_reader :type, :filename def initialize(type, filename) @type, @filename = type, filename super "can not load translations from #{filename}, the file type #{type} is not known" end end end i18n-1.8.11/lib/i18n/gettext.rb000066400000000000000000000014141414033570300157170ustar00rootroot00000000000000# frozen_string_literal: true module I18n module Gettext PLURAL_SEPARATOR = "\001" CONTEXT_SEPARATOR = "\004" autoload :Helpers, 'i18n/gettext/helpers' @@plural_keys = { :en => [:one, :other] } class << self # returns an array of plural keys for the given locale or the whole hash # of locale mappings to plural keys so that we can convert from gettext's # integer-index based style # TODO move this information to the pluralization module def plural_keys(*args) args.empty? ? @@plural_keys : @@plural_keys[args.first] || @@plural_keys[:en] end def extract_scope(msgid, separator) scope = msgid.to_s.split(separator) msgid = scope.pop [scope, msgid] end end end end i18n-1.8.11/lib/i18n/gettext/000077500000000000000000000000001414033570300153725ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/gettext/helpers.rb000066400000000000000000000050571414033570300173700ustar00rootroot00000000000000# frozen_string_literal: true require 'i18n/gettext' module I18n module Gettext # Implements classical Gettext style accessors. To use this include the # module to the global namespace or wherever you want to use it. # # include I18n::Gettext::Helpers module Helpers # Makes dynamic translation messages readable for the gettext parser. # _(fruit) cannot be understood by the gettext parser. To help the parser find all your translations, # you can add fruit = N_("Apple") which does not translate, but tells the parser: "Apple" needs translation. # * msgid: the message id. # * Returns: msgid. def N_(msgsid) msgsid end def gettext(msgid, options = EMPTY_HASH) I18n.t(msgid, **{:default => msgid, :separator => '|'}.merge(options)) end alias _ gettext def sgettext(msgid, separator = '|') scope, msgid = I18n::Gettext.extract_scope(msgid, separator) I18n.t(msgid, :scope => scope, :default => msgid, :separator => separator) end alias s_ sgettext def pgettext(msgctxt, msgid) separator = I18n::Gettext::CONTEXT_SEPARATOR sgettext([msgctxt, msgid].join(separator), separator) end alias p_ pgettext def ngettext(msgid, msgid_plural, n = 1) nsgettext(msgid, msgid_plural, n) end alias n_ ngettext # Method signatures: # nsgettext('Fruits|apple', 'apples', 2) # nsgettext(['Fruits|apple', 'apples'], 2) def nsgettext(msgid, msgid_plural, n = 1, separator = '|') if msgid.is_a?(Array) msgid, msgid_plural, n, separator = msgid[0], msgid[1], msgid_plural, n separator = '|' unless separator.is_a?(::String) end scope, msgid = I18n::Gettext.extract_scope(msgid, separator) default = { :one => msgid, :other => msgid_plural } I18n.t(msgid, :default => default, :count => n, :scope => scope, :separator => separator) end alias ns_ nsgettext # Method signatures: # npgettext('Fruits', 'apple', 'apples', 2) # npgettext('Fruits', ['apple', 'apples'], 2) def npgettext(msgctxt, msgid, msgid_plural, n = 1) separator = I18n::Gettext::CONTEXT_SEPARATOR if msgid.is_a?(Array) msgid_plural, msgid, n = msgid[1], [msgctxt, msgid[0]].join(separator), msgid_plural else msgid = [msgctxt, msgid].join(separator) end nsgettext(msgid, msgid_plural, n, separator) end alias np_ npgettext end end end i18n-1.8.11/lib/i18n/gettext/po_parser.rb000066400000000000000000000151051414033570300177130ustar00rootroot00000000000000=begin poparser.rb - Generate a .mo Copyright (C) 2003-2009 Masao Mutoh You may redistribute it and/or modify it under the same license terms as Ruby. =end #MODIFIED # removed include GetText etc # added stub translation method _(x) require 'racc/parser' module GetText class PoParser < Racc::Parser def _(x) x end module_eval <<'..end src/poparser.ry modeval..id7a99570e05', 'src/poparser.ry', 108 def unescape(orig) ret = orig.gsub(/\\n/, "\n") ret.gsub!(/\\t/, "\t") ret.gsub!(/\\r/, "\r") ret.gsub!(/\\"/, "\"") ret end def parse(str, data, ignore_fuzzy = true) @comments = [] @data = data @fuzzy = false @msgctxt = "" $ignore_fuzzy = ignore_fuzzy str.strip! @q = [] until str.empty? do case str when /\A\s+/ str = $' when /\Amsgctxt/ @q.push [:MSGCTXT, $&] str = $' when /\Amsgid_plural/ @q.push [:MSGID_PLURAL, $&] str = $' when /\Amsgid/ @q.push [:MSGID, $&] str = $' when /\Amsgstr/ @q.push [:MSGSTR, $&] str = $' when /\A\[(\d+)\]/ @q.push [:PLURAL_NUM, $1] str = $' when /\A\#~(.*)/ $stderr.print _("Warning: obsolete msgid exists.\n") $stderr.print " #{$&}\n" @q.push [:COMMENT, $&] str = $' when /\A\#(.*)/ @q.push [:COMMENT, $&] str = $' when /\A\"(.*)\"/ @q.push [:STRING, $1] str = $' else #c = str[0,1] #@q.push [:STRING, c] str = str[1..-1] end end @q.push [false, '$end'] if $DEBUG @q.each do |a,b| puts "[#{a}, #{b}]" end end @yydebug = true if $DEBUG do_parse if @comments.size > 0 @data.set_comment(:last, @comments.join("\n")) end @data end def next_token @q.shift end def on_message(msgid, msgstr) if msgstr.size > 0 @data[msgid] = msgstr @data.set_comment(msgid, @comments.join("\n")) end @comments.clear @msgctxt = "" end def on_comment(comment) @fuzzy = true if (/fuzzy/ =~ comment) @comments << comment end ..end src/poparser.ry modeval..id7a99570e05 ##### racc 1.4.5 generates ### racc_reduce_table = [ 0, 0, :racc_error, 0, 10, :_reduce_none, 2, 10, :_reduce_none, 2, 10, :_reduce_none, 2, 10, :_reduce_none, 2, 12, :_reduce_5, 1, 13, :_reduce_none, 1, 13, :_reduce_none, 4, 15, :_reduce_8, 5, 16, :_reduce_9, 2, 17, :_reduce_10, 1, 17, :_reduce_none, 3, 18, :_reduce_12, 1, 11, :_reduce_13, 2, 14, :_reduce_14, 1, 14, :_reduce_15 ] racc_reduce_n = 16 racc_shift_n = 26 racc_action_table = [ 3, 13, 5, 7, 9, 15, 16, 17, 20, 17, 13, 17, 13, 13, 11, 17, 23, 20, 13, 17 ] racc_action_check = [ 1, 16, 1, 1, 1, 12, 12, 12, 18, 18, 7, 14, 15, 9, 3, 19, 20, 21, 23, 25 ] racc_action_pointer = [ nil, 0, nil, 14, nil, nil, nil, 3, nil, 6, nil, nil, 0, nil, 4, 5, -6, nil, 2, 8, 8, 11, nil, 11, nil, 12 ] racc_action_default = [ -1, -16, -2, -16, -3, -13, -4, -16, -6, -16, -7, 26, -16, -15, -5, -16, -16, -14, -16, -8, -16, -9, -11, -16, -10, -12 ] racc_goto_table = [ 12, 22, 14, 4, 24, 6, 2, 8, 18, 19, 10, 21, 1, nil, nil, nil, 25 ] racc_goto_check = [ 5, 9, 5, 3, 9, 4, 2, 6, 5, 5, 7, 8, 1, nil, nil, nil, 5 ] racc_goto_pointer = [ nil, 12, 5, 2, 4, -7, 6, 9, -7, -17 ] racc_goto_default = [ nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ] racc_token_table = { false => 0, Object.new => 1, :COMMENT => 2, :MSGID => 3, :MSGCTXT => 4, :MSGID_PLURAL => 5, :MSGSTR => 6, :STRING => 7, :PLURAL_NUM => 8 } racc_use_result_var = true racc_nt_base = 9 Racc_arg = [ racc_action_table, racc_action_check, racc_action_default, racc_action_pointer, racc_goto_table, racc_goto_check, racc_goto_default, racc_goto_pointer, racc_nt_base, racc_reduce_table, racc_token_table, racc_shift_n, racc_reduce_n, racc_use_result_var ] Racc_token_to_s_table = [ '$end', 'error', 'COMMENT', 'MSGID', 'MSGCTXT', 'MSGID_PLURAL', 'MSGSTR', 'STRING', 'PLURAL_NUM', '$start', 'msgfmt', 'comment', 'msgctxt', 'message', 'string_list', 'single_message', 'plural_message', 'msgstr_plural', 'msgstr_plural_line'] Racc_debug_parser = true ##### racc system variables end ##### # reduce 0 omitted # reduce 1 omitted # reduce 2 omitted # reduce 3 omitted # reduce 4 omitted module_eval <<'.,.,', 'src/poparser.ry', 25 def _reduce_5( val, _values, result ) @msgctxt = unescape(val[1]) + "\004" result end .,., # reduce 6 omitted # reduce 7 omitted module_eval <<'.,.,', 'src/poparser.ry', 48 def _reduce_8( val, _values, result ) if @fuzzy and $ignore_fuzzy if val[1] != "" $stderr.print _("Warning: fuzzy message was ignored.\n") $stderr.print " msgid '#{val[1]}'\n" else on_message('', unescape(val[3])) end @fuzzy = false else on_message(@msgctxt + unescape(val[1]), unescape(val[3])) end result = "" result end .,., module_eval <<'.,.,', 'src/poparser.ry', 65 def _reduce_9( val, _values, result ) if @fuzzy and $ignore_fuzzy if val[1] != "" $stderr.print _("Warning: fuzzy message was ignored.\n") $stderr.print "msgid = '#{val[1]}\n" else on_message('', unescape(val[3])) end @fuzzy = false else on_message(@msgctxt + unescape(val[1]) + "\000" + unescape(val[3]), unescape(val[4])) end result = "" result end .,., module_eval <<'.,.,', 'src/poparser.ry', 76 def _reduce_10( val, _values, result ) if val[0].size > 0 result = val[0] + "\000" + val[1] else result = "" end result end .,., # reduce 11 omitted module_eval <<'.,.,', 'src/poparser.ry', 84 def _reduce_12( val, _values, result ) result = val[2] result end .,., module_eval <<'.,.,', 'src/poparser.ry', 91 def _reduce_13( val, _values, result ) on_comment(val[0]) result end .,., module_eval <<'.,.,', 'src/poparser.ry', 99 def _reduce_14( val, _values, result ) result = val.delete_if{|item| item == ""}.join result end .,., module_eval <<'.,.,', 'src/poparser.ry', 103 def _reduce_15( val, _values, result ) result = val[0] result end .,., def _reduce_none( val, _values, result ) result end end # class PoParser end # module GetText i18n-1.8.11/lib/i18n/interpolate/000077500000000000000000000000001414033570300162345ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/interpolate/ruby.rb000066400000000000000000000031021414033570300175360ustar00rootroot00000000000000# heavily based on Masao Mutoh's gettext String interpolation extension # http://github.com/mutoh/gettext/blob/f6566738b981fe0952548c421042ad1e0cdfb31e/lib/gettext/core_ext/string.rb module I18n DEFAULT_INTERPOLATION_PATTERNS = [ /%%/, /%\{([\w|]+)\}/, # matches placeholders like "%{foo} or %{foo|word}" /%<(\w+)>(.*?\d*\.?\d*[bBdiouxXeEfgGcps])/ # matches placeholders like "%.d" ].freeze INTERPOLATION_PATTERN = Regexp.union(DEFAULT_INTERPOLATION_PATTERNS) deprecate_constant :INTERPOLATION_PATTERN class << self # Return String or raises MissingInterpolationArgument exception. # Missing argument's logic is handled by I18n.config.missing_interpolation_argument_handler. def interpolate(string, values) raise ReservedInterpolationKey.new($1.to_sym, string) if string =~ RESERVED_KEYS_PATTERN raise ArgumentError.new('Interpolation values must be a Hash.') unless values.kind_of?(Hash) interpolate_hash(string, values) end def interpolate_hash(string, values) string.gsub(Regexp.union(config.interpolation_patterns)) do |match| if match == '%%' '%' else key = ($1 || $2 || match.tr("%{}", "")).to_sym value = if values.key?(key) values[key] else config.missing_interpolation_argument_handler.call(key, values, string) end value = value.call(values) if value.respond_to?(:call) $3 ? sprintf("%#{$3}", value) : value end end end end end i18n-1.8.11/lib/i18n/locale.rb000066400000000000000000000002351414033570300154720ustar00rootroot00000000000000# frozen_string_literal: true module I18n module Locale autoload :Fallbacks, 'i18n/locale/fallbacks' autoload :Tag, 'i18n/locale/tag' end end i18n-1.8.11/lib/i18n/locale/000077500000000000000000000000001414033570300151455ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/locale/fallbacks.rb000066400000000000000000000065121414033570300174200ustar00rootroot00000000000000# Locale Fallbacks # # Extends the I18n module to hold a fallbacks instance which is set to an # instance of I18n::Locale::Fallbacks by default but can be swapped with a # different implementation. # # Locale fallbacks will compute a number of fallback locales for a given locale. # For example: # #

# I18n.fallbacks[:"es-MX"] # => [:"es-MX", :es, :en] 
# # Locale fallbacks always fall back to # # * all parent locales of a given locale (e.g. :es for :"es-MX") first, # * the current default locales and all of their parents second # # The default locales are set to [I18n.default_locale] by default but can be # set to something else. # # One can additionally add any number of additional fallback locales manually. # These will be added before the default locales to the fallback chain. For # example: # # # using the default locale as default fallback locale # # I18n.default_locale = :"en-US" # I18n.fallbacks = I18n::Locale::Fallbacks.new(:"de-AT" => :"de-DE") # I18n.fallbacks[:"de-AT"] # => [:"de-AT", :de, :"de-DE"] # # # using a custom locale as default fallback locale # # I18n.fallbacks = I18n::Locale::Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de) # I18n.fallbacks[:"de-AT"] # => [:"de-AT", :de, :"en-GB", :en] # I18n.fallbacks[:"de-CH"] # => [:"de-CH", :de, :"en-GB", :en] # # # mapping fallbacks to an existing instance # # # people speaking Catalan also speak Spanish as spoken in Spain # fallbacks = I18n.fallbacks # fallbacks.map(:ca => :"es-ES") # fallbacks[:ca] # => [:ca, :"es-ES", :es, :"en-US", :en] # # # people speaking Arabian as spoken in Palestine also speak Hebrew as spoken in Israel # fallbacks.map(:"ar-PS" => :"he-IL") # fallbacks[:"ar-PS"] # => [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en] # fallbacks[:"ar-EG"] # => [:"ar-EG", :ar, :"en-US", :en] # # # people speaking Sami as spoken in Finland also speak Swedish and Finnish as spoken in Finland # fallbacks.map(:sms => [:"se-FI", :"fi-FI"]) # fallbacks[:sms] # => [:sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en] module I18n module Locale class Fallbacks < Hash def initialize(*mappings) @map = {} map(mappings.pop) if mappings.last.is_a?(Hash) self.defaults = mappings.empty? ? [] : mappings end def defaults=(defaults) @defaults = defaults.flat_map { |default| compute(default, false) } end attr_reader :defaults def [](locale) raise InvalidLocale.new(locale) if locale.nil? raise Disabled.new('fallback#[]') if locale == false locale = locale.to_sym super || store(locale, compute(locale)) end def map(mappings) mappings.each do |from, to| from, to = from.to_sym, Array(to) to.each do |_to| @map[from] ||= [] @map[from] << _to.to_sym end end end protected def compute(tags, include_defaults = true, exclude = []) result = Array(tags).flat_map do |tag| tags = I18n::Locale::Tag.tag(tag).self_and_parents.map! { |t| t.to_sym } - exclude tags.each { |_tag| tags += compute(@map[_tag], false, exclude + tags) if @map[_tag] } tags end result.push(*defaults) if include_defaults result.uniq! result.compact! result end end end end i18n-1.8.11/lib/i18n/locale/tag.rb000066400000000000000000000014521414033570300162470ustar00rootroot00000000000000# encoding: utf-8 module I18n module Locale module Tag autoload :Parents, 'i18n/locale/tag/parents' autoload :Rfc4646, 'i18n/locale/tag/rfc4646' autoload :Simple, 'i18n/locale/tag/simple' class << self # Returns the current locale tag implementation. Defaults to +I18n::Locale::Tag::Simple+. def implementation @@implementation ||= Simple end # Sets the current locale tag implementation. Use this to set a different locale tag implementation. def implementation=(implementation) @@implementation = implementation end # Factory method for locale tags. Delegates to the current locale tag implementation. def tag(tag) implementation.tag(tag) end end end end end i18n-1.8.11/lib/i18n/locale/tag/000077500000000000000000000000001414033570300157205ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/locale/tag/parents.rb000066400000000000000000000010131414033570300177140ustar00rootroot00000000000000module I18n module Locale module Tag module Parents def parent @parent ||= begin segs = to_a segs.compact! segs.length > 1 ? self.class.tag(*segs[0..(segs.length - 2)].join('-')) : nil end end def self_and_parents @self_and_parents ||= [self].concat parents end def parents @parents ||= parent ? [parent].concat(parent.parents) : [] end end end end end i18n-1.8.11/lib/i18n/locale/tag/rfc4646.rb000066400000000000000000000046631414033570300173540ustar00rootroot00000000000000# RFC 4646/47 compliant Locale tag implementation that parses locale tags to # subtags such as language, script, region, variant etc. # # For more information see by http://en.wikipedia.org/wiki/IETF_language_tag # # Rfc4646::Parser does not implement grandfathered tags. module I18n module Locale module Tag RFC4646_SUBTAGS = [ :language, :script, :region, :variant, :extension, :privateuse, :grandfathered ] RFC4646_FORMATS = { :language => :downcase, :script => :capitalize, :region => :upcase, :variant => :downcase } class Rfc4646 < Struct.new(*RFC4646_SUBTAGS) class << self # Parses the given tag and returns a Tag instance if it is valid. # Returns false if the given tag is not valid according to RFC 4646. def tag(tag) matches = parser.match(tag) new(*matches) if matches end def parser @@parser ||= Rfc4646::Parser end def parser=(parser) @@parser = parser end end include Parents RFC4646_FORMATS.each do |name, format| define_method(name) { self[name].send(format) unless self[name].nil? } end def to_sym to_s.to_sym end def to_s @tag ||= to_a.compact.join("-") end def to_a members.collect { |attr| self.send(attr) } end module Parser PATTERN = %r{\A(?: ([a-z]{2,3}(?:(?:-[a-z]{3}){0,3})?|[a-z]{4}|[a-z]{5,8}) # language (?:-([a-z]{4}))? # script (?:-([a-z]{2}|\d{3}))? # region (?:-([0-9a-z]{5,8}|\d[0-9a-z]{3}))* # variant (?:-([0-9a-wyz](?:-[0-9a-z]{2,8})+))* # extension (?:-(x(?:-[0-9a-z]{1,8})+))?| # privateuse subtag (x(?:-[0-9a-z]{1,8})+)| # privateuse tag /* ([a-z]{1,3}(?:-[0-9a-z]{2,8}){1,2}) */ # grandfathered )\z}xi class << self def match(tag) c = PATTERN.match(tag.to_s).captures c[0..4] << (c[5].nil? ? c[6] : c[5]) << c[7] # TODO c[7] is grandfathered, throw a NotImplemented exception here? rescue false end end end end end end end i18n-1.8.11/lib/i18n/locale/tag/simple.rb000066400000000000000000000012201414033570300175310ustar00rootroot00000000000000# Simple Locale tag implementation that computes subtags by simply splitting # the locale tag at '-' occurences. module I18n module Locale module Tag class Simple class << self def tag(tag) new(tag) end end include Parents attr_reader :tag def initialize(*tag) @tag = tag.join('-').to_sym end def subtags @subtags = tag.to_s.split('-').map!(&:to_s) end def to_sym tag end def to_s tag.to_s end def to_a subtags end end end end end i18n-1.8.11/lib/i18n/middleware.rb000066400000000000000000000003541414033570300163520ustar00rootroot00000000000000# frozen_string_literal: true module I18n class Middleware def initialize(app) @app = app end def call(env) @app.call(env) ensure Thread.current[:i18n_config] = I18n::Config.new end end end i18n-1.8.11/lib/i18n/tests.rb000066400000000000000000000007371414033570300154040ustar00rootroot00000000000000# frozen_string_literal: true module I18n module Tests autoload :Basics, 'i18n/tests/basics' autoload :Defaults, 'i18n/tests/defaults' autoload :Interpolation, 'i18n/tests/interpolation' autoload :Link, 'i18n/tests/link' autoload :Localization, 'i18n/tests/localization' autoload :Lookup, 'i18n/tests/lookup' autoload :Pluralization, 'i18n/tests/pluralization' autoload :Procs, 'i18n/tests/procs' end end i18n-1.8.11/lib/i18n/tests/000077500000000000000000000000001414033570300150505ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/tests/basics.rb000066400000000000000000000044111414033570300166410ustar00rootroot00000000000000module I18n module Tests module Basics def teardown I18n.available_locales = nil end test "available_locales returns the locales stored to the backend by default" do I18n.backend.store_translations('de', :foo => 'bar') I18n.backend.store_translations('en', :foo => 'foo') assert I18n.available_locales.include?(:de) assert I18n.available_locales.include?(:en) end test "available_locales can be set to something else independently from the actual locale data" do I18n.backend.store_translations('de', :foo => 'bar') I18n.backend.store_translations('en', :foo => 'foo') I18n.available_locales = :foo assert_equal [:foo], I18n.available_locales I18n.available_locales = [:foo, 'bar'] assert_equal [:foo, :bar], I18n.available_locales I18n.available_locales = nil assert I18n.available_locales.include?(:de) assert I18n.available_locales.include?(:en) end test "available_locales memoizes when set explicitely" do I18n.backend.expects(:available_locales).never I18n.available_locales = [:foo] I18n.backend.store_translations('de', :bar => 'baz') I18n.reload! assert_equal [:foo], I18n.available_locales end test "available_locales delegates to the backend when not set explicitely" do original_available_locales_value = I18n.backend.available_locales I18n.backend.expects(:available_locales).returns(original_available_locales_value).twice assert_equal I18n.backend.available_locales, I18n.available_locales end test "exists? is implemented by the backend" do I18n.backend.store_translations(:foo, :bar => 'baz') assert I18n.exists?(:bar, :foo) end test "storing a nil value as a translation removes it from the available locale data" do I18n.backend.store_translations(:en, :to_be_deleted => 'bar') assert_equal 'bar', I18n.t(:to_be_deleted, :default => 'baz') I18n.cache_store.clear if I18n.respond_to?(:cache_store) && I18n.cache_store I18n.backend.store_translations(:en, :to_be_deleted => nil) assert_equal 'baz', I18n.t(:to_be_deleted, :default => 'baz') end end end end i18n-1.8.11/lib/i18n/tests/defaults.rb000066400000000000000000000036621414033570300172130ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Defaults def setup super I18n.backend.store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' }) end test "defaults: given nil as a key it returns the given default" do assert_equal 'default', I18n.t(nil, :default => 'default') end test "defaults: given a symbol as a default it translates the symbol" do assert_equal 'bar', I18n.t(nil, :default => :'foo.bar') end test "defaults: given a symbol as a default and a scope it stays inside the scope when looking up the symbol" do assert_equal 'bar', I18n.t(:missing, :default => :bar, :scope => :foo) end test "defaults: given an array as a default it returns the first match" do assert_equal 'bar', I18n.t(:does_not_exist, :default => [:does_not_exist_2, :'foo.bar']) end test "defaults: given an array as a default with false it returns false" do assert_equal false, I18n.t(:does_not_exist, :default => [false]) end test "defaults: given false it returns false" do assert_equal false, I18n.t(:does_not_exist, :default => false) end test "defaults: given nil it returns nil" do assert_nil I18n.t(:does_not_exist, :default => nil) end test "defaults: given an array of missing keys it raises a MissingTranslationData exception" do assert_raise I18n::MissingTranslationData do I18n.t(:does_not_exist, :default => [:does_not_exist_2, :does_not_exist_3], :raise => true) end end test "defaults: using a custom scope separator" do # data must have been stored using the custom separator when using the ActiveRecord backend I18n.backend.store_translations(:en, { :foo => { :bar => 'bar' } }, { :separator => '|' }) assert_equal 'bar', I18n.t(nil, :default => :'foo|bar', :separator => '|') end end end end i18n-1.8.11/lib/i18n/tests/interpolation.rb000066400000000000000000000170041414033570300202660ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Interpolation # If no interpolation parameter is not given, I18n should not alter the string. # This behavior is due to three reasons: # # * Checking interpolation keys in all strings hits performance, badly; # # * This allows us to retrieve untouched values through I18n. For example # I could have a middleware that returns I18n lookup results in JSON # to be processed through Javascript. Leaving the keys untouched allows # the interpolation to happen at the javascript level; # # * Security concerns: if I allow users to translate a web site, they can # insert %{} in messages causing the I18n lookup to fail in every request. # test "interpolation: given no values it does not alter the string" do assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!') end test "interpolation: given values it interpolates them into the string" do assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => 'David') end test "interpolation: works with a pipe" do assert_equal 'Hi david!', interpolate(:default => 'Hi %{name|lowercase}!', :'name|lowercase' => 'david') end test "interpolation: given a nil value it still interpolates it into the string" do assert_equal 'Hi !', interpolate(:default => 'Hi %{name}!', :name => nil) end test "interpolation: given a lambda as a value it calls it if the string contains the key" do assert_equal 'Hi David!', interpolate(:default => 'Hi %{name}!', :name => lambda { |*args| 'David' }) end test "interpolation: given a lambda as a value it does not call it if the string does not contain the key" do assert_nothing_raised { interpolate(:default => 'Hi!', :name => lambda { |*args| raise 'fail' }) } end test "interpolation: given values but missing a key it raises I18n::MissingInterpolationArgument" do assert_raise(I18n::MissingInterpolationArgument) do interpolate(:default => '%{foo}', :bar => 'bar') end end test "interpolation: it does not raise I18n::MissingInterpolationArgument for escaped variables" do assert_nothing_raised do assert_equal 'Barr %{foo}', interpolate(:default => '%{bar} %%{foo}', :bar => 'Barr') end end test "interpolation: it does not change the original, stored translation string" do I18n.backend.store_translations(:en, :interpolate => 'Hi %{name}!') assert_equal 'Hi David!', interpolate(:interpolate, :name => 'David') assert_equal 'Hi Yehuda!', interpolate(:interpolate, :name => 'Yehuda') end test "interpolation: given an array interpolates each element" do I18n.backend.store_translations(:en, :array_interpolate => ['Hi', 'Mr. %{name}', 'or sir %{name}']) assert_equal ['Hi', 'Mr. Bartuz', 'or sir Bartuz'], interpolate(:array_interpolate, :name => 'Bartuz') end test "interpolation: given the translation is in utf-8 it still works" do assert_equal 'Häi David!', interpolate(:default => 'Häi %{name}!', :name => 'David') end test "interpolation: given the value is in utf-8 it still works" do assert_equal 'Hi ゆきひろ!', interpolate(:default => 'Hi %{name}!', :name => 'ゆきひろ') end test "interpolation: given the translation and the value are in utf-8 it still works" do assert_equal 'こんにちは、ゆきひろさん!', interpolate(:default => 'こんにちは、%{name}さん!', :name => 'ゆきひろ') end if Object.const_defined?(:Encoding) test "interpolation: given a euc-jp translation and a utf-8 value it raises Encoding::CompatibilityError" do assert_raise(Encoding::CompatibilityError) do interpolate(:default => euc_jp('こんにちは、%{name}さん!'), :name => 'ゆきひろ') end end test "interpolation: given a utf-8 translation and a euc-jp value it raises Encoding::CompatibilityError" do assert_raise(Encoding::CompatibilityError) do interpolate(:default => 'こんにちは、%{name}さん!', :name => euc_jp('ゆきひろ')) end end test "interpolation: ASCII strings in the backend should be encoded to UTF8 if interpolation options are in UTF8" do I18n.backend.store_translations 'en', 'encoding' => ('%{who} let me go'.force_encoding("ASCII")) result = I18n.t 'encoding', :who => "måmmå miå" assert_equal Encoding::UTF_8, result.encoding end test "interpolation: UTF8 strings in the backend are still returned as UTF8 with ASCII interpolation" do I18n.backend.store_translations 'en', 'encoding' => 'måmmå miå %{what}' result = I18n.t 'encoding', :what => 'let me go'.force_encoding("ASCII") assert_equal Encoding::UTF_8, result.encoding end test "interpolation: UTF8 strings in the backend are still returned as UTF8 even with numbers interpolation" do I18n.backend.store_translations 'en', 'encoding' => '%{count} times: måmmå miå' result = I18n.t 'encoding', :count => 3 assert_equal Encoding::UTF_8, result.encoding end end test "interpolation: given a translations containing a reserved key it raises I18n::ReservedInterpolationKey" do assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{exception_handler}') } assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{default}') } assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{separator}') } assert_raise(I18n::ReservedInterpolationKey) { interpolate(:foo => :bar, :default => '%{scope}') } end test "interpolation: deep interpolation for default string" do assert_equal 'Hi %{name}!', interpolate(:default => 'Hi %{name}!', :deep_interpolation => true) end test "interpolation: deep interpolation for interpolated string" do assert_equal 'Hi Ann!', interpolate(:default => 'Hi %{name}!', :name => 'Ann', :deep_interpolation => true) end test "interpolation: deep interpolation for Hash" do people = { :people => { :ann => 'Ann is %{ann}', :john => 'John is %{john}' } } interpolated_people = { :people => { :ann => 'Ann is good', :john => 'John is big' } } assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true) end test "interpolation: deep interpolation for Array" do people = { :people => ['Ann is %{ann}', 'John is %{john}'] } interpolated_people = { :people => ['Ann is good', 'John is big'] } assert_equal interpolated_people, interpolate(:default => people, :ann => 'good', :john => 'big', :deep_interpolation => true) end protected def capture(stream) begin stream = stream.to_s eval "$#{stream} = StringIO.new" yield result = eval("$#{stream}").string ensure eval("$#{stream} = #{stream.upcase}") end result end def euc_jp(string) string.encode!(Encoding::EUC_JP) end def interpolate(*args) options = args.last.is_a?(Hash) ? args.pop : {} key = args.pop I18n.backend.translate('en', key, options) end end end end i18n-1.8.11/lib/i18n/tests/link.rb000066400000000000000000000051121414033570300163310ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Link test "linked lookup: if a key resolves to a symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :link => :linked, :linked => 'linked' } assert_equal 'linked', I18n.backend.translate('en', :link) end test "linked lookup: if a key resolves to a dot-separated symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :link => :"foo.linked", :foo => { :linked => 'linked' } } assert_equal('linked', I18n.backend.translate('en', :link)) end test "linked lookup: if a dot-separated key resolves to a symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :foo => { :link => :linked }, :linked => 'linked' } assert_equal('linked', I18n.backend.translate('en', :'foo.link')) end test "linked lookup: if a dot-separated key resolves to a dot-separated symbol it looks up the symbol" do I18n.backend.store_translations 'en', { :foo => { :link => :"bar.linked" }, :bar => { :linked => 'linked' } } assert_equal('linked', I18n.backend.translate('en', :'foo.link')) end test "linked lookup: links always refer to the absolute key" do I18n.backend.store_translations 'en', { :foo => { :link => :linked, :linked => 'linked in foo' }, :linked => 'linked absolutely' } assert_equal 'linked absolutely', I18n.backend.translate('en', :link, :scope => :foo) end test "linked lookup: a link can resolve to a namespace in the middle of a dot-separated key" do I18n.backend.store_translations 'en', { :activemodel => { :errors => { :messages => { :blank => "can't be blank" } } }, :activerecord => { :errors => { :messages => :"activemodel.errors.messages" } } } assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank") assert_equal "can't be blank", I18n.t(:"activerecord.errors.messages.blank") end test "linked lookup: a link can resolve with option :count" do I18n.backend.store_translations 'en', { :counter => :counted, :counted => { :foo => { :one => "one", :other => "other" }, :bar => "bar" } } assert_equal "one", I18n.t(:'counter.foo', count: 1) assert_equal "other", I18n.t(:'counter.foo', count: 2) assert_equal "bar", I18n.t(:'counter.bar', count: 3) end end end end i18n-1.8.11/lib/i18n/tests/localization.rb000066400000000000000000000011131414033570300200610ustar00rootroot00000000000000module I18n module Tests module Localization autoload :Date, 'i18n/tests/localization/date' autoload :DateTime, 'i18n/tests/localization/date_time' autoload :Time, 'i18n/tests/localization/time' autoload :Procs, 'i18n/tests/localization/procs' def self.included(base) base.class_eval do include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Procs include I18n::Tests::Localization::Time end end end end endi18n-1.8.11/lib/i18n/tests/localization/000077500000000000000000000000001414033570300175405ustar00rootroot00000000000000i18n-1.8.11/lib/i18n/tests/localization/date.rb000066400000000000000000000117471414033570300210140ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Localization module Date def setup super setup_date_translations @date = ::Date.new(2008, 3, 1) end test "localize Date: given the short format it uses it" do assert_equal '01. Mär', I18n.l(@date, :format => :short, :locale => :de) end test "localize Date: given the long format it uses it" do assert_equal '01. März 2008', I18n.l(@date, :format => :long, :locale => :de) end test "localize Date: given the default format it uses it" do assert_equal '01.03.2008', I18n.l(@date, :format => :default, :locale => :de) end test "localize Date: given a day name format it returns the correct day name" do assert_equal 'Samstag', I18n.l(@date, :format => '%A', :locale => :de) end test "localize Date: given a uppercased day name format it returns the correct day name in upcase" do assert_equal 'samstag'.upcase, I18n.l(@date, :format => '%^A', :locale => :de) end test "localize Date: given an abbreviated day name format it returns the correct abbreviated day name" do assert_equal 'Sa', I18n.l(@date, :format => '%a', :locale => :de) end test "localize Date: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do assert_equal 'sa'.upcase, I18n.l(@date, :format => '%^a', :locale => :de) end test "localize Date: given a month name format it returns the correct month name" do assert_equal 'März', I18n.l(@date, :format => '%B', :locale => :de) end test "localize Date: given a uppercased month name format it returns the correct month name in upcase" do assert_equal 'märz'.upcase, I18n.l(@date, :format => '%^B', :locale => :de) end test "localize Date: given an abbreviated month name format it returns the correct abbreviated month name" do assert_equal 'Mär', I18n.l(@date, :format => '%b', :locale => :de) end test "localize Date: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do assert_equal 'mär'.upcase, I18n.l(@date, :format => '%^b', :locale => :de) end test "localize Date: given a date format with the month name upcased it returns the correct value" do assert_equal '1. FEBRUAR 2008', I18n.l(::Date.new(2008, 2, 1), :format => "%-d. %^B %Y", :locale => :de) end test "localize Date: given missing translations it returns the correct error message" do assert_equal 'translation missing: fr.date.abbr_month_names', I18n.l(@date, :format => '%b', :locale => :fr) end test "localize Date: given an unknown format it does not fail" do assert_nothing_raised { I18n.l(@date, :format => '%x') } end test "localize Date: does not modify the options hash" do options = { :format => '%b', :locale => :de } assert_equal 'Mär', I18n.l(@date, **options) assert_equal({ :format => '%b', :locale => :de }, options) assert_nothing_raised { I18n.l(@date, **options.freeze) } end test "localize Date: given nil with default value it returns default" do assert_equal 'default', I18n.l(nil, :default => 'default') end test "localize Date: given nil it raises I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l(nil) } end test "localize Date: given a plain Object it raises I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l(Object.new) } end test "localize Date: given a format is missing it raises I18n::MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.l(@date, :format => :missing) } end test "localize Date: it does not alter the format string" do assert_equal '01. Februar 2009', I18n.l(::Date.parse('2009-02-01'), :format => :long, :locale => :de) assert_equal '01. Oktober 2009', I18n.l(::Date.parse('2009-10-01'), :format => :long, :locale => :de) end protected def setup_date_translations I18n.backend.store_translations :de, { :date => { :formats => { :default => "%d.%m.%Y", :short => "%d. %b", :long => "%d. %B %Y", }, :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag), :abbr_day_names => %w(So Mo Di Mi Do Fr Sa), :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil), :abbr_month_names => %w(Jan Feb Mär Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil) } } end end end end end i18n-1.8.11/lib/i18n/tests/localization/date_time.rb000066400000000000000000000107731414033570300220300ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Localization module DateTime def setup super setup_datetime_translations @datetime = ::DateTime.new(2008, 3, 1, 6) @other_datetime = ::DateTime.new(2008, 3, 1, 18) end test "localize DateTime: given the short format it uses it" do assert_equal '01. Mär 06:00', I18n.l(@datetime, :format => :short, :locale => :de) end test "localize DateTime: given the long format it uses it" do assert_equal '01. März 2008 06:00', I18n.l(@datetime, :format => :long, :locale => :de) end test "localize DateTime: given the default format it uses it" do assert_equal 'Sa, 01. Mär 2008 06:00:00 +0000', I18n.l(@datetime, :format => :default, :locale => :de) end test "localize DateTime: given a day name format it returns the correct day name" do assert_equal 'Samstag', I18n.l(@datetime, :format => '%A', :locale => :de) end test "localize DateTime: given a uppercased day name format it returns the correct day name in upcase" do assert_equal 'samstag'.upcase, I18n.l(@datetime, :format => '%^A', :locale => :de) end test "localize DateTime: given an abbreviated day name format it returns the correct abbreviated day name" do assert_equal 'Sa', I18n.l(@datetime, :format => '%a', :locale => :de) end test "localize DateTime: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do assert_equal 'sa'.upcase, I18n.l(@datetime, :format => '%^a', :locale => :de) end test "localize DateTime: given a month name format it returns the correct month name" do assert_equal 'März', I18n.l(@datetime, :format => '%B', :locale => :de) end test "localize DateTime: given a uppercased month name format it returns the correct month name in upcase" do assert_equal 'märz'.upcase, I18n.l(@datetime, :format => '%^B', :locale => :de) end test "localize DateTime: given an abbreviated month name format it returns the correct abbreviated month name" do assert_equal 'Mär', I18n.l(@datetime, :format => '%b', :locale => :de) end test "localize DateTime: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do assert_equal 'mär'.upcase, I18n.l(@datetime, :format => '%^b', :locale => :de) end test "localize DateTime: given a date format with the month name upcased it returns the correct value" do assert_equal '1. FEBRUAR 2008', I18n.l(::DateTime.new(2008, 2, 1, 6), :format => "%-d. %^B %Y", :locale => :de) end test "localize DateTime: given missing translations it returns the correct error message" do assert_equal 'translation missing: fr.date.abbr_month_names', I18n.l(@datetime, :format => '%b', :locale => :fr) end test "localize DateTime: given a meridian indicator format it returns the correct meridian indicator" do assert_equal 'AM', I18n.l(@datetime, :format => '%p', :locale => :de) assert_equal 'PM', I18n.l(@other_datetime, :format => '%p', :locale => :de) end test "localize DateTime: given a meridian indicator format it returns the correct meridian indicator in downcase" do assert_equal 'am', I18n.l(@datetime, :format => '%P', :locale => :de) assert_equal 'pm', I18n.l(@other_datetime, :format => '%P', :locale => :de) end test "localize DateTime: given an unknown format it does not fail" do assert_nothing_raised { I18n.l(@datetime, :format => '%x') } end test "localize DateTime: given a format is missing it raises I18n::MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.l(@datetime, :format => :missing) } end protected def setup_datetime_translations # time translations might have been set up in Tests::Api::Localization::Time I18n.backend.store_translations :de, { :time => { :formats => { :default => "%a, %d. %b %Y %H:%M:%S %z", :short => "%d. %b %H:%M", :long => "%d. %B %Y %H:%M" }, :am => 'am', :pm => 'pm' } } end end end end end i18n-1.8.11/lib/i18n/tests/localization/procs.rb000066400000000000000000000130401414033570300212110ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Localization module Procs test "localize: using day names from lambdas" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_match(/Суббота/, I18n.l(time, :format => "%A, %d %B", :locale => :ru)) assert_match(/суббота/, I18n.l(time, :format => "%d %B (%A)", :locale => :ru)) end test "localize: using month names from lambdas" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_match(/марта/, I18n.l(time, :format => "%d %B %Y", :locale => :ru)) assert_match(/Март /, I18n.l(time, :format => "%B %Y", :locale => :ru)) end test "localize: using abbreviated day names from lambdas" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_match(/марта/, I18n.l(time, :format => "%d %b %Y", :locale => :ru)) assert_match(/март /, I18n.l(time, :format => "%b %Y", :locale => :ru)) end test "localize Date: given a format that resolves to a Proc it calls the Proc with the object" do setup_time_proc_translations date = ::Date.new(2008, 3, 1) assert_equal '[Sat, 01 Mar 2008, {}]', I18n.l(date, :format => :proc, :locale => :ru) end test "localize Date: given a format that resolves to a Proc it calls the Proc with the object and extra options" do setup_time_proc_translations date = ::Date.new(2008, 3, 1) assert_equal '[Sat, 01 Mar 2008, {:foo=>"foo"}]', I18n.l(date, :format => :proc, :foo => 'foo', :locale => :ru) end test "localize DateTime: given a format that resolves to a Proc it calls the Proc with the object" do setup_time_proc_translations datetime = ::DateTime.new(2008, 3, 1, 6) assert_equal '[Sat, 01 Mar 2008 06:00:00 +00:00, {}]', I18n.l(datetime, :format => :proc, :locale => :ru) end test "localize DateTime: given a format that resolves to a Proc it calls the Proc with the object and extra options" do setup_time_proc_translations datetime = ::DateTime.new(2008, 3, 1, 6) assert_equal '[Sat, 01 Mar 2008 06:00:00 +00:00, {:foo=>"foo"}]', I18n.l(datetime, :format => :proc, :foo => 'foo', :locale => :ru) end test "localize Time: given a format that resolves to a Proc it calls the Proc with the object" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) assert_equal I18n::Tests::Localization::Procs.inspect_args([time], {}), I18n.l(time, :format => :proc, :locale => :ru) end test "localize Time: given a format that resolves to a Proc it calls the Proc with the object and extra options" do setup_time_proc_translations time = ::Time.utc(2008, 3, 1, 6, 0) options = { :foo => 'foo' } assert_equal I18n::Tests::Localization::Procs.inspect_args([time], options), I18n.l(time, **options.merge(:format => :proc, :locale => :ru)) end protected def self.inspect_args(args, kwargs) args << kwargs args = args.map do |arg| case arg when ::Time, ::DateTime arg.strftime('%a, %d %b %Y %H:%M:%S %Z').sub('+0000', '+00:00') when ::Date arg.strftime('%a, %d %b %Y') when Hash arg.delete(:fallback_in_progress) arg.inspect else arg.inspect end end "[#{args.join(', ')}]" end def setup_time_proc_translations I18n.backend.store_translations :ru, { :time => { :formats => { :proc => lambda { |*args, **kwargs| I18n::Tests::Localization::Procs.inspect_args(args, kwargs) } } }, :date => { :formats => { :proc => lambda { |*args, **kwargs| I18n::Tests::Localization::Procs.inspect_args(args, kwargs) } }, :'day_names' => lambda { |key, options| (options[:format] =~ /^%A/) ? %w(Воскресенье Понедельник Вторник Среда Четверг Пятница Суббота) : %w(воскресенье понедельник вторник среда четверг пятница суббота) }, :'month_names' => lambda { |key, options| (options[:format] =~ /(%d|%e)(\s*)?(%B)/) ? %w(января февраля марта апреля мая июня июля августа сентября октября ноября декабря).unshift(nil) : %w(Январь Февраль Март Апрель Май Июнь Июль Август Сентябрь Октябрь Ноябрь Декабрь).unshift(nil) }, :'abbr_month_names' => lambda { |key, options| (options[:format] =~ /(%d|%e)(\s*)(%b)/) ? %w(янв. февр. марта апр. мая июня июля авг. сент. окт. нояб. дек.).unshift(nil) : %w(янв. февр. март апр. май июнь июль авг. сент. окт. нояб. дек.).unshift(nil) }, } } end end end end end i18n-1.8.11/lib/i18n/tests/localization/time.rb000066400000000000000000000105431414033570300210260ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Localization module Time def setup super setup_time_translations @time = ::Time.utc(2008, 3, 1, 6, 0) @other_time = ::Time.utc(2008, 3, 1, 18, 0) end test "localize Time: given the short format it uses it" do assert_equal '01. Mär 06:00', I18n.l(@time, :format => :short, :locale => :de) end test "localize Time: given the long format it uses it" do assert_equal '01. März 2008 06:00', I18n.l(@time, :format => :long, :locale => :de) end # TODO Seems to break on Windows because ENV['TZ'] is ignored. What's a better way to do this? # def test_localize_given_the_default_format_it_uses_it # assert_equal 'Sa, 01. Mar 2008 06:00:00 +0000', I18n.l(@time, :format => :default, :locale => :de) # end test "localize Time: given a day name format it returns the correct day name" do assert_equal 'Samstag', I18n.l(@time, :format => '%A', :locale => :de) end test "localize Time: given a uppercased day name format it returns the correct day name in upcase" do assert_equal 'samstag'.upcase, I18n.l(@time, :format => '%^A', :locale => :de) end test "localize Time: given an abbreviated day name format it returns the correct abbreviated day name" do assert_equal 'Sa', I18n.l(@time, :format => '%a', :locale => :de) end test "localize Time: given an abbreviated and uppercased day name format it returns the correct abbreviated day name in upcase" do assert_equal 'sa'.upcase, I18n.l(@time, :format => '%^a', :locale => :de) end test "localize Time: given a month name format it returns the correct month name" do assert_equal 'März', I18n.l(@time, :format => '%B', :locale => :de) end test "localize Time: given a uppercased month name format it returns the correct month name in upcase" do assert_equal 'märz'.upcase, I18n.l(@time, :format => '%^B', :locale => :de) end test "localize Time: given an abbreviated month name format it returns the correct abbreviated month name" do assert_equal 'Mär', I18n.l(@time, :format => '%b', :locale => :de) end test "localize Time: given an abbreviated and uppercased month name format it returns the correct abbreviated month name in upcase" do assert_equal 'mär'.upcase, I18n.l(@time, :format => '%^b', :locale => :de) end test "localize Time: given a date format with the month name upcased it returns the correct value" do assert_equal '1. FEBRUAR 2008', I18n.l(::Time.utc(2008, 2, 1, 6, 0), :format => "%-d. %^B %Y", :locale => :de) end test "localize Time: given missing translations it returns the correct error message" do assert_equal 'translation missing: fr.date.abbr_month_names', I18n.l(@time, :format => '%b', :locale => :fr) end test "localize Time: given a meridian indicator format it returns the correct meridian indicator" do assert_equal 'AM', I18n.l(@time, :format => '%p', :locale => :de) assert_equal 'PM', I18n.l(@other_time, :format => '%p', :locale => :de) end test "localize Time: given a meridian indicator format it returns the correct meridian indicator in upcase" do assert_equal 'am', I18n.l(@time, :format => '%P', :locale => :de) assert_equal 'pm', I18n.l(@other_time, :format => '%P', :locale => :de) end test "localize Time: given an unknown format it does not fail" do assert_nothing_raised { I18n.l(@time, :format => '%x') } end test "localize Time: given a format is missing it raises I18n::MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.l(@time, :format => :missing) } end protected def setup_time_translations I18n.backend.store_translations :de, { :time => { :formats => { :default => "%a, %d. %b %Y %H:%M:%S %z", :short => "%d. %b %H:%M", :long => "%d. %B %Y %H:%M", }, :am => 'am', :pm => 'pm' } } end end end end end i18n-1.8.11/lib/i18n/tests/lookup.rb000066400000000000000000000054611414033570300167140ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Lookup def setup super I18n.backend.store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' }, :falsy => false, :truthy => true, :string => "a", :array => %w(a b c), :hash => { "a" => "b" }) end test "lookup: it returns a string" do assert_equal("a", I18n.t(:string)) end test "lookup: it returns hash" do assert_equal({ :a => "b" }, I18n.t(:hash)) end test "lookup: it returns an array" do assert_equal(%w(a b c), I18n.t(:array)) end test "lookup: it returns a native true" do assert I18n.t(:truthy) === true end test "lookup: it returns a native false" do assert I18n.t(:falsy) === false end test "lookup: given a missing key, no default and no raise option it returns an error message" do assert_equal "translation missing: en.missing", I18n.t(:missing) end test "lookup: given a missing key, no default and the raise option it raises MissingTranslationData" do assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } end test "lookup: does not raise an exception if no translation data is present for the given locale" do assert_nothing_raised { I18n.t(:foo, :locale => :xx) } end test "lookup: does not modify the options hash" do options = {} assert_equal "a", I18n.t(:string, **options) assert_equal({}, options) assert_nothing_raised { I18n.t(:string, **options.freeze) } end test "lookup: given an array of keys it translates all of them" do assert_equal %w(bar baz), I18n.t([:bar, :baz], :scope => [:foo]) end test "lookup: using a custom scope separator" do # data must have been stored using the custom separator when using the ActiveRecord backend I18n.backend.store_translations(:en, { :foo => { :bar => 'bar' } }, { :separator => '|' }) assert_equal 'bar', I18n.t('foo|bar', :separator => '|') end # In fact it probably *should* fail but Rails currently relies on using the default locale instead. # So we'll stick to this for now until we get it fixed in Rails. test "lookup: given nil as a locale it does not raise but use the default locale" do # assert_raise(I18n::InvalidLocale) { I18n.t(:bar, :locale => nil) } assert_nothing_raised { I18n.t(:bar, :locale => nil) } end test "lookup: a resulting String is not frozen" do assert !I18n.t(:string).frozen? end test "lookup: a resulting Array is not frozen" do assert !I18n.t(:array).frozen? end test "lookup: a resulting Hash is not frozen" do assert !I18n.t(:hash).frozen? end end end end i18n-1.8.11/lib/i18n/tests/pluralization.rb000066400000000000000000000025201414033570300202710ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Pluralization test "pluralization: given 0 it returns the :zero translation if it is defined" do assert_equal 'zero', I18n.t(:default => { :zero => 'zero' }, :count => 0) end test "pluralization: given 0 it returns the :other translation if :zero is not defined" do assert_equal 'bars', I18n.t(:default => { :other => 'bars' }, :count => 0) end test "pluralization: given 1 it returns the singular translation" do assert_equal 'bar', I18n.t(:default => { :one => 'bar' }, :count => 1) end test "pluralization: given 2 it returns the :other translation" do assert_equal 'bars', I18n.t(:default => { :other => 'bars' }, :count => 2) end test "pluralization: given 3 it returns the :other translation" do assert_equal 'bars', I18n.t(:default => { :other => 'bars' }, :count => 3) end test "pluralization: given nil it returns the whole entry" do assert_equal({ :one => 'bar' }, I18n.t(:default => { :one => 'bar' }, :count => nil)) end test "pluralization: given incomplete pluralization data it raises I18n::InvalidPluralizationData" do assert_raise(I18n::InvalidPluralizationData) { I18n.t(:default => { :one => 'bar' }, :count => 2) } end end end end i18n-1.8.11/lib/i18n/tests/procs.rb000066400000000000000000000062411414033570300165260ustar00rootroot00000000000000# encoding: utf-8 module I18n module Tests module Procs test "lookup: given a translation is a proc it calls the proc with the key and interpolation values" do I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| I18n::Tests::Procs.filter_args(*args) }) assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(:a_lambda, :foo => 'foo') end test "lookup: given a translation is a proc it passes the interpolation values as keyword arguments" do I18n.backend.store_translations(:en, :a_lambda => lambda { |key, foo:, **| I18n::Tests::Procs.filter_args(key, foo: foo) }) assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(:a_lambda, :foo => 'foo') end test "defaults: given a default is a Proc it calls it with the key and interpolation values" do proc = lambda { |*args| I18n::Tests::Procs.filter_args(*args) } assert_equal '[nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo') end test "defaults: given a default is a key that resolves to a Proc it calls it with the key and interpolation values" do the_lambda = lambda { |*args| I18n::Tests::Procs.filter_args(*args) } I18n.backend.store_translations(:en, :a_lambda => the_lambda) assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => :a_lambda, :foo => 'foo') assert_equal '[:a_lambda, {:foo=>"foo"}]', I18n.t(nil, :default => [nil, :a_lambda], :foo => 'foo') end test "interpolation: given an interpolation value is a lambda it calls it with key and values before interpolating it" do proc = lambda { |*args| I18n::Tests::Procs.filter_args(*args) } assert_match %r(\[\{:foo=>#\}\]), I18n.t(nil, :default => '%{foo}', :foo => proc) end test "interpolation: given a key resolves to a Proc that returns a string then interpolation still works" do proc = lambda { |*args| "%{foo}: " + I18n::Tests::Procs.filter_args(*args) } assert_equal 'foo: [nil, {:foo=>"foo"}]', I18n.t(nil, :default => proc, :foo => 'foo') end test "pluralization: given a key resolves to a Proc that returns valid data then pluralization still works" do proc = lambda { |*args| { :zero => 'zero', :one => 'one', :other => 'other' } } assert_equal 'zero', I18n.t(:default => proc, :count => 0) assert_equal 'one', I18n.t(:default => proc, :count => 1) assert_equal 'other', I18n.t(:default => proc, :count => 2) end test "lookup: given the option :resolve => false was passed it does not resolve proc translations" do I18n.backend.store_translations(:en, :a_lambda => lambda { |*args| I18n::Tests::Procs.filter_args(*args) }) assert_equal Proc, I18n.t(:a_lambda, :resolve => false).class end test "lookup: given the option :resolve => false was passed it does not resolve proc default" do assert_equal Proc, I18n.t(nil, :default => lambda { |*args| I18n::Tests::Procs.filter_args(*args) }, :resolve => false).class end def self.filter_args(*args) args.map {|arg| arg.delete(:fallback_in_progress) if arg.is_a?(Hash) ; arg }.inspect end end end end i18n-1.8.11/lib/i18n/version.rb000066400000000000000000000001041414033570300157130ustar00rootroot00000000000000# frozen_string_literal: true module I18n VERSION = "1.8.11" end i18n-1.8.11/test/000077500000000000000000000000001414033570300133405ustar00rootroot00000000000000i18n-1.8.11/test/api/000077500000000000000000000000001414033570300141115ustar00rootroot00000000000000i18n-1.8.11/test/api/all_features_test.rb000066400000000000000000000031301414033570300201400ustar00rootroot00000000000000require 'test_helper' begin require 'rubygems' require 'active_support' rescue LoadError puts "not testing with Cache enabled because active_support can not be found" end class I18nAllFeaturesApiTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Metadata include I18n::Backend::Cache include I18n::Backend::Cascade include I18n::Backend::Fallbacks include I18n::Backend::Pluralization include I18n::Backend::Memoize end def setup I18n.backend = I18n::Backend::Chain.new(Backend.new, I18n::Backend::Simple.new) I18n.cache_store = cache_store super end def teardown I18n.cache_store.clear if I18n.cache_store I18n.cache_store = nil super end def cache_store ActiveSupport::Cache.lookup_store(:memory_store) if cache_available? end def cache_available? defined?(ActiveSupport) && defined?(ActiveSupport::Cache) end include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time include I18n::Tests::Localization::Procs test "make sure we use a Chain backend with an all features backend" do assert_equal I18n::Backend::Chain, I18n.backend.class assert_equal Backend, I18n.backend.backends.first.class end # links: test that keys stored on one backend can link to keys stored on another backend end i18n-1.8.11/test/api/cascade_test.rb000066400000000000000000000013201414033570300170540ustar00rootroot00000000000000require 'test_helper' class I18nCascadeApiTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Cascade end def setup I18n.backend = Backend.new super end include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time include I18n::Tests::Localization::Procs test "make sure we use a backend with Cascade included" do assert_equal Backend, I18n.backend.class end end i18n-1.8.11/test/api/chain_test.rb000066400000000000000000000012611414033570300165570ustar00rootroot00000000000000require 'test_helper' class I18nApiChainTest < I18n::TestCase def setup super I18n.backend = I18n::Backend::Chain.new(I18n::Backend::Simple.new, I18n.backend) end include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time include I18n::Tests::Localization::Procs test "make sure we use the Chain backend" do assert_equal I18n::Backend::Chain, I18n.backend.class end end i18n-1.8.11/test/api/fallbacks_test.rb000066400000000000000000000014621414033570300174220ustar00rootroot00000000000000require 'test_helper' class I18nFallbacksApiTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks end def setup I18n.backend = Backend.new super end include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time include I18n::Tests::Localization::Procs test "make sure we use a backend with Fallbacks included" do assert_equal Backend, I18n.backend.class end # links: test that keys stored on one backend can link to keys stored on another backend end i18n-1.8.11/test/api/key_value_test.rb000066400000000000000000000012671414033570300174670ustar00rootroot00000000000000require 'test_helper' class I18nKeyValueApiTest < I18n::TestCase include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization # include Tests::Api::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time # include Tests::Api::Localization::Procs def setup I18n.backend = I18n::Backend::KeyValue.new({}) super end test "make sure we use the KeyValue backend" do assert_equal I18n::Backend::KeyValue, I18n.backend.class end end if I18n::TestCase.key_value? i18n-1.8.11/test/api/memoize_test.rb000066400000000000000000000027661414033570300171550ustar00rootroot00000000000000require 'test_helper' class I18nMemoizeBackendWithSimpleApiTest < I18n::TestCase include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time include I18n::Tests::Localization::Procs class MemoizeBackend < I18n::Backend::Simple include I18n::Backend::Memoize end def setup I18n.backend = MemoizeBackend.new super end test "make sure we use the MemoizeBackend backend" do assert_equal MemoizeBackend, I18n.backend.class end end class I18nMemoizeBackendWithKeyValueApiTest < I18n::TestCase include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time # include I18n::Tests::Procs # include I18n::Tests::Localization::Procs class MemoizeBackend < I18n::Backend::KeyValue include I18n::Backend::Memoize end def setup I18n.backend = MemoizeBackend.new({}) super end test "make sure we use the MemoizeBackend backend" do assert_equal MemoizeBackend, I18n.backend.class end end if I18n::TestCase.key_value? i18n-1.8.11/test/api/override_test.rb000066400000000000000000000022421414033570300173140ustar00rootroot00000000000000require 'test_helper' class I18nOverrideTest < I18n::TestCase module OverrideInverse def translate(key, **options) super(key, **options).reverse end alias :t :translate end module OverrideSignature def translate(*args) args.first + args[1] end alias :t :translate end def setup super @I18n = I18n.dup @I18n.backend = I18n::Backend::Simple.new end test "make sure modules can overwrite I18n methods" do @I18n.extend OverrideInverse @I18n.backend.store_translations('en', :foo => 'bar') assert_equal 'rab', @I18n.translate(:foo, :locale => 'en') assert_equal 'rab', @I18n.t(:foo, :locale => 'en') assert_equal 'rab', @I18n.translate!(:foo, :locale => 'en') assert_equal 'rab', @I18n.t!(:foo, :locale => 'en') end test "make sure modules can overwrite I18n signature" do exception = catch(:exception) do @I18n.t('Hello', :tokenize => true, :throw => true) end assert exception.message @I18n.extend OverrideSignature assert_equal 'HelloWelcome message on home page', @I18n.translate('Hello', 'Welcome message on home page', :tokenize => true) # tr8n example end end i18n-1.8.11/test/api/pluralization_test.rb000066400000000000000000000014761414033570300204020ustar00rootroot00000000000000require 'test_helper' class I18nPluralizationApiTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Pluralization end def setup I18n.backend = Backend.new super end include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time include I18n::Tests::Localization::Procs test "make sure we use a backend with Pluralization included" do assert_equal Backend, I18n.backend.class end # links: test that keys stored on one backend can link to keys stored on another backend end i18n-1.8.11/test/api/simple_test.rb000066400000000000000000000013531414033570300167700ustar00rootroot00000000000000require 'test_helper' class I18nSimpleBackendApiTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Pluralization end def setup I18n.backend = I18n::Backend::Simple.new super end include I18n::Tests::Basics include I18n::Tests::Defaults include I18n::Tests::Interpolation include I18n::Tests::Link include I18n::Tests::Lookup include I18n::Tests::Pluralization include I18n::Tests::Procs include I18n::Tests::Localization::Date include I18n::Tests::Localization::DateTime include I18n::Tests::Localization::Time include I18n::Tests::Localization::Procs test "make sure we use the Simple backend" do assert_equal I18n::Backend::Simple, I18n.backend.class end end i18n-1.8.11/test/backend/000077500000000000000000000000001414033570300147275ustar00rootroot00000000000000i18n-1.8.11/test/backend/cache_file_test.rb000066400000000000000000000046501414033570300203620ustar00rootroot00000000000000require 'test_helper' require 'fileutils' require 'tempfile' module CountWrites attr_reader :writes def initialize(*args) super @writes = [] end def store_translations(*args) super.tap { @writes << args } end end module CacheFileTest test 'load_translations caches loaded file contents' do setup_backend! I18n.load_path = [locales_dir + '/en.yml'] assert_equal 0, @backend.writes.count @backend.load_translations unless @backend.is_a?(I18n::Backend::Simple) assert_equal('baz', I18n.t('foo.bar')) assert_equal 2, @backend.writes.count @backend.load_translations assert_equal('baz', I18n.t('foo.bar')) assert_equal 2, @backend.writes.count end test 'setting path_roots normalizes write key' do setup_backend! I18n.load_path = [locales_dir + '/en.yml'] @backend.path_roots = [locales_dir] @backend.load_translations refute_nil I18n.t("0/en\x01yml", scope: :load_file, locale: :i18n, default: nil) end test 'load_translations caches file through updated modification time' do setup_backend! Tempfile.open(['test', '.yml']) do |file| I18n.load_path = [file.path] File.write(file, { :en => { :foo => { :bar => 'baz' } } }.to_yaml) assert_equal 0, @backend.writes.count @backend.load_translations unless @backend.is_a?(I18n::Backend::Simple) assert_equal('baz', I18n.t('foo.bar')) assert_equal 2, @backend.writes.count FileUtils.touch(file, :mtime => Time.now + 1) @backend.load_translations assert_equal('baz', I18n.t('foo.bar')) assert_equal 2, @backend.writes.count File.write(file, { :en => { :foo => { :bar => 'baa' } } }.to_yaml) FileUtils.touch(file, :mtime => Time.now + 1) @backend.load_translations assert_equal('baa', I18n.t('foo.bar')) assert_equal 4, @backend.writes.count end end end class SimpleCacheFileTest < I18n::TestCase include CacheFileTest class Backend < I18n::Backend::Simple include CountWrites include I18n::Backend::CacheFile end def setup_backend! @backend = I18n.backend = Backend.new end end class KeyValueCacheFileTest < I18n::TestCase include CacheFileTest class Backend < I18n::Backend::KeyValue include CountWrites include I18n::Backend::CacheFile def initialize super({}) end end def setup_backend! @backend = I18n.backend = Backend.new end end if I18n::TestCase.key_value? i18n-1.8.11/test/backend/cache_test.rb000066400000000000000000000063221414033570300173610ustar00rootroot00000000000000require 'test_helper' require 'openssl' begin require 'active_support' rescue LoadError $stderr.puts "Skipping cache tests using ActiveSupport" else class I18nBackendCacheTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Cache end def setup I18n.backend = Backend.new super I18n.cache_store = ActiveSupport::Cache.lookup_store(:memory_store) I18n.cache_store.clear I18n.cache_key_digest = nil end def teardown super I18n.cache_store.clear I18n.cache_store = nil end test "it uses the cache" do assert I18n.cache_store.is_a?(ActiveSupport::Cache::MemoryStore) end test "translate hits the backend and caches the response" do I18n.backend.expects(:lookup).returns('Foo') assert_equal 'Foo', I18n.t(:foo) I18n.backend.expects(:lookup).never assert_equal 'Foo', I18n.t(:foo) I18n.backend.expects(:lookup).returns('Bar') assert_equal 'Bar', I18n.t(:bar) end test "translate returns a cached false response" do I18n.backend.expects(:lookup).never I18n.cache_store.expects(:read).returns(false) assert_equal false, I18n.t(:foo) end test "still raises MissingTranslationData but also caches it" do assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } assert_equal 1, I18n.cache_store.instance_variable_get(:@data).size # I18n.backend.expects(:lookup).returns(nil) # assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } # I18n.backend.expects(:lookup).never # assert_raise(I18n::MissingTranslationData) { I18n.t(:missing, :raise => true) } end test "uses 'i18n' as a cache key namespace by default" do assert_equal 0, I18n.backend.send(:cache_key, :en, :foo, {}).index('i18n') end test "adds a custom cache key namespace" do with_cache_namespace('bar') do assert_equal 0, I18n.backend.send(:cache_key, :en, :foo, {}).index('i18n/bar/') end end test "adds locale and hash of key and hash of options" do options = { :bar => 1 } assert_equal "i18n//en/#{:foo.to_s.hash}/#{options.to_s.hash}", I18n.backend.send(:cache_key, :en, :foo, options) end test "cache_key uses configured digest method" do digest = OpenSSL::Digest::SHA256.new options = { :bar => 1 } options_hash = options.inspect with_cache_key_digest(digest) do assert_equal "i18n//en/#{digest.hexdigest(:foo.to_s)}/#{digest.hexdigest(options_hash)}", I18n.backend.send(:cache_key, :en, :foo, options) end end test "keys should not be equal" do interpolation_values1 = { :foo => 1, :bar => 2 } interpolation_values2 = { :foo => 2, :bar => 1 } key1 = I18n.backend.send(:cache_key, :en, :some_key, interpolation_values1) key2 = I18n.backend.send(:cache_key, :en, :some_key, interpolation_values2) assert key1 != key2 end protected def with_cache_namespace(namespace) I18n.cache_namespace = namespace yield I18n.cache_namespace = nil end def with_cache_key_digest(digest) I18n.cache_key_digest = digest yield I18n.cache_key_digest = nil end end end # AS cache check i18n-1.8.11/test/backend/cascade_test.rb000066400000000000000000000070501414033570300177000ustar00rootroot00000000000000require 'test_helper' class I18nBackendCascadeTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Cascade end def setup super I18n.backend = Backend.new store_translations(:en, :foo => 'foo', :bar => { :baz => 'baz' }) @cascade_options = { :step => 1, :offset => 1, :skip_root => false } end def lookup(key, options = {}) I18n.t(key, **options.merge(:cascade => @cascade_options)) end test "still returns an existing translation as usual" do assert_equal 'foo', lookup(:foo) assert_equal 'baz', lookup(:'bar.baz') end test "falls back by cutting keys off the end of the scope" do assert_equal 'foo', lookup(:foo, :scope => :'missing') assert_equal 'foo', lookup(:foo, :scope => :'missing.missing') assert_equal 'baz', lookup(:baz, :scope => :'bar.missing') assert_equal 'baz', lookup(:baz, :scope => :'bar.missing.missing') end test "raises I18n::MissingTranslationData exception when no translation was found" do assert_raise(I18n::MissingTranslationData) { lookup(:'foo.missing', :raise => true) } assert_raise(I18n::MissingTranslationData) { lookup(:'bar.baz.missing', :raise => true) } assert_raise(I18n::MissingTranslationData) { lookup(:'missing.bar.baz', :raise => true) } end test "cascades before evaluating the default" do assert_equal 'foo', lookup(:foo, :scope => :missing, :default => 'default') end test "cascades defaults, too" do assert_equal 'foo', lookup(nil, :default => [:'missing.missing', :'missing.foo']) end test "works with :offset => 2 and a single key" do @cascade_options[:offset] = 2 lookup(:foo) end test "assemble required fallbacks for ActiveRecord validation messages" do store_translations(:en, :errors => { :odd => 'errors.odd', :reply => { :title => { :blank => 'errors.reply.title.blank' }, :taken => 'errors.reply.taken' }, :topic => { :title => { :format => 'errors.topic.title.format' }, :length => 'errors.topic.length' } } ) assert_equal 'errors.reply.title.blank', lookup(:'errors.reply.title.blank', :default => :'errors.topic.title.blank') assert_equal 'errors.reply.taken', lookup(:'errors.reply.title.taken', :default => :'errors.topic.title.taken') assert_equal 'errors.topic.title.format', lookup(:'errors.reply.title.format', :default => :'errors.topic.title.format') assert_equal 'errors.topic.length', lookup(:'errors.reply.title.length', :default => :'errors.topic.title.length') assert_equal 'errors.odd', lookup(:'errors.reply.title.odd', :default => :'errors.topic.title.odd') end test "assemble action view translation helper lookup cascade" do @cascade_options[:offset] = 2 store_translations(:en, :menu => { :show => 'menu.show' }, :namespace => { :menu => { :new => 'namespace.menu.new' }, :controller => { :menu => { :edit => 'namespace.controller.menu.edit' }, :action => { :menu => { :destroy => 'namespace.controller.action.menu.destroy' } } } } ) assert_equal 'menu.show', lookup(:'namespace.controller.action.menu.show') assert_equal 'namespace.menu.new', lookup(:'namespace.controller.action.menu.new') assert_equal 'namespace.controller.menu.edit', lookup(:'namespace.controller.action.menu.edit') assert_equal 'namespace.controller.action.menu.destroy', lookup(:'namespace.controller.action.menu.destroy') end end i18n-1.8.11/test/backend/chain_test.rb000066400000000000000000000134111414033570300173750ustar00rootroot00000000000000require 'test_helper' class I18nBackendChainTest < I18n::TestCase def setup super @first = backend(:en => { :foo => 'Foo', :formats => { :short => 'short', :subformats => {:short => 'short'}, }, :plural_1 => { :one => '%{count}' }, :dates => {:a => "A"}, :fallback_bar => nil, }) @second = backend(:en => { :bar => 'Bar', :formats => { :long => 'long', :subformats => {:long => 'long'}, }, :plural_2 => { :one => 'one' }, :dates => {:a => "B", :b => "B"}, :fallback_bar => 'Bar', }) @chain = I18n.backend = I18n::Backend::Chain.new(@first, @second) end test "looks up translations from the first chained backend" do assert_equal 'Foo', @first.send(:translations)[:en][:foo] assert_equal 'Foo', I18n.t(:foo) end test "looks up translations from the second chained backend" do assert_equal 'Bar', @second.send(:translations)[:en][:bar] assert_equal 'Bar', I18n.t(:bar) end test "defaults only apply to lookups on the last backend in the chain" do assert_equal 'Foo', I18n.t(:foo, :default => 'Bah') assert_equal 'Bar', I18n.t(:bar, :default => 'Bah') assert_equal 'Bah', I18n.t(:bah, :default => 'Bah') # default kicks in only here end test "default" do assert_equal 'Fuh', I18n.t(:default => 'Fuh') assert_equal 'Zero', I18n.t(:default => { :zero => 'Zero' }, :count => 0) assert_equal({ :zero => 'Zero' }, I18n.t(:default => { :zero => 'Zero' })) assert_equal 'Foo', I18n.t(:default => :foo) end test 'default is returned if translation is missing' do assert_equal({}, I18n.t(:'i18n.transliterate.rule', :locale => 'en', :default => {})) end test "namespace lookup collects results from all backends and merges deep hashes" do assert_equal({:long=>"long", :subformats=>{:long=>"long", :short=>"short"}, :short=>"short"}, I18n.t(:formats)) end test "namespace lookup collects results from all backends and lets leftmost backend take priority" do assert_equal({ :a => "A", :b => "B" }, I18n.t(:dates)) end test "namespace lookup with only the first backend returning a result" do assert_equal({ :one => '%{count}' }, I18n.t(:plural_1)) end test "pluralization still works" do assert_equal '1', I18n.t(:plural_1, :count => 1) assert_equal 'one', I18n.t(:plural_2, :count => 1) end test "bulk lookup collects results from all backends" do assert_equal ['Foo', 'Bar'], I18n.t([:foo, :bar]) assert_equal ['Foo', 'Bar', 'Bah'], I18n.t([:foo, :bar, :bah], :default => 'Bah') assert_equal [{ :long=>"long", :subformats=>{:long=>"long", :short=>"short"}, :short=>"short"}, {:one=>"one"}, "Bah"], I18n.t([:formats, :plural_2, :bah], :default => 'Bah') end test "store_translations options are not dropped while transfering to backend" do @first.expects(:store_translations).with(:foo, {:bar => :baz}, {:option => 'persists'}) I18n.backend.store_translations :foo, {:bar => :baz}, {:option => 'persists'} end test 'store should call initialize on all backends and return true if all initialized' do @first.send :init_translations @second.send :init_translations assert I18n.backend.initialized? end test 'store should call initialize on all backends and return false if one not initialized' do @first.reload! @second.send :init_translations assert !I18n.backend.initialized? end test 'should reload all backends' do @first.send :init_translations @second.send :init_translations I18n.backend.reload! assert !@first.initialized? assert !@second.initialized? end test 'should eager load all backends' do I18n.backend.eager_load! assert @first.initialized? assert @second.initialized? end test "falls back to other backends for nil values" do assert_nil @first.send(:translations)[:en][:fallback_bar] assert_equal 'Bar', @second.send(:translations)[:en][:fallback_bar] assert_equal 'Bar', I18n.t(:fallback_bar) end test 'should be able to get all translations of all backends merged together' do expected = { en: { foo: 'Foo', bar: 'Bar', formats: { short: 'short', long: 'long', subformats: { short: 'short', long: 'long' } }, plural_1: { one: "%{count}" }, plural_2: { one: 'one' }, dates: { a: 'A', b: 'B' }, fallback_bar: 'Bar' } } assert_equal expected, I18n.backend.send(:translations) end protected def backend(translations) backend = I18n::Backend::Simple.new translations.each { |locale, data| backend.store_translations(locale, data) } backend end end class I18nBackendChainWithKeyValueTest < I18n::TestCase def setup_backend!(subtrees = true) first = I18n::Backend::KeyValue.new({}, subtrees) first.store_translations(:en, :plural_1 => { :one => '%{count}' }) second = I18n::Backend::Simple.new second.store_translations(:en, :plural_2 => { :one => 'one' }) I18n.backend = I18n::Backend::Chain.new(first, second) end test "subtrees enabled: looks up pluralization translations from the first chained backend" do setup_backend! assert_equal '1', I18n.t(:plural_1, count: 1) end test "subtrees disabled: looks up pluralization translations from the first chained backend" do setup_backend!(false) assert_equal '1', I18n.t(:plural_1, count: 1) end test "subtrees enabled: looks up translations from the second chained backend" do setup_backend! assert_equal 'one', I18n.t(:plural_2, count: 1) end test "subtrees disabled: looks up translations from the second chained backend" do setup_backend!(false) assert_equal 'one', I18n.t(:plural_2, count: 1) end end if I18n::TestCase.key_value? i18n-1.8.11/test/backend/exceptions_test.rb000066400000000000000000000026271414033570300205030ustar00rootroot00000000000000require 'test_helper' class I18nBackendExceptionsTest < I18n::TestCase def setup super I18n.backend = I18n::Backend::Simple.new end test "throw message: MissingTranslation message from #translate includes the given scope and full key" do exception = catch(:exception) do I18n.t(:'baz.missing', :scope => :'foo.bar', :throw => true) end assert_equal "translation missing: en.foo.bar.baz.missing", exception.message end test "exceptions: MissingTranslationData message from #translate includes the given scope and full key" do begin I18n.t(:'baz.missing', :scope => :'foo.bar', :raise => true) rescue I18n::MissingTranslationData => exception end assert_equal "translation missing: en.foo.bar.baz.missing", exception.message end test "exceptions: MissingTranslationData message from #localize includes the given scope and full key" do begin I18n.l(Time.now, :format => :foo) rescue I18n::MissingTranslationData => exception end assert_equal "translation missing: en.time.formats.foo", exception.message end test "exceptions: MissingInterpolationArgument message includes missing key, provided keys and full string" do exception = I18n::MissingInterpolationArgument.new('key', {:this => 'was given'}, 'string') assert_equal 'missing interpolation argument "key" in "string" ({:this=>"was given"} given)', exception.message end end i18n-1.8.11/test/backend/fallbacks_test.rb000066400000000000000000000317521414033570300202450ustar00rootroot00000000000000require 'test_helper' class I18nBackendFallbacksTranslateTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks end def setup super I18n.backend = Backend.new store_translations(:en, :foo => 'Foo in :en', :bar => 'Bar in :en', :buz => 'Buz in :en', :interpolate => 'Interpolate %{value}', :interpolate_count => 'Interpolate %{value} %{count}') store_translations(:de, :bar => 'Bar in :de', :baz => 'Baz in :de') store_translations(:'de-DE', :baz => 'Baz in :de-DE') store_translations(:'pt-BR', :baz => 'Baz in :pt-BR') end test "still returns an existing translation as usual" do assert_equal 'Foo in :en', I18n.t(:foo, :locale => :en) assert_equal 'Bar in :de', I18n.t(:bar, :locale => :de) assert_equal 'Baz in :de-DE', I18n.t(:baz, :locale => :'de-DE') end test "returns interpolated value if no key provided" do assert_equal 'Interpolate %{value}', I18n.t(:interpolate) end test "returns the :de translation for a missing :'de-DE' translation" do assert_equal 'Bar in :de', I18n.t(:bar, :locale => :'de-DE') end test "keeps the count option when defaulting to a different key" do assert_equal 'Interpolate 5 10', I18n.t(:non_existant, default: :interpolate_count, count: 10, value: 5) end test "returns the :de translation for a missing :'de-DE' when :default is a String" do assert_equal 'Bar in :de', I18n.t(:bar, :locale => :'de-DE', :default => "Default Bar") assert_equal "Default Bar", I18n.t(:missing_bar, :locale => :'de-DE', :default => "Default Bar") end test "returns the :de translation for a missing :'de-DE' when defaults is a Symbol (which exists in :en)" do assert_equal "Bar in :de", I18n.t(:bar, :locale => :'de-DE', :default => [:buz]) end test "returns the :'de-DE' default :baz translation for a missing :'de-DE' (which exists in :de)" do assert_equal "Baz in :de-DE", I18n.t(:bar, :locale => :'de-DE', :default => [:baz]) end test "returns the :de translation for a missing :'de-DE' when :default is a Proc" do assert_equal 'Bar in :de', I18n.t(:bar, :locale => :'de-DE', :default => Proc.new { "Default Bar" }) assert_equal "Default Bar", I18n.t(:missing_bar, :locale => :'de-DE', :default => Proc.new { "Default Bar" }) end test "returns the :de translation for a missing :'de-DE' when :default is a Hash" do assert_equal 'Bar in :de', I18n.t(:bar, :locale => :'de-DE', :default => {}) assert_equal({}, I18n.t(:missing_bar, :locale => :'de-DE', :default => {})) end test "returns the :de translation for a missing :'de-DE' when :default is nil" do assert_equal 'Bar in :de', I18n.t(:bar, :locale => :'de-DE', :default => nil) assert_nil I18n.t(:missing_bar, :locale => :'de-DE', :default => nil) end test "returns the translation missing message if the default is also missing" do assert_equal 'translation missing: de-DE.missing_bar', I18n.t(:missing_bar, :locale => :'de-DE', :default => [:missing_baz]) end test "returns the :'de-DE' default :baz translation for a missing :'de-DE' when defaults contains Symbol" do assert_equal 'Baz in :de-DE', I18n.t(:missing_foo, :locale => :'de-DE', :default => [:baz, "Default Bar"]) end test "returns the defaults translation for a missing :'de-DE' when defaults contains a String or Proc before Symbol" do assert_equal "Default Bar", I18n.t(:missing_foo, :locale => :'de-DE', :default => [:missing_bar, "Default Bar", :baz]) assert_equal "Default Bar", I18n.t(:missing_foo, :locale => :'de-DE', :default => [:missing_bar, Proc.new { "Default Bar" }, :baz]) end test "returns the default translation for a missing :'de-DE' and existing :de when default is a Hash" do assert_equal 'Default 6 Bars', I18n.t(:missing_foo, :locale => :'de-DE', :default => [:missing_bar, {:other => "Default %{count} Bars"}, "Default Bar"], :count => 6) end test "returns the default translation for a missing :de translation even when default is a String when fallback is disabled" do assert_equal 'Default String', I18n.t(:foo, :locale => :de, :default => 'Default String', :fallback => false) end test "raises I18n::MissingTranslationData exception when fallback is disabled even when fallback translation exists" do assert_raise(I18n::MissingTranslationData) { I18n.t(:foo, :locale => :de, :fallback => false, :raise => true) } end test "raises I18n::MissingTranslationData exception when no translation was found" do assert_raise(I18n::MissingTranslationData) { I18n.t(:faa, :locale => :en, :raise => true) } assert_raise(I18n::MissingTranslationData) { I18n.t(:faa, :locale => :de, :raise => true) } end test "should ensure that default is not splitted on new line char" do assert_equal "Default \n Bar", I18n.t(:missing_bar, :default => "Default \n Bar") end test "should not raise error when enforce_available_locales is true, :'pt' is missing and default is a Symbol" do I18n.enforce_available_locales = true begin assert_equal 'Foo', I18n.t(:'model.attrs.foo', :locale => :'pt-BR', :default => [:'attrs.foo', "Foo"]) ensure I18n.enforce_available_locales = false end end test "returns fallback default given missing pluralization data" do assert_equal 'default', I18n.t(:missing_bar, count: 1, default: 'default') assert_equal 'default', I18n.t(:missing_bar, count: 0, default: 'default') end test "multi-threaded fallbacks" do I18n.fallbacks = [:en] thread = Thread.new do I18n.fallbacks = [:de] end begin thread.join assert_equal 'Bar in :en', I18n.t(:bar, :locale => :'pt-BR') ensure thread.exit I18n.fallbacks = I18n::Locale::Fallbacks.new end end end # See Issue #534 class I18nBackendFallbacksLocalizeTestWithDefaultLocale < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks end def setup super I18n.backend = Backend.new I18n.enforce_available_locales = false I18n.fallbacks = [I18n.default_locale] store_translations(:en, time: { formats: { fallback: 'en fallback' } }) end test "falls back to default locale - Issue #534" do assert_equal 'en fallback', I18n.l(Time.now, format: :fallback, locale: "un-supported") end end # See Issue #536 class I18nBackendFallbacksWithCustomClass < I18n::TestCase class BackendWithFallbacks < I18n::Backend::Simple include I18n::Backend::Fallbacks end # Quacks like a fallback class class MyDefaultFallback def [](key) [:my_language] end end def setup super I18n.backend = BackendWithFallbacks.new I18n.enforce_available_locales = false I18n.fallbacks = MyDefaultFallback.new store_translations(:my_language, foo: 'customer foo') store_translations(:en, foo: 'english foo') end test "can use a default fallback object that doesn't inherit from I18n::Locale::Fallbacks" do assert_equal 'customer foo', I18n.t(:foo, locale: :en) assert_equal 'customer foo', I18n.t(:foo, locale: :nothing) end end # See Issue #546 class I18nBackendFallbacksLocalizeTestWithMultipleThreads < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks end def setup super I18n.backend = Backend.new I18n.enforce_available_locales = false I18n.fallbacks = [I18n.default_locale] store_translations(:en, time: { formats: { fallback: 'en fallback' } }) end test "falls back to default locale - Issue #546" do Thread.new { assert_equal 'en fallback', I18n.l(Time.now, format: :fallback, locale: "un-supported") }.join end end class I18nBackendFallbacksLocalizeTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks end def setup super I18n.backend = Backend.new store_translations(:en, :date => { :formats => { :en => 'en' }, :day_names => %w(Sunday) }) store_translations(:de, :date => { :formats => { :de => 'de' }, :day_names => %w(Sunday) }) end test "still uses an existing format as usual" do assert_equal 'en', I18n.l(Date.today, :format => :en, :locale => :en) end test "looks up and uses a fallback locale's format for a key missing in the given locale" do assert_equal 'de', I18n.l(Date.today, :format => :de, :locale => :'de-DE') end test "still uses an existing day name translation as usual" do assert_equal 'Sunday', I18n.l(Date.new(2010, 1, 3), :format => '%A', :locale => :en) end test "uses a fallback locale's translation for a key missing in the given locale" do assert_equal 'Sunday', I18n.l(Date.new(2010, 1, 3), :format => '%A', :locale => :'de-DE') end end class I18nBackendFallbacksWithChainTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks end class Chain < I18n::Backend::Chain include I18n::Backend::Fallbacks end def setup super backend = Backend.new backend.store_translations(:de, :foo => 'FOO') backend.store_translations(:'pt-BR', :foo => 'Baz in :pt-BR') I18n.backend = Chain.new(I18n::Backend::Simple.new, backend) end test "falls back from de-DE to de when there is no translation for de-DE available" do assert_equal 'FOO', I18n.t(:foo, :locale => :'de-DE') end test "exists? falls back from de-DE to de given a key missing from the given locale" do assert_equal true, I18n.exists?(:foo, :locale => :'de-DE') end test "exists? should return false when fallback disabled given a key missing from the given locale" do assert_equal false, I18n.exists?(:foo, :locale => :'de-DE', fallback: false) end test "falls back from de-DE to de when there is no translation for de-DE available when using arrays, too" do assert_equal ['FOO', 'FOO'], I18n.t([:foo, :foo], :locale => :'de-DE') end test "should not raise error when enforce_available_locales is true, :'pt' is missing and default is a Symbol" do I18n.enforce_available_locales = true begin assert_equal 'Foo', I18n.t(:'model.attrs.foo', :locale => :'pt-BR', :default => [:'attrs.foo', "Foo"]) ensure I18n.enforce_available_locales = false end end end class I18nBackendFallbacksExistsTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks end def setup super I18n.backend = Backend.new store_translations(:en, :foo => 'Foo in :en', :bar => 'Bar in :en') store_translations(:de, :bar => 'Bar in :de') store_translations(:'de-DE', :baz => 'Baz in :de-DE') end test "exists? given an existing key will return true" do assert_equal true, I18n.exists?(:foo) end test "exists? given a non-existing key will return false" do assert_equal false, I18n.exists?(:bogus) end test "exists? given an existing key and an existing locale will return true" do assert_equal true, I18n.exists?(:foo, :en) assert_equal true, I18n.exists?(:bar, :de) end test "exists? given a non-existing key and an existing locale will return false" do assert_equal false, I18n.exists?(:bogus, :en) assert_equal false, I18n.exists?(:bogus, :de) end test "exists? should return true given a key which is missing from the given locale and exists in a fallback locale" do assert_equal true, I18n.exists?(:bar, :de) assert_equal true, I18n.exists?(:bar, :'de-DE') end test "exists? should return false given a key which is missing from the given locale and all its fallback locales" do assert_equal false, I18n.exists?(:baz, :de) assert_equal false, I18n.exists?(:bogus, :'de-DE') end test "exists? should return false when fallback is disabled given a key which is missing from the given locale" do assert_equal true, I18n.exists?(:bar, :'de-DE') assert_equal false, I18n.exists?(:bar, :'de-DE', fallback: false) assert_equal false, I18n.exists?(:bar, :'de-DE-XX', fallback: false) end end class I18nBackendOnFallbackHookTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Fallbacks attr :fallback_collector private def on_fallback(*args) @fallback_collector ||= [] @fallback_collector << args end end def setup super I18n.backend = Backend.new I18n.fallbacks = I18n::Locale::Fallbacks.new(de: :en) store_translations(:en, :foo => 'Foo in :en', :bar => 'Bar in :en') store_translations(:de, :bar => 'Bar in :de') store_translations(:"de-DE", :baz => 'Baz in :"de-DE"') end test "on_fallback should be called when fallback happens" do assert_equal [:"de-DE", :de, :en], I18n.fallbacks[:"de-DE"] assert_equal 'Baz in :"de-DE"', I18n.t(:baz, locale: :'de-DE') assert_equal 'Bar in :de', I18n.t(:bar, locale: :'de-DE') assert_equal 'Foo in :en', I18n.t(:foo, locale: :'de-DE') assert_equal [:'de-DE', :de, :bar, {}], I18n.backend.fallback_collector[0] assert_equal [:'de-DE', :en, :foo, {}], I18n.backend.fallback_collector[1] end test "on_fallback should not be called when use a String locale" do assert_equal 'Bar in :de', I18n.t("bar", locale: "de") assert I18n.backend.fallback_collector.nil? end end i18n-1.8.11/test/backend/interpolation_compiler_test.rb000066400000000000000000000107671414033570300231070ustar00rootroot00000000000000require 'test_helper' class InterpolationCompilerTest < I18n::TestCase Compiler = I18n::Backend::InterpolationCompiler::Compiler def compile_and_interpolate(str, values = {}) Compiler.compile_if_an_interpolation(str).i18n_interpolate(values) end def assert_escapes_interpolation_key(expected, malicious_str) assert_equal(expected, Compiler.send(:escape_key_sym, malicious_str)) end def test_escape_key_properly_escapes assert_escapes_interpolation_key ':"\""', '"' assert_escapes_interpolation_key ':"\\\\"', '\\' assert_escapes_interpolation_key ':"\\\\\""', '\\"' assert_escapes_interpolation_key ':"\#{}"', '#{}' assert_escapes_interpolation_key ':"\\\\\#{}"', '\#{}' end def assert_escapes_plain_string(expected, plain_str) assert_equal expected, Compiler.send(:escape_plain_str, plain_str) end def test_escape_plain_string_properly_escapes assert_escapes_plain_string '\\"', '"' assert_escapes_plain_string '\'', '\'' assert_escapes_plain_string '\\#', '#' assert_escapes_plain_string '\\#{}', '#{}' assert_escapes_plain_string '\\\\\\"','\\"' end def test_non_interpolated_strings_or_arrays_dont_get_compiled ['abc', '\\{a}}', '{a}}', []].each do |obj| Compiler.compile_if_an_interpolation(obj) assert_equal false, obj.respond_to?(:i18n_interpolate) end end def test_interpolated_string_gets_compiled assert_equal '-A-', compile_and_interpolate('-%{a}-', :a => 'A') end def assert_handles_key(str, key) assert_equal 'A', compile_and_interpolate(str, key => 'A') end def test_compiles_fancy_keys assert_handles_key('%{\}', :'\\' ) assert_handles_key('%{#}', :'#' ) assert_handles_key('%{#{}', :'#{' ) assert_handles_key('%{#$SAFE}', :'#$SAFE') assert_handles_key('%{\000}', :'\000' ) assert_handles_key('%{\'}', :'\'' ) assert_handles_key('%{\'\'}', :'\'\'' ) assert_handles_key('%{a.b}', :'a.b' ) assert_handles_key('%{ }', :' ' ) assert_handles_key('%{:}', :':' ) assert_handles_key("%{:''}", :":''" ) assert_handles_key('%{:"}', :':"' ) end def test_str_containing_only_escaped_interpolation_is_handled_correctly assert_equal 'abc %{x}', compile_and_interpolate('abc %%{x}') end def test_handles_weird_strings assert_equal '#{} a', compile_and_interpolate('#{} %{a}', :a => 'a') assert_equal '"#{abc}"', compile_and_interpolate('"#{ab%{a}c}"', :a => '' ) assert_equal 'a}', compile_and_interpolate('%{{a}}', :'{a' => 'a') assert_equal '"', compile_and_interpolate('"%{a}', :a => '' ) assert_equal 'a%{a}', compile_and_interpolate('%{a}%%{a}', :a => 'a') assert_equal '%%{a}', compile_and_interpolate('%%%{a}') assert_equal '\";eval("a")', compile_and_interpolate('\";eval("%{a}")', :a => 'a') assert_equal '\";eval("a")', compile_and_interpolate('\";eval("a")%{a}', :a => '' ) assert_equal "\na", compile_and_interpolate("\n%{a}", :a => 'a') end def test_raises_exception_when_argument_is_missing assert_raise(I18n::MissingInterpolationArgument) do compile_and_interpolate('%{first} %{last}', :first => 'first') end end def test_custom_missing_interpolation_argument_handler old_handler = I18n.config.missing_interpolation_argument_handler I18n.config.missing_interpolation_argument_handler = lambda do |key, values, string| "missing key is #{key}, values are #{values.inspect}, given string is '#{string}'" end assert_equal %|first missing key is last, values are {:first=>"first"}, given string is '%{first} %{last}'|, compile_and_interpolate('%{first} %{last}', :first => 'first') ensure I18n.config.missing_interpolation_argument_handler = old_handler end end class I18nBackendInterpolationCompilerTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::InterpolationCompiler end include I18n::Tests::Interpolation def setup I18n.backend = Backend.new super end # pre-compile default strings to make sure we are testing I18n::Backend::InterpolationCompiler def interpolate(*args) options = args.last.kind_of?(Hash) ? args.last : {} if default_str = options[:default] I18n::Backend::InterpolationCompiler::Compiler.compile_if_an_interpolation(default_str) end super end end i18n-1.8.11/test/backend/key_value_test.rb000066400000000000000000000075301414033570300203040ustar00rootroot00000000000000require 'test_helper' class I18nBackendKeyValueTest < I18n::TestCase def setup_backend!(subtree=true) I18n.backend = I18n::Backend::KeyValue.new({}, subtree) store_translations(:en, :foo => { :bar => 'bar', :baz => 'baz' }) end def assert_flattens(expected, nested, escape=true, subtree=true) assert_equal expected, I18n.backend.flatten_translations("en", nested, escape, subtree) end test "hash flattening works" do setup_backend! assert_flattens( {:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}, :"b.f" => {:x=>"x"}, :"b.c"=>"c", :"b.f.x"=>"x", :"b.d"=>"d"}, {:a=>'a', :b=>{:c=>'c', :d=>'d', :f=>{:x=>'x'}}} ) assert_flattens({:a=>{:b =>['a', 'b']}, :"a.b"=>['a', 'b']}, {:a=>{:b =>['a', 'b']}}) assert_flattens({:"a\001b" => "c"}, {:"a.b" => "c"}) assert_flattens({:"a.b"=>['a', 'b']}, {:a=>{:b =>['a', 'b']}}, true, false) assert_flattens({:"a.b" => "c"}, {:"a.b" => "c"}, false) end test "store_translations supports numeric keys" do setup_backend! store_translations(:en, 1 => 'foo') assert_equal 'foo', I18n.t('1') assert_equal 'foo', I18n.t(1) assert_equal 'foo', I18n.t(:'1') end test "store_translations handle subtrees by default" do setup_backend! assert_equal({ :bar => 'bar', :baz => 'baz' }, I18n.t("foo")) end test "store_translations merge subtrees accordingly" do setup_backend! store_translations(:en, :foo => { :baz => "BAZ"}) assert_equal('BAZ', I18n.t("foo.baz")) assert_equal({ :bar => 'bar', :baz => 'BAZ' }, I18n.t("foo")) end test "store_translations does not handle subtrees if desired" do setup_backend!(false) assert_raise I18n::MissingTranslationData do I18n.t("foo", :raise => true) end end test 'initialized? checks that a store is available' do setup_backend! I18n.backend.reload! assert_equal I18n.backend.initialized?, true end test 'translations gets the translations from the store' do setup_backend! I18n.backend.send(:translations) expected = { :en => {:foo => { :bar => 'bar', :baz => 'baz' }} } assert_equal expected, translations end test "subtrees enabled: given incomplete pluralization data it raises I18n::InvalidPluralizationData" do setup_backend! store_translations(:en, :bar => { :one => "One" }) assert_raise(I18n::InvalidPluralizationData) { I18n.t(:bar, :count => 2) } end test "subtrees disabled: given incomplete pluralization data it returns an error message" do setup_backend!(false) store_translations(:en, :bar => { :one => "One" }) assert_equal "translation missing: en.bar", I18n.t(:bar, :count => 2) end test "translate handles subtrees for pluralization" do setup_backend!(false) store_translations(:en, :bar => { :one => "One" }) assert_equal("One", I18n.t("bar", :count => 1)) end test "subtrees enabled: returns localized string given missing pluralization data" do setup_backend!(true) assert_equal 'bar', I18n.t("foo.bar", count: 1) end test "subtrees disabled: returns localized string given missing pluralization data" do setup_backend!(false) assert_equal 'bar', I18n.t("foo.bar", count: 1) end test "subtrees enabled: Returns fallback default given missing pluralization data" do setup_backend!(true) I18n.backend.extend I18n::Backend::Fallbacks assert_equal 'default', I18n.t(:missing_bar, count: 1, default: 'default') assert_equal 'default', I18n.t(:missing_bar, count: 0, default: 'default') end test "subtrees disabled: Returns fallback default given missing pluralization data" do setup_backend!(false) I18n.backend.extend I18n::Backend::Fallbacks assert_equal 'default', I18n.t(:missing_bar, count: 1, default: 'default') assert_equal 'default', I18n.t(:missing_bar, count: 0, default: 'default') end end if I18n::TestCase.key_value? i18n-1.8.11/test/backend/memoize_test.rb000066400000000000000000000045271414033570300177700ustar00rootroot00000000000000require 'test_helper' require 'backend/simple_test' class I18nBackendMemoizeTest < I18nBackendSimpleTest module MemoizeSpy attr_accessor :spy_calls def available_locales self.spy_calls = (self.spy_calls || 0) + 1 super end end class MemoizeBackend < I18n::Backend::Simple include MemoizeSpy include I18n::Backend::Memoize end def setup super I18n.backend = MemoizeBackend.new end def test_memoizes_available_locales I18n.backend.spy_calls = 0 assert_equal I18n.available_locales, I18n.available_locales assert_equal 1, I18n.backend.spy_calls end def test_resets_available_locales_on_reload! I18n.available_locales I18n.backend.spy_calls = 0 I18n.reload! assert_equal I18n.available_locales, I18n.available_locales assert_equal 1, I18n.backend.spy_calls end def test_resets_available_locales_on_store_translations I18n.available_locales I18n.backend.spy_calls = 0 I18n.backend.store_translations(:copa, :ca => :bana) assert_equal I18n.available_locales, I18n.available_locales assert I18n.available_locales.include?(:copa) assert_equal 1, I18n.backend.spy_calls end def test_eager_load I18n.eager_load! I18n.backend.spy_calls = 0 assert_equal I18n.available_locales, I18n.available_locales assert_equal 0, I18n.backend.spy_calls end module TestLookup def lookup(locale, key, scope = [], options = {}) keys = I18n.normalize_keys(locale, key, scope, options[:separator]) keys.inspect end end def test_lookup_concurrent_consistency backend_impl = Class.new(I18n::Backend::Simple) do include TestLookup include I18n::Backend::Memoize end backend = backend_impl.new memoized_lookup = backend.send(:memoized_lookup) assert_equal "[:foo, :scoped, :sample]", backend.translate('foo', scope = [:scoped, :sample]) 30.times.inject([]) do |memo, i| memo << Thread.new do backend.translate('bar', scope); backend.translate(:baz, scope) end end.each(&:join) memoized_lookup = backend.send(:memoized_lookup) puts memoized_lookup.inspect if $VERBOSE assert_equal 3, memoized_lookup.size, "NON-THREAD-SAFE lookup memoization backend: #{memoized_lookup.class}" # if a plain Hash is used might eventually end up in a weird (inconsistent) state end end i18n-1.8.11/test/backend/metadata_test.rb000066400000000000000000000032021414033570300200700ustar00rootroot00000000000000require 'test_helper' class I18nBackendMetadataTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Metadata end def setup super I18n.backend = Backend.new store_translations(:en, :foo => 'Hi %{name}') end test "translation strings carry metadata" do translation = I18n.t(:foo, :name => 'David') assert translation.respond_to?(:translation_metadata) assert translation.translation_metadata.is_a?(Hash) end test "translate adds the locale to metadata on Strings" do assert_equal :en, I18n.t(:foo, :name => 'David', :locale => :en).translation_metadata[:locale] end test "translate adds the key to metadata on Strings" do assert_equal :foo, I18n.t(:foo, :name => 'David').translation_metadata[:key] end test "translate adds the default to metadata on Strings" do assert_equal 'bar', I18n.t(:foo, :default => 'bar', :name => '').translation_metadata[:default] end test "translation adds the interpolation values to metadata on Strings" do assert_equal({:name => 'David'}, I18n.t(:foo, :name => 'David').translation_metadata[:values]) end test "interpolation adds the original string to metadata on Strings" do assert_equal('Hi %{name}', I18n.t(:foo, :name => 'David').translation_metadata[:original]) end test "pluralization adds the count to metadata on Strings" do assert_equal(1, I18n.t(:missing, :count => 1, :default => { :one => 'foo' }).translation_metadata[:count]) end test "metadata works with frozen values" do assert_equal(1, I18n.t(:missing, :count => 1, :default => 'foo'.freeze).translation_metadata[:count]) end end i18n-1.8.11/test/backend/pluralization_fallback_test.rb000066400000000000000000000047321414033570300230350ustar00rootroot00000000000000require 'test_helper' class I18nBackendPluralizationFallbackTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Pluralization include I18n::Backend::Fallbacks end def setup super I18n.default_locale = :'en' I18n.backend = Backend.new store_translations('en', cat: { zero: 'cat', one: 'cat', other: 'cats' }) store_translations('en-US', cat: { zero: 'no cat', one: nil, other: 'lots of cats' }) store_translations('ru', cat: { one: 'кот', few: 'кошек', many: 'кошка', other: 'кошек' }) # probably not a real locale but just to demonstrate store_translations('ru-US', cat: { one: nil, few: nil, many: nil, other: nil }) store_translations('ru', i18n: { plural: { rule: russian_rule }}) end test "fallbacks: nils are ignored and fallback is applied" do assert_equal "no cat", I18n.t("cat", count: 0, locale: "en-US") assert_equal "cat", I18n.t("cat", count: 0, locale: "en") assert_equal "cat", I18n.t("cat", count: 1, locale: "en-US") assert_equal "cat", I18n.t("cat", count: 1, locale: "en") assert_equal "lots of cats", I18n.t("cat", count: 2, locale: "en-US") assert_equal "cats", I18n.t("cat", count: 2, locale: "en") end test "fallbacks: nils are ignored and fallback is applied, with custom rule" do # more specs: https://github.com/svenfuchs/rails-i18n/blob/master/spec/unit/pluralization/east_slavic.rb assert_equal "кошка", I18n.t("cat", count: 0, locale: "ru") assert_equal "кошка", I18n.t("cat", count: 0, locale: "ru-US") assert_equal "кот", I18n.t("cat", count: 1, locale: "ru") assert_equal "кот", I18n.t("cat", count: 1, locale: "ru-US") assert_equal "кошек", I18n.t("cat", count: 2, locale: "ru") assert_equal "кошек", I18n.t("cat", count: 2, locale: "ru-US") assert_equal "кошек", I18n.t("cat", count: 1.5, locale: "ru") assert_equal "кошек", I18n.t("cat", count: 1.5, locale: "ru-US") end private # copied from https://github.com/svenfuchs/rails-i18n/blob/master/lib/rails_i18n/common_pluralizations/east_slavic.rb def russian_rule lambda do |n| n ||= 0 mod10 = n % 10 mod100 = n % 100 if mod10 == 1 && mod100 != 11 :one elsif (2..4).include?(mod10) && !(12..14).include?(mod100) :few elsif mod10 == 0 || (5..9).include?(mod10) || (11..14).include?(mod100) :many else :other end end end end i18n-1.8.11/test/backend/pluralization_scope_test.rb000066400000000000000000000022261414033570300224030ustar00rootroot00000000000000require 'test_helper' class I18nBackendPluralizationScopeTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Pluralization include I18n::Backend::Fallbacks end def setup super I18n.default_locale = :'en' I18n.backend = Backend.new translations = { i18n: { plural: { keys: [:one, :other], rule: lambda { |n| n == 1 ? :one : :other }, } }, activerecord: { models: { my_model: { one: 'one model', other: 'more models', some_other_key: { key: 'value' } } } } } store_translations('en', translations) end test "pluralization picks :other for 2" do args = { scope: [:activerecord, :models], count: 2, default: ["My model"] } assert_equal 'more models', I18n.translate(:my_model, **args) end test "pluralization picks :one for 1" do args = { scope: [:activerecord, :models], count: 1, default: ["My model"] } assert_equal 'one model', I18n.translate(:my_model, **args) end end i18n-1.8.11/test/backend/pluralization_test.rb000066400000000000000000000034701414033570300212140ustar00rootroot00000000000000require 'test_helper' class I18nBackendPluralizationTest < I18n::TestCase class Backend < I18n::Backend::Simple include I18n::Backend::Pluralization include I18n::Backend::Fallbacks end def setup super I18n.backend = Backend.new @rule = lambda { |n| n == 1 ? :one : n == 0 || (2..10).include?(n % 100) ? :few : (11..19).include?(n % 100) ? :many : :other } store_translations(:xx, :i18n => { :plural => { :rule => @rule } }) @entry = { :zero => 'zero', :one => 'one', :few => 'few', :many => 'many', :other => 'other' } end test "pluralization picks a pluralizer from :'i18n.pluralize'" do assert_equal @rule, I18n.backend.send(:pluralizer, :xx) end test "pluralization picks :one for 1" do assert_equal 'one', I18n.t(:count => 1, :default => @entry, :locale => :xx) end test "pluralization picks :few for 2" do assert_equal 'few', I18n.t(:count => 2, :default => @entry, :locale => :xx) end test "pluralization picks :many for 11" do assert_equal 'many', I18n.t(:count => 11, :default => @entry, :locale => :xx) end test "pluralization picks zero for 0 if the key is contained in the data" do assert_equal 'zero', I18n.t(:count => 0, :default => @entry, :locale => :xx) end test "pluralization picks few for 0 if the key is not contained in the data" do @entry.delete(:zero) assert_equal 'few', I18n.t(:count => 0, :default => @entry, :locale => :xx) end test "pluralization picks one for 1 if the entry has attributes hash on unknown locale" do @entry[:attributes] = { :field => 'field', :second => 'second' } assert_equal 'one', I18n.t(:count => 1, :default => @entry, :locale => :pirate) end test "Fallbacks can pick up rules from fallback locales, too" do assert_equal @rule, I18n.backend.send(:pluralizer, :'xx-XX') end end i18n-1.8.11/test/backend/simple_test.rb000066400000000000000000000150171414033570300176100ustar00rootroot00000000000000require 'test_helper' class I18nBackendSimpleTest < I18n::TestCase def setup super I18n.backend = I18n::Backend::Simple.new I18n.load_path = [locales_dir + '/en.yml'] end # useful because this way we can use the backend with no key for interpolation/pluralization test "simple backend translate: given nil as a key it still interpolations the default value" do assert_equal "Hi David", I18n.t(nil, :default => "Hi %{name}", :name => "David") end test "simple backend translate: given true as a key" do store_translations :en, available: { true => "Yes", false => "No" } assert_equal "Yes", I18n.t(:available)[true] assert_equal "No", I18n.t(:available)[false] end test "simple backend translate: given integer as a key" do store_translations :en, available: { 1 => "Yes", 2 => "No" } assert_equal "Yes", I18n.t(:available)[1] assert_equal "Yes", I18n.t('available.1') end test 'simple backend translate: given integer with a lead zero as a key' do store_translations :en, available: { '01' => 'foo' } assert_equal 'foo', I18n.t(:available)[:'01'] assert_equal 'foo', I18n.t('available.01') end test "simple backend translate: symbolize keys in hash" do store_translations :en, nested_hashes_in_array: { hello: "world" } assert_equal "world", I18n.t('nested_hashes_in_array.hello') assert_equal "world", I18n.t('nested_hashes_in_array')[:hello] end test "simple backend translate: symbolize keys in array" do store_translations :en, nested_hashes_in_array: [ { hello: "world" } ] I18n.t('nested_hashes_in_array').each do |val| assert_equal "world", val[:hello] end end # loading translations test "simple load_translations: given an unknown file type it raises I18n::UnknownFileType" do assert_raise(I18n::UnknownFileType) { I18n.backend.load_translations("#{locales_dir}/en.xml") } end test "simple load_translations: given a YAML file name with yaml extension does not raise anything" do assert_nothing_raised { I18n.backend.load_translations("#{locales_dir}/en.yaml") } end test "simple load_translations: given a JSON file name with yaml extension does not raise anything" do assert_nothing_raised { I18n.backend.load_translations("#{locales_dir}/en.json") } end test "simple load_translations: given a Ruby file name it does not raise anything" do assert_nothing_raised { I18n.backend.load_translations("#{locales_dir}/en.rb") } end test "simple load_translations: given no argument, it uses I18n.load_path" do I18n.backend.load_translations assert_equal({ :en => { :foo => { :bar => 'baz' } } }, I18n.backend.send(:translations)) end test "simple load_rb: loads data from a Ruby file" do data = I18n.backend.send(:load_rb, "#{locales_dir}/en.rb") assert_equal({ :en => { :fuh => { :bah => 'bas' } } }, data) end test "simple load_yml: loads data from a YAML file" do data = I18n.backend.send(:load_yml, "#{locales_dir}/en.yml") assert_equal({ 'en' => { 'foo' => { 'bar' => 'baz' } } }, data) end test "simple load_json: loads data from a JSON file" do data = I18n.backend.send(:load_json, "#{locales_dir}/en.json") assert_equal({ 'en' => { 'foo' => { 'bar' => 'baz' } } }, data) end test "simple load_translations: loads data from known file formats" do I18n.backend = I18n::Backend::Simple.new I18n.backend.load_translations("#{locales_dir}/en.rb", "#{locales_dir}/en.yml") expected = { :en => { :fuh => { :bah => "bas" }, :foo => { :bar => "baz" } } } assert_equal expected, translations end test "simple load_translations: given file names as array it does not raise anything" do assert_nothing_raised { I18n.backend.load_translations(["#{locales_dir}/en.rb", "#{locales_dir}/en.yml"]) } end # storing translations test "simple store_translations: stores translations, ... no, really :-)" do store_translations :'en', :foo => 'bar' assert_equal Hash[:'en', {:foo => 'bar'}], translations end test "simple store_translations: deep_merges with existing translations" do store_translations :'en', :foo => {:bar => 'bar'} store_translations :'en', :foo => {:baz => 'baz'} assert_equal Hash[:'en', {:foo => {:bar => 'bar', :baz => 'baz'}}], translations end test "simple store_translations: converts the given locale to a Symbol" do store_translations 'en', :foo => 'bar' assert_equal Hash[:'en', {:foo => 'bar'}], translations end test "simple store_translations: converts keys to Symbols" do store_translations 'en', 'foo' => {'bar' => 'bar', 'baz' => 'baz'} assert_equal Hash[:'en', {:foo => {:bar => 'bar', :baz => 'baz'}}], translations end test "simple store_translations: do not store translations unavailable locales if enforce_available_locales is true" do begin I18n.enforce_available_locales = true I18n.available_locales = [:en, :es] store_translations(:fr, :foo => {:bar => 'barfr', :baz => 'bazfr'}) store_translations(:es, :foo => {:bar => 'bares', :baz => 'bazes'}) assert_equal translations[:fr], {} assert_equal Hash[:foo, {:bar => 'bares', :baz => 'bazes'}], translations[:es] ensure I18n.config.enforce_available_locales = false end end test "simple store_translations: store translations for unavailable locales if enforce_available_locales is false" do I18n.available_locales = [:en, :es] store_translations(:fr, :foo => {:bar => 'barfr', :baz => 'bazfr'}) assert_equal Hash[:foo, {:bar => 'barfr', :baz => 'bazfr'}], translations[:fr] end test "simple store_translations: supports numeric keys" do store_translations(:en, 1 => 'foo') assert_equal 'foo', I18n.t('1') assert_equal 'foo', I18n.t(1) assert_equal 'foo', I18n.t(:'1') end # reloading translations test "simple reload_translations: unloads translations" do I18n.backend.reload! assert_nil translations end test "simple reload_translations: uninitializes the backend" do I18n.backend.reload! assert_equal false, I18n.backend.initialized? end test "simple eager_load!: loads the translations" do assert_equal false, I18n.backend.initialized? I18n.backend.eager_load! assert_equal true, I18n.backend.initialized? end test "simple reload!: reinitialize the backend if it was previously eager loaded" do I18n.backend.eager_load! I18n.backend.reload! assert_equal true, I18n.backend.initialized? end test "returns localized string given missing pluralization data" do assert_equal 'baz', I18n.t('foo.bar', count: 1) end end i18n-1.8.11/test/backend/transliterator_test.rb000066400000000000000000000060141414033570300213710ustar00rootroot00000000000000# encoding: utf-8 require 'test_helper' class I18nBackendTransliterator < I18n::TestCase def setup super I18n.backend = I18n::Backend::Simple.new @proc = lambda { |n| n.upcase } @hash = { "ü" => "ue", "ö" => "oe", "a" => "a" } @transliterator = I18n::Backend::Transliterator.get end test "transliteration rule can be a proc" do store_translations(:xx, :i18n => {:transliterate => {:rule => @proc}}) assert_equal "HELLO", I18n.backend.transliterate(:xx, "hello") end test "transliteration rule can be a hash" do store_translations(:xx, :i18n => {:transliterate => {:rule => @hash}}) assert_equal "ue", I18n.backend.transliterate(:xx, "ü") end test "transliteration rule must be a proc or hash" do store_translations(:xx, :i18n => {:transliterate => {:rule => ""}}) assert_raise I18n::ArgumentError do I18n.backend.transliterate(:xx, "ü") end end test "transliterator defaults to latin => ascii when no rule is given" do assert_equal "AEroskobing", I18n.backend.transliterate(:xx, "Ærøskøbing") end test "default transliterator should not modify ascii characters" do (0..127).each do |byte| char = [byte].pack("U") assert_equal char, @transliterator.transliterate(char) end end test "default transliterator correctly transliterates latin characters" do # create string with range of Unicode's western characters with # diacritics, excluding the division and multiplication signs which for # some reason or other are floating in the middle of all the letters. string = (0xC0..0x17E).to_a.reject {|c| [0xD7, 0xF7].include? c}.pack("U*") string.split(//) do |char| assert_match %r{^[a-zA-Z']*$}, @transliterator.transliterate(string) end end test "should replace non-ASCII chars not in map with a replacement char" do assert_equal "abc?", @transliterator.transliterate("abcſ") end test "can replace non-ASCII chars not in map with a custom replacement string" do assert_equal "abc#", @transliterator.transliterate("abcſ", "#") end test "default transliterator raises errors for invalid UTF-8" do assert_raise ArgumentError do @transliterator.transliterate("a\x92b") end end test "I18n.transliterate should transliterate using a default transliterator" do assert_equal "aeo", I18n.transliterate("áèö") end test "I18n.transliterate should transliterate using a locale" do store_translations(:xx, :i18n => {:transliterate => {:rule => @hash}}) assert_equal "ue", I18n.transliterate("ü", :locale => :xx) end test "default transliterator fails with custom rules with uncomposed input" do char = [117, 776].pack("U*") # "ü" as ASCII "u" plus COMBINING DIAERESIS transliterator = I18n::Backend::Transliterator.get(@hash) assert_not_equal "ue", transliterator.transliterate(char) end test "DEFAULT_APPROXIMATIONS is frozen to prevent concurrency issues" do assert I18n::Backend::Transliterator::HashTransliterator::DEFAULT_APPROXIMATIONS.frozen? end end i18n-1.8.11/test/core_ext/000077500000000000000000000000001414033570300151505ustar00rootroot00000000000000i18n-1.8.11/test/core_ext/hash_test.rb000066400000000000000000000030471414033570300174630ustar00rootroot00000000000000require 'test_helper' require 'i18n/core_ext/hash' require 'active_support/core_ext/hash' class I18nCoreExtHashInterpolationTest < I18n::TestCase using I18n::HashRefinements test "#deep_symbolize_keys" do hash = { 'foo' => { 'bar' => { 'baz' => 'bar' } } } expected = { :foo => { :bar => { :baz => 'bar' } } } assert_equal expected, hash.deep_symbolize_keys end test "#deep_symbolize_keys with numeric keys" do hash = { 1 => { 2 => { 3 => 'bar' } } } expected = { 1 => { 2 => { 3 => 'bar' } } } assert_equal expected, hash.deep_symbolize_keys end test "#slice" do hash = { :foo => 'bar', :baz => 'bar' } expected = { :foo => 'bar' } assert_equal expected, hash.slice(:foo) end test "#slice non-existent key" do hash = { :foo => 'bar', :baz => 'bar' } expected = { :foo => 'bar' } assert_equal expected, hash.slice(:foo, :not_here) end test "#except" do hash = { :foo => 'bar', :baz => 'bar' } expected = { :foo => 'bar' } assert_equal expected, hash.except(:baz) end test "#deep_merge!" do hash = { :foo => { :bar => { :baz => 'bar' } }, :baz => 'bar' } hash.deep_merge!(:foo => { :bar => { :baz => 'foo' } }) expected = { :foo => { :bar => { :baz => 'foo' } }, :baz => 'bar' } assert_equal expected, hash end test "#except supports ActiveSupport::HashWithIndifferentAccess" do hash = { :foo => 'bar', :baz => 'bar' }.with_indifferent_access expected = { :foo => 'bar' }.with_indifferent_access assert_equal expected, hash.except(:baz) end end i18n-1.8.11/test/gettext/000077500000000000000000000000001414033570300150245ustar00rootroot00000000000000i18n-1.8.11/test/gettext/api_test.rb000066400000000000000000000210211414033570300171550ustar00rootroot00000000000000# encoding: utf-8 require 'test_helper' require 'i18n/gettext/helpers' include I18n::Gettext::Helpers class I18nGettextApiTest < I18n::TestCase def setup super I18n.locale = :en I18n.backend.store_translations :de, { 'Hi Gettext!' => 'Hallo Gettext!', 'Sentence 1. Sentence 2.' => 'Satz 1. Satz 2.', "An apple" => { :one => 'Ein Apfel', :other => '%{count} Äpfel' }, :special => { "A special apple" => { :one => 'Ein spezieller Apfel', :other => '%{count} spezielle Äpfel' } }, :foo => { :bar => 'bar-de' }, 'foo.bar' => 'Foo Bar' }, :separator => '|' end # N_ def test_N_returns_original_msg assert_equal 'foo|bar', N_('foo|bar') I18n.locale = :de assert_equal 'Hi Gettext!', N_('Hi Gettext!') end # gettext def test_gettext_uses_msg_as_default assert_equal 'Hi Gettext!', _('Hi Gettext!') end def test_gettext_uses_msg_as_key I18n.locale = :de assert_equal 'Hallo Gettext!', gettext('Hi Gettext!') assert_equal 'Hallo Gettext!', _('Hi Gettext!') end def test_gettext_uses_msg_containing_dots_as_default assert_equal 'Sentence 1. Sentence 2.', gettext('Sentence 1. Sentence 2.') assert_equal 'Sentence 1. Sentence 2.', _('Sentence 1. Sentence 2.') end def test_gettext_uses_msg_containing_dots_as_key I18n.locale = :de assert_equal 'Satz 1. Satz 2.', gettext('Sentence 1. Sentence 2.') assert_equal 'Satz 1. Satz 2.', _('Sentence 1. Sentence 2.') end # sgettext def test_sgettext_defaults_to_the_last_token_of_a_scoped_msgid assert_equal 'bar', sgettext('foo|bar') assert_equal 'bar', s_('foo|bar') end def test_sgettext_looks_up_a_scoped_translation I18n.locale = :de assert_equal 'bar-de', sgettext('foo|bar') assert_equal 'bar-de', s_('foo|bar') end def test_sgettext_ignores_dots I18n.locale = :de assert_equal 'Foo Bar', sgettext('foo.bar') assert_equal 'Foo Bar', s_('foo.bar') end # pgettext def test_pgettext_defaults_to_msgid assert_equal 'bar', pgettext('foo', 'bar') assert_equal 'bar', p_('foo', 'bar') end def test_pgettext_looks_up_a_scoped_translation I18n.locale = :de assert_equal 'bar-de', pgettext('foo', 'bar') assert_equal 'bar-de', p_('foo', 'bar') end # ngettext def test_ngettext_looks_up_msg_id_as_default_singular assert_equal 'An apple', ngettext('An apple', '%{count} apples', 1) assert_equal 'An apple', n_('An apple', '%{count} apples', 1) end def test_ngettext_looks_up_msg_id_plural_as_default_plural assert_equal '2 apples', ngettext('An apple', '%{count} apples', 2) assert_equal '2 apples', n_('An apple', '%{count} apples', 2) end def test_ngettext_looks_up_a_singular I18n.locale = :de assert_equal 'Ein Apfel', ngettext('An apple', '%{count} apples', 1) assert_equal 'Ein Apfel', n_('An apple', '%{count} apples', 1) end def test_ngettext_looks_up_a_plural I18n.locale = :de assert_equal '2 Äpfel', ngettext('An apple', '%{count} apples', 2) assert_equal '2 Äpfel', n_('An apple', '%{count} apples', 2) end def test_ngettext_looks_up_msg_id_as_default_singular_with_alternative_syntax assert_equal 'An apple', ngettext(['An apple', '%{count} apples'], 1) assert_equal 'An apple', n_(['An apple', '%{count} apples'], 1) end def test_ngettext_looks_up_msg_id_plural_as_default_plural_with_alternative_syntax assert_equal '2 apples', ngettext(['An apple', '%{count} apples'], 2) assert_equal '2 apples', n_(['An apple', '%{count} apples'], 2) end def test_ngettext_looks_up_a_singular_with_alternative_syntax I18n.locale = :de assert_equal 'Ein Apfel', ngettext(['An apple', '%{count} apples'], 1) assert_equal 'Ein Apfel', n_(['An apple', '%{count} apples'], 1) end def test_ngettext_looks_up_a_plural_with_alternative_syntax I18n.locale = :de assert_equal '2 Äpfel', ngettext(['An apple', '%{count} apples'], 2) assert_equal '2 Äpfel', n_(['An apple', '%{count} apples'], 2) end # nsgettext def test_nsgettext_looks_up_msg_id_as_default_singular assert_equal 'A special apple', nsgettext('special|A special apple', '%{count} special apples', 1) assert_equal 'A special apple', ns_('special|A special apple', '%{count} special apples', 1) end def test_nsgettext_looks_up_msg_id_plural_as_default_plural assert_equal '2 special apples', nsgettext('special|A special apple', '%{count} special apples', 2) assert_equal '2 special apples', ns_('special|A special apple', '%{count} special apples', 2) end def test_nsgettext_looks_up_a_singular I18n.locale = :de assert_equal 'Ein spezieller Apfel', nsgettext('special|A special apple', '%{count} special apples', 1) assert_equal 'Ein spezieller Apfel', ns_('special|A special apple', '%{count} special apples', 1) end def test_nsgettext_looks_up_a_plural I18n.locale = :de assert_equal '2 spezielle Äpfel', nsgettext('special|A special apple', '%{count} special apples', 2) assert_equal '2 spezielle Äpfel', ns_('special|A special apple', '%{count} special apples', 2) end def test_nsgettext_looks_up_msg_id_as_default_singular_with_alternative_syntax assert_equal 'A special apple', nsgettext(['special|A special apple', '%{count} special apples'], 1) assert_equal 'A special apple', ns_(['special|A special apple', '%{count} special apples'], 1) end def test_nsgettext_looks_up_msg_id_plural_as_default_plural_with_alternative_syntax assert_equal '2 special apples', nsgettext(['special|A special apple', '%{count} special apples'], 2) assert_equal '2 special apples', ns_(['special|A special apple', '%{count} special apples'], 2) end def test_nsgettext_looks_up_a_singular_with_alternative_syntax I18n.locale = :de assert_equal 'Ein spezieller Apfel', nsgettext(['special|A special apple', '%{count} special apples'], 1) assert_equal 'Ein spezieller Apfel', ns_(['special|A special apple', '%{count} special apples'], 1) end def test_nsgettext_looks_up_a_plural_with_alternative_syntax I18n.locale = :de assert_equal '2 spezielle Äpfel', nsgettext(['special|A special apple', '%{count} special apples'], 2) assert_equal '2 spezielle Äpfel', ns_(['special|A special apple', '%{count} special apples'], 2) end # npgettext def test_npgettext_looks_up_msg_id_as_default_singular assert_equal 'A special apple', npgettext('special', 'A special apple', '%{count} special apples', 1) assert_equal 'A special apple', np_('special', 'A special apple', '%{count} special apples', 1) end def test_npgettext_looks_up_msg_id_plural_as_default_plural assert_equal '2 special apples', npgettext('special', 'A special apple', '%{count} special apples', 2) assert_equal '2 special apples', np_('special', 'A special apple', '%{count} special apples', 2) end def test_npgettext_looks_up_a_singular I18n.locale = :de assert_equal 'Ein spezieller Apfel', npgettext('special', 'A special apple', '%{count} special apples', 1) assert_equal 'Ein spezieller Apfel', np_('special', 'A special apple', '%{count} special apples', 1) end def test_npgettext_looks_up_a_plural I18n.locale = :de assert_equal '2 spezielle Äpfel', npgettext('special', 'A special apple', '%{count} special apples', 2) assert_equal '2 spezielle Äpfel', np_('special', 'A special apple', '%{count} special apples', 2) end def test_npgettext_looks_up_msg_id_as_default_singular_with_alternative_syntax assert_equal 'A special apple', npgettext('special', ['A special apple', '%{count} special apples'], 1) assert_equal 'A special apple', np_('special', ['A special apple', '%{count} special apples'], 1) end def test_npgettext_looks_up_msg_id_plural_as_default_plural_with_alternative_syntax assert_equal '2 special apples', npgettext('special', ['A special apple', '%{count} special apples'], 2) assert_equal '2 special apples', np_('special', ['A special apple', '%{count} special apples'], 2) end def test_npgettext_looks_up_a_singular_with_alternative_syntax I18n.locale = :de assert_equal 'Ein spezieller Apfel', npgettext('special', ['A special apple', '%{count} special apples'], 1) assert_equal 'Ein spezieller Apfel', np_('special', ['A special apple', '%{count} special apples'], 1) end def test_npgettext_looks_up_a_plural_with_alternative_syntax I18n.locale = :de assert_equal '2 spezielle Äpfel', npgettext('special', ['A special apple', '%{count} special apples'], 2) assert_equal '2 spezielle Äpfel', np_('special', ['A special apple', '%{count} special apples'], 2) end end i18n-1.8.11/test/gettext/backend_test.rb000066400000000000000000000061541414033570300200050ustar00rootroot00000000000000# encoding: utf-8 require 'test_helper' class I18nGettextBackendTest < I18n::TestCase include I18n::Gettext::Helpers class Backend < I18n::Backend::Simple include I18n::Backend::Gettext end def setup super I18n.backend = Backend.new I18n.locale = :en I18n.load_path = ["#{locales_dir}/de.po"] I18n.default_separator = '|' end def test_backend_loads_po_file I18n.backend.send(:init_translations) assert I18n.backend.send(:translations)[:de][:"Axis"] end def test_looks_up_a_translation I18n.locale = :de assert_equal 'Auto', gettext('car') end def test_uses_default_translation assert_equal 'car', gettext('car') end def test_looks_up_a_namespaced_translation I18n.locale = :de assert_equal 'Räderzahl', sgettext('Car|Wheels count') assert_equal 'Räderzahl', pgettext('Car', 'Wheels count') assert_equal 'Räderzahl!', pgettext('New car', 'Wheels count') end def test_uses_namespaced_default_translation assert_equal 'Wheels count', sgettext('Car|Wheels count') assert_equal 'Wheels count', pgettext('Car', 'Wheels count') assert_equal 'Wheels count', pgettext('New car', 'Wheels count') end def test_pluralizes_entry I18n.locale = :de assert_equal 'Achse', ngettext('Axis', 'Axis', 1) assert_equal 'Achsen', ngettext('Axis', 'Axis', 2) end def test_pluralizes_default_entry assert_equal 'Axis', ngettext('Axis', 'Axis', 1) assert_equal 'Axis', ngettext('Axis', 'Axis', 2) end def test_pluralizes_namespaced_entry I18n.locale = :de assert_equal 'Rad', nsgettext('Car|wheel', 'wheels', 1) assert_equal 'Räder', nsgettext('Car|wheel', 'wheels', 2) assert_equal 'Rad', npgettext('Car', 'wheel', 'wheels', 1) assert_equal 'Räder', npgettext('Car', 'wheel', 'wheels', 2) assert_equal 'Rad!', npgettext('New car', 'wheel', 'wheels', 1) assert_equal 'Räder!', npgettext('New car', 'wheel', 'wheels', 2) end def test_pluralizes_namespaced_default_entry assert_equal 'wheel', nsgettext('Car|wheel', 'wheels', 1) assert_equal 'wheels', nsgettext('Car|wheel', 'wheels', 2) assert_equal 'wheel', npgettext('Car', 'wheel', 'wheels', 1) assert_equal 'wheels', npgettext('Car', 'wheel', 'wheels', 2) assert_equal 'wheel', npgettext('New car', 'wheel', 'wheels', 1) assert_equal 'wheels', npgettext('New car', 'wheel', 'wheels', 2) end def test_pluralizes_namespaced_entry_with_alternative_syntax I18n.locale = :de assert_equal 'Rad', nsgettext(['Car|wheel', 'wheels'], 1) assert_equal 'Räder', nsgettext(['Car|wheel', 'wheels'], 2) assert_equal 'Rad', npgettext('Car', ['wheel', 'wheels'], 1) assert_equal 'Räder', npgettext('Car', ['wheel', 'wheels'], 2) assert_equal 'Rad!', npgettext('New car', ['wheel', 'wheels'], 1) assert_equal 'Räder!', npgettext('New car', ['wheel', 'wheels'], 2) end def test_ngettextpluralizes_entry_with_dots I18n.locale = :de assert_equal 'Auf 1 Achse.', n_("On %{count} wheel.", "On %{count} wheels.", 1) assert_equal 'Auf 2 Achsen.', n_("On %{count} wheel.", "On %{count} wheels.", 2) end end i18n-1.8.11/test/i18n/000077500000000000000000000000001414033570300141175ustar00rootroot00000000000000i18n-1.8.11/test/i18n/exceptions_test.rb000066400000000000000000000075341414033570300176750ustar00rootroot00000000000000require 'test_helper' class I18nExceptionsTest < I18n::TestCase def test_invalid_locale_stores_locale force_invalid_locale rescue I18n::ArgumentError => exception assert_nil exception.locale end test "passing an invalid locale raises an InvalidLocale exception" do force_invalid_locale do |exception| assert_equal 'nil is not a valid locale', exception.message end end test "MissingTranslation can be initialized without options" do exception = I18n::MissingTranslation.new(:en, 'foo') assert_equal({}, exception.options) end test "MissingTranslationData exception stores locale, key and options" do force_missing_translation_data do |exception| assert_equal 'de', exception.locale assert_equal :foo, exception.key assert_equal({:scope => :bar}, exception.options) end end test "MissingTranslationData message contains the locale and scoped key" do force_missing_translation_data do |exception| assert_equal 'translation missing: de.bar.foo', exception.message end end test "InvalidPluralizationData stores entry, count and key" do force_invalid_pluralization_data do |exception| assert_equal({:other => "bar"}, exception.entry) assert_equal 1, exception.count assert_equal :one, exception.key end end test "InvalidPluralizationData message contains count, data and missing key" do force_invalid_pluralization_data do |exception| assert_match '1', exception.message assert_match '{:other=>"bar"}', exception.message assert_match 'one', exception.message end end test "MissingInterpolationArgument stores key and string" do assert_raise(I18n::MissingInterpolationArgument) { force_missing_interpolation_argument } force_missing_interpolation_argument do |exception| assert_equal :bar, exception.key assert_equal "%{bar}", exception.string end end test "MissingInterpolationArgument message contains the missing and given arguments" do force_missing_interpolation_argument do |exception| assert_equal 'missing interpolation argument :bar in "%{bar}" ({:baz=>"baz"} given)', exception.message end end test "ReservedInterpolationKey stores key and string" do force_reserved_interpolation_key do |exception| assert_equal :scope, exception.key assert_equal "%{scope}", exception.string end end test "ReservedInterpolationKey message contains the reserved key" do force_reserved_interpolation_key do |exception| assert_equal 'reserved key :scope used in "%{scope}"', exception.message end end test "MissingTranslationData#new can be initialized with just two arguments" do assert I18n::MissingTranslationData.new('en', 'key') end private def force_invalid_locale I18n.translate(:foo, :locale => nil) rescue I18n::ArgumentError => e block_given? ? yield(e) : raise(e) end def force_missing_translation_data(options = {}) store_translations('de', :bar => nil) I18n.translate(:foo, **options.merge(:scope => :bar, :locale => :de)) rescue I18n::ArgumentError => e block_given? ? yield(e) : raise(e) end def force_invalid_pluralization_data store_translations('de', :foo => { :other => 'bar' }) I18n.translate(:foo, :count => 1, :locale => :de) rescue I18n::ArgumentError => e block_given? ? yield(e) : raise(e) end def force_missing_interpolation_argument store_translations('de', :foo => "%{bar}") I18n.translate(:foo, :baz => 'baz', :locale => :de) rescue I18n::ArgumentError => e block_given? ? yield(e) : raise(e) end def force_reserved_interpolation_key store_translations('de', :foo => "%{scope}") I18n.translate(:foo, :baz => 'baz', :locale => :de) rescue I18n::ArgumentError => e block_given? ? yield(e) : raise(e) end end i18n-1.8.11/test/i18n/gettext_plural_keys_test.rb000066400000000000000000000011311414033570300215750ustar00rootroot00000000000000require 'test_helper' class I18nGettextPluralKeysTest < I18n::TestCase def setup super I18n::Gettext.plural_keys[:zz] = [:value1, :value2] end test "Returns the plural keys of the given locale if present" do assert_equal I18n::Gettext.plural_keys(:zz), [:value1, :value2] end test "Returns the plural keys of :en if given locale not present" do assert_equal I18n::Gettext.plural_keys(:yy), [:one, :other] end test "Returns the whole hash with no arguments" do assert_equal I18n::Gettext.plural_keys, { :en => [:one, :other], :zz => [:value1, :value2] } end end i18n-1.8.11/test/i18n/interpolate_test.rb000066400000000000000000000105111414033570300200270ustar00rootroot00000000000000require 'test_helper' # thanks to Masao's String extensions, some tests taken from Masao's tests # http://github.com/mutoh/gettext/blob/edbbe1fa8238fa12c7f26f2418403015f0270e47/test/test_string.rb class I18nInterpolateTest < I18n::TestCase test "String interpolates a hash argument w/ named placeholders" do assert_equal "Masao Mutoh", I18n.interpolate("%{first} %{last}", :first => 'Masao', :last => 'Mutoh' ) end test "String interpolates a hash argument w/ named placeholders (reverse order)" do assert_equal "Mutoh, Masao", I18n.interpolate("%{last}, %{first}", :first => 'Masao', :last => 'Mutoh' ) end test "String interpolates named placeholders with sprintf syntax" do assert_equal "10, 43.4", I18n.interpolate("%d, %.1f", :integer => 10, :float => 43.4) end test "String interpolates named placeholders with sprintf syntax, does not recurse" do assert_equal "%s", I18n.interpolate("%{msg}", :msg => '%s', :not_translated => 'should not happen' ) end test "String interpolation does not replace anything when no placeholders are given" do assert_equal "aaa", I18n.interpolate("aaa", :num => 1) end test "String interpolation sprintf behaviour equals Ruby 1.9 behaviour" do assert_equal "1", I18n.interpolate("%d", :num => 1) assert_equal "0b1", I18n.interpolate("%#b", :num => 1) assert_equal "foo", I18n.interpolate("%s", :msg => "foo") assert_equal "1.000000", I18n.interpolate("%f", :num => 1.0) assert_equal " 1", I18n.interpolate("%3.0f", :num => 1.0) assert_equal "100.00", I18n.interpolate("%2.2f", :num => 100.0) assert_equal "0x64", I18n.interpolate("%#x", :num => 100.0) assert_raise(ArgumentError) { I18n.interpolate("%,d", :num => 100) } assert_raise(ArgumentError) { I18n.interpolate("%/d", :num => 100) } end test "String interpolation raises an I18n::MissingInterpolationArgument when the string has extra placeholders" do assert_raise(I18n::MissingInterpolationArgument, "key not found") do I18n.interpolate("%{first} %{last}", :first => 'Masao') end end test "String interpolation does not raise when extra values were passed" do assert_nothing_raised do assert_equal "Masao Mutoh", I18n.interpolate("%{first} %{last}", :first => 'Masao', :last => 'Mutoh', :salutation => 'Mr.' ) end end test "% acts as escape character in String interpolation" do assert_equal "%{first}", I18n.interpolate("%%{first}", :first => 'Masao') assert_equal "% 1", I18n.interpolate("%% %d", :num => 1.0) assert_equal "%{num} %d", I18n.interpolate("%%{num} %%d", :num => 1) end def test_sprintf_mix_unformatted_and_formatted_named_placeholders assert_equal "foo 1.000000", I18n.interpolate("%{name} %f", :name => "foo", :num => 1.0) end class RailsSafeBuffer < String def gsub(*args, &block) to_str.gsub(*args, &block) end end test "with String subclass that redefined gsub method" do assert_equal "Hello mars world", I18n.interpolate(RailsSafeBuffer.new("Hello %{planet} world"), :planet => 'mars') end end class I18nMissingInterpolationCustomHandlerTest < I18n::TestCase def setup super @old_handler = I18n.config.missing_interpolation_argument_handler I18n.config.missing_interpolation_argument_handler = lambda do |key, values, string| "missing key is #{key}, values are #{values.inspect}, given string is '#{string}'" end end def teardown I18n.config.missing_interpolation_argument_handler = @old_handler super end test "String interpolation can use custom missing interpolation handler" do assert_equal %|Masao missing key is last, values are {:first=>"Masao"}, given string is '%{first} %{last}'|, I18n.interpolate("%{first} %{last}", :first => 'Masao') end end class I18nCustomInterpolationPatternTest < I18n::TestCase def setup super @old_interpolation_patterns = I18n.config.interpolation_patterns I18n.config.interpolation_patterns << /\{\{(\w+)\}\}/ end def teardown I18n.config.interpolation_patterns = @old_interpolation_patterns super end test "String interpolation can use custom interpolation pattern" do assert_equal "Masao Mutoh", I18n.interpolate("{{first}} {{last}}", :first => "Masao", :last => "Mutoh") end end i18n-1.8.11/test/i18n/load_path_test.rb000066400000000000000000000020471414033570300174410ustar00rootroot00000000000000require 'test_helper' class I18nLoadPathTest < I18n::TestCase def setup super I18n.locale = :en I18n.backend = I18n::Backend::Simple.new store_translations(:en, :foo => {:bar => 'bar', :baz => 'baz'}) end test "nested load paths do not break locale loading" do I18n.load_path = [[locales_dir + '/en.yml']] assert_equal "baz", I18n.t(:'foo.bar') end test "loading an empty yml file raises an InvalidLocaleData exception" do assert_raise I18n::InvalidLocaleData do I18n.load_path = [[locales_dir + '/invalid/empty.yml']] I18n.t(:'foo.bar', :default => "baz") end end test "loading an invalid yml file raises an InvalidLocaleData exception" do assert_raise I18n::InvalidLocaleData do I18n.load_path = [[locales_dir + '/invalid/syntax.yml']] I18n.t(:'foo.bar', :default => "baz") end end test "adding arrays of filenames to the load path does not break locale loading" do I18n.load_path << Dir[locales_dir + '/*.{rb,yml}'] assert_equal "baz", I18n.t(:'foo.bar') end end i18n-1.8.11/test/i18n/middleware_test.rb000066400000000000000000000012431414033570300176200ustar00rootroot00000000000000require 'test_helper' class I18nMiddlewareTest < I18n::TestCase def setup super I18n.default_locale = :fr @app = DummyRackApp.new @middleware = I18n::Middleware.new(@app) end test "middleware initializes new config object after request" do old_i18n_config_object_id = Thread.current[:i18n_config].object_id @middleware.call({}) updated_i18n_config_object_id = Thread.current[:i18n_config].object_id assert_not_equal updated_i18n_config_object_id, old_i18n_config_object_id end test "succesfully resets i18n locale to default locale by defining new config" do @middleware.call({}) assert_equal :fr, I18n.locale end end i18n-1.8.11/test/i18n_test.rb000066400000000000000000000403451414033570300155110ustar00rootroot00000000000000# encoding: utf-8 require 'test_helper' class I18nTest < I18n::TestCase def setup super store_translations(:en, :currency => { :format => { :separator => '.', :delimiter => ',', } }) store_translations(:nl, :currency => { :format => { :separator => ',', :delimiter => '.', } }) store_translations(:en, "true" => "Yes", "false" => "No") end test "exposes its VERSION constant" do assert I18n::VERSION end test "uses the simple backend by default" do assert I18n.backend.is_a?(I18n::Backend::Simple) end test "can set the backend" do begin assert_nothing_raised { I18n.backend = self } assert_equal self, I18n.backend ensure I18n.backend = I18n::Backend::Simple.new end end test "uses :en as a default_locale by default" do assert_equal :en, I18n.default_locale end test "can set the default locale" do begin assert_nothing_raised { I18n.default_locale = 'de' } assert_equal :de, I18n.default_locale ensure I18n.default_locale = :en end end test "default_locale= doesn't ignore junk" do assert_raise(NoMethodError) { I18n.default_locale = Class } end test "raises an I18n::InvalidLocale exception when setting an unavailable default locale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.default_locale = :klingon } ensure I18n.config.enforce_available_locales = false end end test "uses the default locale as a locale by default" do assert_equal I18n.default_locale, I18n.locale end test "sets the current locale to Thread.current" do assert_nothing_raised { I18n.locale = 'de' } assert_equal :de, I18n.locale assert_equal :de, Thread.current[:i18n_config].locale I18n.locale = :en end test "locale= doesn't ignore junk" do assert_raise(NoMethodError) { I18n.locale = Class } end test "raises an I18n::InvalidLocale exception when setting an unavailable locale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.locale = :klingon } ensure I18n.config.enforce_available_locales = false end end test "can set the configuration object" do begin I18n.config = self assert_equal self, I18n.config assert_equal self, Thread.current[:i18n_config] ensure I18n.config = ::I18n::Config.new end end test "locale is not shared between configurations" do a = I18n::Config.new b = I18n::Config.new a.locale = :fr b.locale = :es assert_equal :fr, a.locale assert_equal :es, b.locale assert_equal :en, I18n.locale end test "other options are shared between configurations" do begin a = I18n::Config.new b = I18n::Config.new a.default_locale = :fr b.default_locale = :es assert_equal :es, a.default_locale assert_equal :es, b.default_locale assert_equal :es, I18n.default_locale ensure I18n.default_locale = :en end end test "uses a dot as a default_separator by default" do assert_equal '.', I18n.default_separator end test "can set the default_separator" do begin assert_nothing_raised { I18n.default_separator = "\001" } ensure I18n.default_separator = '.' end end test "normalize_keys normalizes given locale, keys and scope to an array of single-key symbols" do assert_equal [:en, :foo, :bar], I18n.normalize_keys(:en, :bar, :foo) assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz.buz', :'foo.bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, 'baz.buz', 'foo.bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, %w(baz buz), %w(foo bar)) assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, [:baz, :buz], [:foo, :bar]) end test "normalize_keys discards empty keys" do assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz..buz', :'foo..bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz......buz', :'foo......bar') assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, ['baz', nil, '', 'buz'], ['foo', nil, '', 'bar']) end test "normalize_keys uses a given separator" do assert_equal [:en, :foo, :bar, :baz, :buz], I18n.normalize_keys(:en, :'baz|buz', :'foo|bar', '|') end test "can set the exception_handler" do begin previous_exception_handler = I18n.exception_handler assert_nothing_raised { I18n.exception_handler = :custom_exception_handler } ensure I18n.exception_handler = previous_exception_handler end end test "uses a custom exception handler set to I18n.exception_handler" do begin previous_exception_handler = I18n.exception_handler I18n.exception_handler = :custom_exception_handler I18n.expects(:custom_exception_handler) I18n.translate :bogus ensure I18n.exception_handler = previous_exception_handler end end test "uses a custom exception handler passed as an option" do I18n.expects(:custom_exception_handler) I18n.translate(:bogus, :exception_handler => :custom_exception_handler) end test "delegates translate calls to the backend" do I18n.backend.expects(:translate).with('de', :foo, {}) I18n.translate :foo, :locale => 'de' end test "delegates localize calls to the backend" do I18n.backend.expects(:localize).with('de', :whatever, :default, {}) I18n.localize :whatever, :locale => 'de' end test "translate given no locale uses the current locale" do I18n.backend.expects(:translate).with(:en, :foo, {}) I18n.translate :foo end test "translate works with nested symbol keys" do assert_equal ".", I18n.t(:'currency.format.separator') end test "translate works with nested string keys" do assert_equal ".", I18n.t('currency.format.separator') end test "translate with an array as a scope works" do assert_equal ".", I18n.t(:separator, :scope => %w(currency format)) end test "translate with an array containing dot separated strings as a scope works" do assert_equal ".", I18n.t(:separator, :scope => ['currency.format']) end test "translate with an array of keys and a dot separated string as a scope works" do assert_equal [".", ","], I18n.t(%w(separator delimiter), :scope => 'currency.format') end test "translate with an array of dot separated keys and a scope works" do assert_equal [".", ","], I18n.t(%w(format.separator format.delimiter), :scope => 'currency') end # def test_translate_given_no_args_raises_missing_translation_data # assert_equal "translation missing: en, no key", I18n.t # end test "translate given a bogus key returns an error message" do assert_equal "translation missing: en.bogus", I18n.t(:bogus) end test "translate given an empty string as a key raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.t("") } end test "translate given an empty symbol as a key raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.t(:"") } end test "translate given an array with empty string as a key raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.t(["", :foo]) } end test "translate given an empty array as a key returns empty array" do assert_equal [], I18n.t([]) end test "translate given nil returns nil" do assert_nil I18n.t(nil) end test "translate given an unavailable locale rases an I18n::InvalidLocale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.t(:foo, :locale => 'klingon') } ensure I18n.config.enforce_available_locales = false end end test "translate given true as a key works" do assert_equal "Yes", I18n.t(true) end test "translate given false as a key works" do assert_equal "No", I18n.t(false) end test "translate raises Disabled if locale is false" do I18n.with_locale(false) do assert_raise I18n::Disabled do I18n.t('foo') end assert_equal 'translation missing: en.foo', I18n.t('foo', locale: :en) end end test "available_locales can be replaced at runtime" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.t(:foo, :locale => 'klingon') } old_locales, I18n.config.available_locales = I18n.config.available_locales, [:klingon] I18n.t(:foo, :locale => 'klingon') ensure I18n.config.enforce_available_locales = false I18n.config.available_locales = old_locales end end test "available_locales_set should return a set" do assert_equal Set, I18n.config.available_locales_set.class assert_equal I18n.config.available_locales.size * 2, I18n.config.available_locales_set.size end test "exists? given an existing key will return true" do assert_equal true, I18n.exists?(:currency) end test "exists? given a non-existing key will return false" do assert_equal false, I18n.exists?(:bogus) end test "exists? given an existing dot-separated key will return true" do assert_equal true, I18n.exists?('currency.format.delimiter') end test "exists? given a non-existing dot-separated key will return false" do assert_equal false, I18n.exists?('currency.format.bogus') end test "exists? given an existing key and an existing locale will return true" do assert_equal true, I18n.exists?(:currency, :nl) end test "exists? given a non-existing key and an existing locale will return false" do assert_equal false, I18n.exists?(:bogus, :nl) end test "exists? raises Disabled if locale is false" do I18n.with_locale(false) do assert_raise I18n::Disabled do I18n.exists?(:bogus) end assert_equal false, I18n.exists?(:bogus, :nl) end end test "localize given nil raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l nil } end test "localize given nil and default returns default" do assert_nil I18n.l(nil, :default => nil) end test "localize given an Object raises an I18n::ArgumentError" do assert_raise(I18n::ArgumentError) { I18n.l Object.new } end test "localize given an unavailable locale rases an I18n::InvalidLocale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.l(Time.now, :locale => 'klingon') } ensure I18n.config.enforce_available_locales = false end end test "localize raises Disabled if locale is false" do I18n.with_locale(false) do assert_raise I18n::Disabled do I18n.l(Time.now) end end end test "can use a lambda as an exception handler" do begin previous_exception_handler = I18n.exception_handler I18n.exception_handler = Proc.new { |exception, locale, key, options| key } assert_equal :test_proc_handler, I18n.translate(:test_proc_handler) ensure I18n.exception_handler = previous_exception_handler end end test "can use an object responding to #call as an exception handler" do begin previous_exception_handler = I18n.exception_handler I18n.exception_handler = Class.new do def call(exception, locale, key, options); key; end end.new assert_equal :test_proc_handler, I18n.translate(:test_proc_handler) ensure I18n.exception_handler = previous_exception_handler end end test "I18n.with_locale temporarily sets the given locale" do store_translations(:en, :foo => 'Foo in :en') store_translations(:de, :foo => 'Foo in :de') store_translations(:pl, :foo => 'Foo in :pl') I18n.with_locale { assert_equal [:en, 'Foo in :en'], [I18n.locale, I18n.t(:foo)] } I18n.with_locale(:de) { assert_equal [:de, 'Foo in :de'], [I18n.locale, I18n.t(:foo)] } I18n.with_locale(:pl) { assert_equal [:pl, 'Foo in :pl'], [I18n.locale, I18n.t(:foo)] } I18n.with_locale(:en) { assert_equal [:en, 'Foo in :en'], [I18n.locale, I18n.t(:foo)] } assert_equal I18n.default_locale, I18n.locale end test "I18n.with_locale resets the locale in case of errors" do assert_raise(I18n::ArgumentError) { I18n.with_locale(:pl) { raise I18n::ArgumentError } } assert_equal I18n.default_locale, I18n.locale end test "I18n.translitarate handles I18n::ArgumentError exception" do I18n::Backend::Transliterator.stubs(:get).raises(I18n::ArgumentError) I18n.exception_handler.expects(:call).raises(I18n::ArgumentError) assert_raise(I18n::ArgumentError) { I18n.transliterate("ąćó") } end test "I18n.translitarate raises I18n::ArgumentError exception" do I18n::Backend::Transliterator.stubs(:get).raises(I18n::ArgumentError) I18n.exception_handler.expects(:call).never assert_raise(I18n::ArgumentError) { I18n.transliterate("ąćó", :raise => true) } end test "transliterate given an unavailable locale rases an I18n::InvalidLocale" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.transliterate('string', :locale => 'klingon') } ensure I18n.config.enforce_available_locales = false end end test "transliterate non-ASCII chars not in map with default replacement char" do assert_equal "???", I18n.transliterate("日本語") end test "I18n.locale_available? returns true when the passed locale is available" do I18n.available_locales = [:en, :de] assert_equal true, I18n.locale_available?(:de) end test "I18n.locale_available? returns true when the passed locale is a string and is available" do I18n.available_locales = [:en, :de] assert_equal true, I18n.locale_available?('de') end test "I18n.locale_available? returns false when the passed locale is unavailable" do assert_equal false, I18n.locale_available?(:klingon) end test "I18n.enforce_available_locales! raises an I18n::InvalidLocale when the passed locale is unavailable" do begin I18n.config.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.enforce_available_locales!(:klingon) } ensure I18n.config.enforce_available_locales = false end end test "I18n.enforce_available_locales! does nothing when the passed locale is available" do I18n.available_locales = [:en, :de] begin I18n.config.enforce_available_locales = true assert_nothing_raised { I18n.enforce_available_locales!(:en) } ensure I18n.config.enforce_available_locales = false end end test "I18n.enforce_available_locales config can be set to false" do begin I18n.config.enforce_available_locales = false assert_equal false, I18n.config.enforce_available_locales ensure I18n.config.enforce_available_locales = false end end test 'I18n.reload! reloads the set of locales that are enforced' do begin # Clear the backend that affects the available locales and somehow can remain # set from the last running test. # For instance, it contains enough translations to cause a false positive with # this test when ran with --seed=50992 I18n.backend = I18n::Backend::Simple.new assert !I18n.available_locales.include?(:de), "Available locales should not include :de at this point" I18n.enforce_available_locales = true assert_raise(I18n::InvalidLocale) { I18n.default_locale = :de } assert_raise(I18n::InvalidLocale) { I18n.locale = :de } store_translations(:de, :foo => 'Foo in :de') assert_raise(I18n::InvalidLocale) { I18n.default_locale = :de } assert_raise(I18n::InvalidLocale) { I18n.locale = :de } I18n.reload! store_translations(:en, :foo => 'Foo in :en') store_translations(:de, :foo => 'Foo in :de') store_translations(:pl, :foo => 'Foo in :pl') assert I18n.available_locales.include?(:de), ":de should now be allowed" assert I18n.available_locales.include?(:en), ":en should now be allowed" assert I18n.available_locales.include?(:pl), ":pl should now be allowed" assert_nothing_raised { I18n.default_locale = I18n.locale = :en } assert_nothing_raised { I18n.default_locale = I18n.locale = :de } assert_nothing_raised { I18n.default_locale = I18n.locale = :pl } ensure I18n.enforce_available_locales = false end end end i18n-1.8.11/test/locale/000077500000000000000000000000001414033570300145775ustar00rootroot00000000000000i18n-1.8.11/test/locale/fallbacks_test.rb000066400000000000000000000140451414033570300201110ustar00rootroot00000000000000require 'test_helper' include I18n::Locale class I18nFallbacksDefaultsTest < I18n::TestCase test "defaults to an empty array if no default has been set manually" do I18n.default_locale = :'en-US' fallbacks = Fallbacks.new assert_equal [], fallbacks.defaults end test "documentation example #1 - does not use default locale in fallbacks - See Issues #413 & #415" do I18n.default_locale = :"en-US" fallbacks = Fallbacks.new(:"de-AT" => :"de-DE") assert_equal [:"de-AT", :de, :"de-DE"], fallbacks[:"de-AT"] end test "documentation example #2 - does not use default locale in fallbacks - Uses custom locale - See Issues #413 & #415" do I18n.default_locale = :"en-US" fallbacks = Fallbacks.new(:"en-GB", :"de-AT" => :de, :"de-CH" => :de) assert_equal [:"de-AT", :de, :"en-GB", :en], fallbacks[:"de-AT"] assert_equal [:"de-CH", :de, :"en-GB", :en], fallbacks[:"de-CH"] end test "explicit fallback to default locale" do I18n.default_locale = :"en-US" fallbacks = Fallbacks.new([:"en-US"]) assert_equal [:"de-AT", :de, :"en-US", :en], fallbacks[:"de-AT"] assert_equal [:"de-CH", :de, :"en-US", :en], fallbacks[:"de-CH"] end test "defaults reflect a manually passed default locale if any" do fallbacks = Fallbacks.new(:'fi-FI') assert_equal [:'fi-FI', :fi], fallbacks.defaults I18n.default_locale = :'de-DE' assert_equal [:'fi-FI', :fi], fallbacks.defaults end test "defaults allows to set multiple defaults" do fallbacks = Fallbacks.new(:'fi-FI', :'se-FI') assert_equal [:'fi-FI', :fi, :'se-FI', :se], fallbacks.defaults end end class I18nFallbacksComputationTest < I18n::TestCase def setup super @fallbacks = Fallbacks.new(:'en-US') end test "with no mappings defined it returns [:es, :en-US] for :es" do assert_equal [:es, :"en-US", :en], @fallbacks[:es] end test "with no mappings defined it returns [:es-ES, :es, :en-US] for :es-ES" do assert_equal [:"es-ES", :es, :"en-US", :en], @fallbacks[:"es-ES"] end test "with no mappings defined it returns [:es-MX, :es, :en-US] for :es-MX" do assert_equal [:"es-MX", :es, :"en-US", :en], @fallbacks[:"es-MX"] end test "with no mappings defined it returns [:es-Latn-ES, :es-Latn, :es, :en-US] for :es-Latn-ES" do assert_equal [:"es-Latn-ES", :"es-Latn", :es, :"en-US", :en], @fallbacks[:'es-Latn-ES'] end test "with no mappings defined it returns [:en, :en-US] for :en" do assert_equal [:en, :"en-US"], @fallbacks[:en] end test "with no mappings defined it returns [:en-US, :en] for :en-US (special case: locale == default)" do assert_equal [:"en-US", :en], @fallbacks[:"en-US"] end # Most people who speak Catalan also live in Spain, so it is safe to assume # that they also speak Spanish as spoken in Spain. test "with a Catalan mapping defined it returns [:ca, :es-ES, :es, :en-US] for :ca" do @fallbacks.map(:ca => :"es-ES") assert_equal [:ca, :"es-ES", :es, :"en-US", :en], @fallbacks[:ca] end test "with a Catalan mapping defined it returns [:ca-ES, :ca, :es-ES, :es, :en-US] for :ca-ES" do @fallbacks.map(:ca => :"es-ES") assert_equal [:"ca-ES", :ca, :"es-ES", :es, :"en-US", :en], @fallbacks[:"ca-ES"] end # People who speak Arabic as spoken in Palestine often times also speak # Hebrew as spoken in Israel. However it is in no way safe to assume that # everybody who speaks Arabic also speaks Hebrew. test "with a Hebrew mapping defined it returns [:ar, :en-US] for :ar" do @fallbacks.map(:"ar-PS" => :"he-IL") assert_equal [:ar, :"en-US", :en], @fallbacks[:ar] end test "with a Hebrew mapping defined it returns [:ar-EG, :ar, :en-US] for :ar-EG" do @fallbacks.map(:"ar-PS" => :"he-IL") assert_equal [:"ar-EG", :ar, :"en-US", :en], @fallbacks[:"ar-EG"] end test "with a Hebrew mapping defined it returns [:ar-PS, :ar, :he-IL, :he, :en-US] for :ar-PS" do @fallbacks.map(:"ar-PS" => :"he-IL") assert_equal [:"ar-PS", :ar, :"he-IL", :he, :"en-US", :en], @fallbacks[:"ar-PS"] end # Sami people live in several scandinavian countries. In Finnland many people # know Swedish and Finnish. Thus, it can be assumed that Sami living in # Finnland also speak Swedish and Finnish. test "with a Sami mapping defined it returns [:sms-FI, :sms, :se-FI, :se, :fi-FI, :fi, :en-US] for :sms-FI" do @fallbacks.map(:sms => [:"se-FI", :"fi-FI"]) assert_equal [:"sms-FI", :sms, :"se-FI", :se, :"fi-FI", :fi, :"en-US", :en], @fallbacks[:"sms-FI"] end # Austrian people understand German as spoken in Germany test "with a German mapping defined it returns [:de, :en-US] for de" do @fallbacks.map(:"de-AT" => :"de-DE") assert_equal [:de, :"en-US", :en], @fallbacks[:"de"] end test "with a German mapping defined it returns [:de-DE, :de, :en-US] for de-DE" do @fallbacks.map(:"de-AT" => :"de-DE") assert_equal [:"de-DE", :de, :"en-US", :en], @fallbacks[:"de-DE"] end test "with a German mapping defined it returns [:de-AT, :de, :de-DE, :en-US] for de-AT" do @fallbacks.map(:"de-AT" => :"de-DE") assert_equal [:"de-AT", :de, :"de-DE", :"en-US", :en], @fallbacks[:"de-AT"] end # Mapping :de => :en, :he => :en test "with a mapping :de => :en, :he => :en defined it returns [:de, :en] for :de" do assert_equal [:de, :"en-US", :en], @fallbacks[:de] end test "with a mapping :de => :en, :he => :en defined it [:he, :en] for :de" do assert_equal [:he, :"en-US", :en], @fallbacks[:he] end # Test allowing mappings that fallback to each other test "with :no => :nb, :nb => :no defined :no returns [:no, :nb, :en-US, :en]" do @fallbacks.map(:no => :nb, :nb => :no) assert_equal [:no, :nb, :"en-US", :en], @fallbacks[:no] end test "with :no => :nb, :nb => :no defined :nb returns [:nb, :no, :en-US, :en]" do @fallbacks.map(:no => :nb, :nb => :no) assert_equal [:nb, :no, :"en-US", :en], @fallbacks[:nb] end # Test I18n::Disabled is raised correctly when locale is false during fallback test "with locale equals false" do assert_raise I18n::Disabled do @fallbacks[false] end end end i18n-1.8.11/test/locale/tag/000077500000000000000000000000001414033570300153525ustar00rootroot00000000000000i18n-1.8.11/test/locale/tag/rfc4646_test.rb000066400000000000000000000121161414033570300200350ustar00rootroot00000000000000# encoding: utf-8 require 'test_helper' class I18nLocaleTagRfc4646ParserTest < I18n::TestCase include I18n::Locale test "Rfc4646::Parser given a valid tag 'de' returns an array of subtags" do assert_equal ['de', nil, nil, nil, nil, nil, nil], Tag::Rfc4646::Parser.match('de') end test "Rfc4646::Parser given a valid tag 'de-DE' returns an array of subtags" do assert_equal ['de', nil, 'DE', nil, nil, nil, nil], Tag::Rfc4646::Parser.match('de-DE') end test "Rfc4646::Parser given a valid lowercase tag 'de-latn-de-variant-x-phonebk' returns an array of subtags" do assert_equal ['de', 'latn', 'de', 'variant', nil, 'x-phonebk', nil], Tag::Rfc4646::Parser.match('de-latn-de-variant-x-phonebk') end test "Rfc4646::Parser given a valid uppercase tag 'DE-LATN-DE-VARIANT-X-PHONEBK' returns an array of subtags" do assert_equal ['DE', 'LATN', 'DE', 'VARIANT', nil, 'X-PHONEBK', nil], Tag::Rfc4646::Parser.match('DE-LATN-DE-VARIANT-X-PHONEBK') end test "Rfc4646::Parser given an invalid tag 'a-DE' it returns false" do assert_equal false, Tag::Rfc4646::Parser.match('a-DE') end test "Rfc4646::Parser given an invalid tag 'de-419-DE' it returns false" do assert_equal false, Tag::Rfc4646::Parser.match('de-419-DE') end end # Tag for the locale 'de-Latn-DE-Variant-a-ext-x-phonebk-i-klingon' class I18nLocaleTagSubtagsTest < I18n::TestCase include I18n::Locale def setup super subtags = %w(de Latn DE variant a-ext x-phonebk i-klingon) @tag = Tag::Rfc4646.new(*subtags) end test "returns 'de' as the language subtag in lowercase" do assert_equal 'de', @tag.language end test "returns 'Latn' as the script subtag in titlecase" do assert_equal 'Latn', @tag.script end test "returns 'DE' as the region subtag in uppercase" do assert_equal 'DE', @tag.region end test "returns 'variant' as the variant subtag in lowercase" do assert_equal 'variant', @tag.variant end test "returns 'a-ext' as the extension subtag" do assert_equal 'a-ext', @tag.extension end test "returns 'x-phonebk' as the privateuse subtag" do assert_equal 'x-phonebk', @tag.privateuse end test "returns 'i-klingon' as the grandfathered subtag" do assert_equal 'i-klingon', @tag.grandfathered end test "returns a formatted tag string from #to_s" do assert_equal 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon', @tag.to_s end test "returns an array containing the formatted subtags from #to_a" do assert_equal %w(de Latn DE variant a-ext x-phonebk i-klingon), @tag.to_a end end # Tag inheritance class I18nLocaleTagSubtagsTest < I18n::TestCase test "#parent returns 'de-Latn-DE-variant-a-ext-x-phonebk' as the parent of 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon'" do tag = Tag::Rfc4646.new(*%w(de Latn DE variant a-ext x-phonebk i-klingon)) assert_equal 'de-Latn-DE-variant-a-ext-x-phonebk', tag.parent.to_s end test "#parent returns 'de-Latn-DE-variant-a-ext' as the parent of 'de-Latn-DE-variant-a-ext-x-phonebk'" do tag = Tag::Rfc4646.new(*%w(de Latn DE variant a-ext x-phonebk)) assert_equal 'de-Latn-DE-variant-a-ext', tag.parent.to_s end test "#parent returns 'de-Latn-DE-variant' as the parent of 'de-Latn-DE-variant-a-ext'" do tag = Tag::Rfc4646.new(*%w(de Latn DE variant a-ext)) assert_equal 'de-Latn-DE-variant', tag.parent.to_s end test "#parent returns 'de-Latn-DE' as the parent of 'de-Latn-DE-variant'" do tag = Tag::Rfc4646.new(*%w(de Latn DE variant)) assert_equal 'de-Latn-DE', tag.parent.to_s end test "#parent returns 'de-Latn' as the parent of 'de-Latn-DE'" do tag = Tag::Rfc4646.new(*%w(de Latn DE)) assert_equal 'de-Latn', tag.parent.to_s end test "#parent returns 'de' as the parent of 'de-Latn'" do tag = Tag::Rfc4646.new(*%w(de Latn)) assert_equal 'de', tag.parent.to_s end # TODO RFC4647 says: "If no language tag matches the request, the "default" value is returned." # where should we set the default language? # test "#parent returns '' as the parent of 'de'" do # tag = Tag::Rfc4646.new *%w(de) # assert_equal '', tag.parent.to_s # end test "#parent returns an array of 5 parents for 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon'" do parents = %w(de-Latn-DE-variant-a-ext-x-phonebk-i-klingon de-Latn-DE-variant-a-ext-x-phonebk de-Latn-DE-variant-a-ext de-Latn-DE-variant de-Latn-DE de-Latn de) tag = Tag::Rfc4646.new(*%w(de Latn DE variant a-ext x-phonebk i-klingon)) assert_equal parents, tag.self_and_parents.map(&:to_s) end test "returns an array of 5 parents for 'de-Latn-DE-variant-a-ext-x-phonebk-i-klingon'" do parents = %w(de-Latn-DE-variant-a-ext-x-phonebk-i-klingon de-Latn-DE-variant-a-ext-x-phonebk de-Latn-DE-variant-a-ext de-Latn-DE-variant de-Latn-DE de-Latn de) tag = Tag::Rfc4646.new(*%w(de Latn DE variant a-ext x-phonebk i-klingon)) assert_equal parents, tag.self_and_parents.map(&:to_s) end end i18n-1.8.11/test/locale/tag/simple_test.rb000066400000000000000000000017721414033570300202360ustar00rootroot00000000000000# encoding: utf-8 require 'test_helper' class I18nLocaleTagSimpleTest < I18n::TestCase include I18n::Locale test "returns 'de' as the language subtag in lowercase" do assert_equal %w(de Latn DE), Tag::Simple.new('de-Latn-DE').subtags end test "returns a formatted tag string from #to_s" do assert_equal 'de-Latn-DE', Tag::Simple.new('de-Latn-DE').to_s end test "returns an array containing the formatted subtags from #to_a" do assert_equal %w(de Latn DE), Tag::Simple.new('de-Latn-DE').to_a end # Tag inheritance test "#parent returns 'de-Latn' as the parent of 'de-Latn-DE'" do assert_equal 'de-Latn', Tag::Simple.new('de-Latn-DE').parent.to_s end test "#parent returns 'de' as the parent of 'de-Latn'" do assert_equal 'de', Tag::Simple.new('de-Latn').parent.to_s end test "#self_and_parents returns an array of 3 tags for 'de-Latn-DE'" do assert_equal %w(de-Latn-DE de-Latn de), Tag::Simple.new('de-Latn-DE').self_and_parents.map { |tag| tag.to_s} end end i18n-1.8.11/test/run_all.rb000066400000000000000000000007761414033570300153330ustar00rootroot00000000000000def bundle_check `bundle check` == "Resolving dependencies...\nThe Gemfile's dependencies are satisfied\n" end def execute(command) puts command system command end gemfiles = %w(Gemfile) + Dir['gemfiles/Gemfile*'].reject { |f| f.end_with?('.lock') } results = gemfiles.map do |gemfile| puts "\nBUNDLE_GEMFILE=#{gemfile}" ENV['BUNDLE_GEMFILE'] = File.expand_path("../../#{gemfile}", __FILE__) execute 'bundle install' unless bundle_check execute 'bundle exec rake test' end exit results.all? i18n-1.8.11/test/run_one.rb000066400000000000000000000004171414033570300153340ustar00rootroot00000000000000def bundle_check `bundle check` == "Resolving dependencies...\nThe Gemfile's dependencies are satisfied\n" end def execute(command) puts command system command end execute 'bundle install' unless bundle_check execute "bundle exec ruby -w -I'lib:test' #{ARGV[0]}" i18n-1.8.11/test/test_data/000077500000000000000000000000001414033570300153105ustar00rootroot00000000000000i18n-1.8.11/test/test_data/locales/000077500000000000000000000000001414033570300167325ustar00rootroot00000000000000i18n-1.8.11/test/test_data/locales/de.po000066400000000000000000000040041414033570300176600ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: version 0.0.1\n" "POT-Creation-Date: 2009-02-26 19:50+0100\n" "PO-Revision-Date: 2009-02-18 14:53+0100\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" # #: app/helpers/translation_helper.rb:3 # msgid "%{relative_time} ago" # msgstr "vor %{relative_time}" #: app/views/cars/show.html.erb:5 msgid "Axis" msgid_plural "Axis" msgstr[0] "Achse" msgstr[1] "Achsen" #: app/controllers/cars_controller.rb:47 msgid "Car was successfully created." msgstr "Auto wurde erfolgreich gespeichert" #: app/controllers/cars_controller.rb:64 msgid "Car was successfully updated." msgstr "Auto wurde erfolgreich aktualisiert" #: app/views/cars/show.html.erb:1 locale/model_attributes.rb:3 msgid "Car|Model" msgstr "Modell" #: app/views/cars/show.html.erb:3 locale/model_attributes.rb:4 msgid "Car|Wheels count" msgstr "Räderzahl" msgctxt "New car" msgid "Wheels count" msgstr "Räderzahl!" #: app/views/cars/show.html.erb:7 msgid "Created" msgstr "Erstellt" #: app/views/cars/show.html.erb:9 msgid "Month" msgstr "Monat" #: locale/model_attributes.rb:2 msgid "car" msgstr "Auto" #: locale/testlog_phrases.rb:2 msgid "this is a dynamic translation which was found thorugh gettext_test_log!" msgstr "" "Dies ist eine dynamische Übersetzung, die durch gettext_test_log " "gefunden wurde!" #: app/views/cars/nowhere_really msgid "Car|wheel" msgid_plural "Car|wheels" msgstr[0] "Rad" msgstr[1] "Räder" msgctxt "New car" msgid "wheel" msgid_plural "wheels" msgstr[0] "Rad!" msgstr[1] "Räder!" msgid "On %{count} wheel." msgid_plural "On %{count} wheels." msgstr[0] "Auf %{count} Achse." msgstr[1] "Auf %{count} Achsen." i18n-1.8.11/test/test_data/locales/en.json000066400000000000000000000000701414033570300202240ustar00rootroot00000000000000{ "en": { "foo": { "bar": "baz" } } } i18n-1.8.11/test/test_data/locales/en.rb000066400000000000000000000000731414033570300176610ustar00rootroot00000000000000# encoding: utf-8 { :en => { :fuh => { :bah => "bas" } } }i18n-1.8.11/test/test_data/locales/en.yaml000066400000000000000000000000271414033570300202170ustar00rootroot00000000000000en: foo: bar: bazi18n-1.8.11/test/test_data/locales/en.yml000066400000000000000000000000301414033570300200500ustar00rootroot00000000000000en: foo: bar: baz i18n-1.8.11/test/test_data/locales/invalid/000077500000000000000000000000001414033570300203605ustar00rootroot00000000000000i18n-1.8.11/test/test_data/locales/invalid/empty.yml000066400000000000000000000000001414033570300222270ustar00rootroot00000000000000i18n-1.8.11/test/test_data/locales/invalid/syntax.yml000066400000000000000000000000351414033570300224270ustar00rootroot00000000000000en: foo: foo bar: baz:i18n-1.8.11/test/test_data/locales/plurals.rb000066400000000000000000000353451414033570300207530ustar00rootroot00000000000000# encoding: utf-8 { :af => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :am => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :ar => { :i18n => { :plural => { :keys => [:zero, :one, :two, :few, :many, :other], :rule => lambda { |n| n == 0 ? :zero : n == 1 ? :one : n == 2 ? :two : [3, 4, 5, 6, 7, 8, 9, 10].include?(n % 100) ? :few : [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].include?(n % 100) ? :many : :other } } } }, :az => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :be => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, :bg => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :bh => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :bn => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :bo => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :bs => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, :ca => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :cs => { :i18n => { :plural => { :keys => [:one, :few, :other], :rule => lambda { |n| n == 1 ? :one : [2, 3, 4].include?(n) ? :few : :other } } } }, :cy => { :i18n => { :plural => { :keys => [:one, :two, :many, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : n == 8 || n == 11 ? :many : :other } } } }, :da => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :de => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :dz => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :el => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :en => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :eo => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :es => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :et => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :eu => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :fa => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :fi => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :fil => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :fo => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :fr => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n.between?(0, 2) && n != 2 ? :one : :other } } } }, :fur => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :fy => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :ga => { :i18n => { :plural => { :keys => [:one, :two, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } } }, :gl => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :gu => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :guw => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :ha => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :he => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :hi => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :hr => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, :hu => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :id => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :is => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :it => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :iw => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :ja => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :jv => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :ka => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :km => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :kn => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :ko => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :ku => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :lb => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :ln => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :lt => { :i18n => { :plural => { :keys => [:one, :few, :other], :rule => lambda { |n| n % 10 == 1 && ![11, 12, 13, 14, 15, 16, 17, 18, 19].include?(n % 100) ? :one : [2, 3, 4, 5, 6, 7, 8, 9].include?(n % 10) && ![11, 12, 13, 14, 15, 16, 17, 18, 19].include?(n % 100) ? :few : :other } } } }, :lv => { :i18n => { :plural => { :keys => [:zero, :one, :other], :rule => lambda { |n| n == 0 ? :zero : n % 10 == 1 && n % 100 != 11 ? :one : :other } } } }, :mg => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :mk => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n % 10 == 1 ? :one : :other } } } }, :ml => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :mn => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :mo => { :i18n => { :plural => { :keys => [:one, :few, :other], :rule => lambda { |n| n == 1 ? :one : n == 0 ? :few : :other } } } }, :mr => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :ms => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :mt => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n == 1 ? :one : n == 0 || [2, 3, 4, 5, 6, 7, 8, 9, 10].include?(n % 100) ? :few : [11, 12, 13, 14, 15, 16, 17, 18, 19].include?(n % 100) ? :many : :other } } } }, :my => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :nah => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :nb => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :ne => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :nl => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :nn => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :no => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :nso => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :oc => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :om => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :or => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :pa => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :pap => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :pl => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n == 1 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : (n != 1 && [0, 1].include?(n % 10)) || [5, 6, 7, 8, 9].include?(n % 10) || [12, 13, 14].include?(n % 100) ? :many : :other } } } }, :ps => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :pt => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :"pt-PT" => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :ro => { :i18n => { :plural => { :keys => [:one, :few, :other], :rule => lambda { |n| n == 1 ? :one : n == 0 ? :few : :other } } } }, :ru => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, :se => { :i18n => { :plural => { :keys => [:one, :two, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } } }, :sh => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, :sk => { :i18n => { :plural => { :keys => [:one, :few, :other], :rule => lambda { |n| n == 1 ? :one : [2, 3, 4].include?(n) ? :few : :other } } } }, :sl => { :i18n => { :plural => { :keys => [:one, :two, :few, :other], :rule => lambda { |n| n % 100 == 1 ? :one : n % 100 == 2 ? :two : [3, 4].include?(n % 100) ? :few : :other } } } }, :sma => { :i18n => { :plural => { :keys => [:one, :two, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } } }, :smi => { :i18n => { :plural => { :keys => [:one, :two, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } } }, :smj => { :i18n => { :plural => { :keys => [:one, :two, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } } }, :smn => { :i18n => { :plural => { :keys => [:one, :two, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } } }, :sms => { :i18n => { :plural => { :keys => [:one, :two, :other], :rule => lambda { |n| n == 1 ? :one : n == 2 ? :two : :other } } } }, :so => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :sq => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :sr => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, :sv => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :sw => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :ta => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :te => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :th => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :ti => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :tk => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :tl => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :to => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :tr => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :uk => { :i18n => { :plural => { :keys => [:one, :few, :many, :other], :rule => lambda { |n| n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other } } } }, :ur => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } }, :vi => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :wa => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| [0, 1].include?(n) ? :one : :other } } } }, :yo => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :zh => { :i18n => { :plural => { :keys => [:other], :rule => lambda { |n| :other } } } }, :zu => { :i18n => { :plural => { :keys => [:one, :other], :rule => lambda { |n| n == 1 ? :one : :other } } } } } i18n-1.8.11/test/test_helper.rb000066400000000000000000000023141414033570300162030ustar00rootroot00000000000000require 'minitest/autorun' TEST_CASE = defined?(Minitest::Test) ? Minitest::Test : MiniTest::Unit::TestCase # TODO: Remove these aliases and update tests accordingly. class TEST_CASE alias :assert_raise :assert_raises alias :assert_not_equal :refute_equal def assert_nothing_raised(*args) yield end end require 'bundler/setup' require 'i18n' require 'mocha/setup' require 'test_declarative' class I18n::TestCase < TEST_CASE def self.key_value? defined?(ActiveSupport) end def setup super I18n.load_path = nil I18n.enforce_available_locales = false end def teardown I18n.locale = nil I18n.default_locale = nil I18n.load_path = nil I18n.available_locales = nil I18n.backend = nil I18n.default_separator = nil I18n.enforce_available_locales = true I18n.fallbacks = nil if I18n.respond_to?(:fallbacks=) super end protected def translations I18n.backend.instance_variable_get(:@translations) end def store_translations(locale, data) I18n.backend.store_translations(locale, data) end def locales_dir File.dirname(__FILE__) + '/test_data/locales' end end class DummyRackApp def call(env) I18n.locale = :es end end