├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Gemfile ├── LICENSE.txt ├── README.md ├── Rakefile ├── i18n-debug.gemspec ├── lib └── i18n │ ├── debug.rb │ └── debug │ └── version.rb └── test └── test_i18n_debug.rb /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | *.gem 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: ruby 3 | cache: bundler 4 | script: "bundle exec rake test" 5 | rvm: 6 | - 2.4.3 7 | - 2.5.0 8 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | # 1.2.0 4 | 5 | - Don't change method visibility of `#lookup` (#8, @aleksandrs-ledovskis) 6 | 7 | ## 1.1.1 8 | 9 | - Update i18n version 10 | - Make Rails logger check more robust 11 | 12 | ## 1.1.0 13 | 14 | - Use `Module#prepend` instead of aliasing methods. 15 | - Allow hook to be defined as a block to `#on_lookup`. 16 | 17 | ## 1.0.0 18 | 19 | - Initial release 20 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | gemspec 3 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Philipe Fatio 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby I18n Debug 2 | 3 | [![Build Status][build-image]][build-link] 4 | [![Gem Version][gem-image]][gem-link] 5 | 6 | **Ever wondered which translations are being looked up by Rails, a gem, or 7 | simply your app? Wonder no more!** 8 | 9 | Rails' implicit translations, for instance, are a nice feature. But sometimes 10 | getting the key to, let's say, the `BillingAddress`' `street` attribute in 11 | a nested form inside an `Order` can be quite tricky to get right on the first 12 | try. The key for this example would be 13 | `activerecord.attributes.order/billing_address.street`. Good luck figuring that 14 | out! 15 | 16 | With this gem you can easily see which translations are being looked up. The key 17 | above would have created the following debug log entry: 18 | 19 | ``` 20 | [i18n-debug] activerecord.attributes.order/billing_address.name => nil 21 | ``` 22 | 23 | After setting the translation for that key you just discovered, the log entry 24 | changes to this: 25 | 26 | ``` 27 | [i18n-debug] activerecord.attributes.order/billing_address.name => "Order billing name" 28 | ``` 29 | 30 | ## Installation 31 | 32 | Simply add the gem to your `Gemfile`. You probably only want this in development. 33 | Thus, place it inside the `development` group. 34 | 35 | ```ruby 36 | gem 'i18n-debug', group: :development 37 | ``` 38 | 39 | If you need support for ruby <= 2.0, make sure to use version 1.0.0. 40 | 41 | ## Usage 42 | 43 | This gem works straight out of the box. If Rails is available, it will log using 44 | `Rails.logger.debug`. Otherwise it will log using `Logger.new($stdout).debug`. 45 | 46 | If you wish to use a custom logger, simply set it as follows (make sure it 47 | responds to `debug`): 48 | 49 | ```ruby 50 | I18n::Debug.logger = my_custom_logger 51 | ``` 52 | 53 | Every lookup invokes the lambda `I18n::Debug.on_lookup` with the key and the 54 | translation value as arguments. The default lambda simply logs it to the logger 55 | mentioned above. If you want to change the logging format or do something 56 | totally different, simply set your own handler to do so: 57 | 58 | ```ruby 59 | # Collect stats on I18n key usage. 60 | i18n_stats = Hash.new { |stats, key| stats[key] = 0 } 61 | 62 | I18n::Debug.on_lookup do |key, value| 63 | i18n_stats[key] += 1 if value 64 | end 65 | ``` 66 | 67 | ## Additional Information 68 | 69 | ### Dependencies 70 | 71 | - [i18n](https://github.com/svenfuchs/i18n) 72 | 73 | ### Author 74 | 75 | Philipe Fatio ([fphilipe](https://github.com/fphilipe)) 76 | 77 | ### License 78 | 79 | MIT License. Copyright 2014 Philipe Fatio 80 | 81 | [build-image]: https://travis-ci.org/fphilipe/i18n-debug.svg 82 | [build-link]: https://travis-ci.org/fphilipe/i18n-debug 83 | [gem-image]: https://badge.fury.io/rb/i18n-debug.svg 84 | [gem-link]: https://rubygems.org/gems/i18n-debug 85 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/testtask' 3 | 4 | Rake::TestTask.new(:test) do |t| 5 | t.libs << 'test' 6 | end 7 | 8 | task :default => :test 9 | -------------------------------------------------------------------------------- /i18n-debug.gemspec: -------------------------------------------------------------------------------- 1 | require File.expand_path('../lib/i18n/debug/version', __FILE__) 2 | 3 | Gem::Specification.new do |spec| 4 | spec.name = 'i18n-debug' 5 | spec.version = I18n::Debug::VERSION 6 | spec.author = 'Philipe Fatio' 7 | spec.email = 'me@phili.pe' 8 | spec.homepage = 'https://github.com/fphilipe/i18n-debug' 9 | spec.license = 'MIT' 10 | spec.files = `git ls-files -z`.split("\x0") 11 | spec.test_files = `git ls-files -z -- test`.split("\x0") 12 | spec.summary = %q{Ever wondered which translations are being looked up by Rails, a gem, or simply your app? Wonder no more!} 13 | spec.description = spec.summary 14 | 15 | spec.add_development_dependency 'bundler', '~> 1.7' 16 | spec.add_development_dependency 'rake', '~> 10.0' 17 | spec.add_development_dependency 'minitest', '~> 5.8' 18 | spec.add_dependency 'i18n', '< 2' 19 | end 20 | -------------------------------------------------------------------------------- /lib/i18n/debug.rb: -------------------------------------------------------------------------------- 1 | require 'i18n' 2 | require 'i18n/debug/version' 3 | 4 | module I18n 5 | module Debug 6 | @on_lookup = lambda do |key, result| 7 | logger.debug("[i18n-debug] #{key} => #{result.inspect}") 8 | end 9 | 10 | class << self 11 | attr_accessor :logger 12 | attr_writer :on_lookup 13 | 14 | def logger 15 | @logger ||= 16 | if defined?(::Rails) and ::Rails.respond_to?(:logger) 17 | ::Rails.logger 18 | else 19 | require 'logger' 20 | ::Logger.new($stdout) 21 | end 22 | end 23 | 24 | def on_lookup(&blk) 25 | return @on_lookup unless block_given? 26 | self.on_lookup = blk 27 | end 28 | end 29 | 30 | module Hook 31 | protected 32 | 33 | def lookup(*args) 34 | super.tap do |result| 35 | options = args.last.is_a?(Hash) ? args.pop : {} 36 | separator = options[:separator] || I18n.default_separator 37 | key = I18n.normalize_keys(*args, separator).join(separator) 38 | Debug.on_lookup[key, result] 39 | end 40 | end 41 | end 42 | end 43 | 44 | Backend::Simple.prepend(Debug::Hook) 45 | end 46 | -------------------------------------------------------------------------------- /lib/i18n/debug/version.rb: -------------------------------------------------------------------------------- 1 | module I18n 2 | module Debug 3 | VERSION = '1.2.0' 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /test/test_i18n_debug.rb: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 2 | require 'i18n/debug' 3 | require 'minitest/autorun' 4 | 5 | class TestI18nDebug < Minitest::Test 6 | alias_method :silence_io, :capture_io 7 | 8 | def setup 9 | I18n.backend.store_translations(:en, foo: { bar: 'baz' }) 10 | # Avoid I18n deprecation warning: 11 | I18n.enforce_available_locales = true 12 | # Reset logger to its initial state: 13 | I18n::Debug.logger = nil 14 | end 15 | 16 | def test_does_not_alter_default_i18n_behavior 17 | silence_io do 18 | assert_equal I18n.t('foo.bar'), 'baz' 19 | end 20 | end 21 | 22 | def test_does_not_alter_default_i18n_lookup_method_visibility 23 | assert I18n.backend.class.protected_method_defined?(:lookup) 24 | end 25 | 26 | def test_logger_invoked 27 | assert_output(/en\.foo\.bar => "baz"/) do 28 | I18n.t('foo.bar') 29 | end 30 | end 31 | 32 | def test_custom_lookup_hook_called 33 | default_hook = I18n::Debug.on_lookup 34 | hook_key, hook_value = nil 35 | I18n::Debug.on_lookup do |key, value| 36 | hook_key, hook_value = key, value 37 | end 38 | 39 | I18n.t('foo.bar') 40 | 41 | assert_equal hook_key, 'en.foo.bar' 42 | assert_equal hook_value, 'baz' 43 | ensure 44 | I18n::Debug.on_lookup = default_hook 45 | end 46 | end 47 | --------------------------------------------------------------------------------