Show translation missing in rails 3 like the rails 2 way - ruby-on-rails

Since I'm using rails 3 there are a lot of translation missing records in production environment because of the way translation missing strings are handled in rails 3, for example the output of translation missing is now :
<span class="translation_missing" title="translation missing: fr.admin.orders_logs.update.title">Title</span>
In our application we see "Title" so we think the translation is ok but infact the translation is missing, if I"m not wrong the displayed text was "translation missing: fr.admin.orders_logs.update.title" in Rails 2.X
How I can activate this again that he shows me the error message instead of putting it just as title in a span?

This seems to be a feature in Rails. See: https://gist.github.com/rails/rails/issues/6489
A possible fix is to override the culprit by placing something like this to application.rb:
module ActiveModel
module Translation
def human_attribute_name(attribute, options = {})
defaults = []
parts = attribute.to_s.split(".", 2)
attribute = parts.pop
namespace = parts.pop
if namespace
lookup_ancestors.each do |klass|
defaults << :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}"
end
defaults << :"#{self.i18n_scope}.attributes.#{namespace}.#{attribute}"
else
lookup_ancestors.each do |klass|
defaults << :"#{self.i18n_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}"
end
end
defaults << :"attributes.#{attribute}"
defaults << options.delete(:default) if options[:default]
defaults << "MISSING TRANSLATION"+defaults.to_yaml # defaults << attribute.humanize
options.reverse_merge! :count => 1, :default => defaults
I18n.translate(defaults.shift, options)
end
end
end

Have you tried setting the i18n.fallbacks config to false?
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = false

Related

Modify Rails i18n config during a test?

I'm trying to test a Rails plugin to make sure that the correct action is performed with or without fallbacks turned on. Inside my Dummy application's configuration, I have:
module Dummy
class Application < Rails::Application
config.i18n.fallbacks = true
end
end
How can I flip this back to false for a specific test? So far I have tried:
Dummy::Application.config.i18n.fallbacks = false
Dummy::Application.configure do |app|
app.config.i18n.fallbacks = false
end
Rails.application.config.i18n.fallbacks = false
All to no avail.
This is an interesting question, actually once the app got initialized in the beginning, you couldn't change i18n configuration because it already got memoized with these codes:
# Setup i18n configuration.
def self.initialize_i18n(app)
return if #i18n_inited
...
#i18n_inited = true
end
And I18n.fallbacks was set with this line
I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
When you specify the callbacks as true, I18n.fallbacks has a value of
[1] pry(main)> I18n.fallbacks
=> {}
[2] pry(main)> I18n.fallbacks.class
=> I18n::Locale::Fallbacks
And I18n.fallbacks is used in this way:
locales.concat(I18n.fallbacks[I18n.locale]) if I18n.respond_to? :fallbacks
As long as I18n.respond_to? :fallbacks, the app will always have fallbacks feature turned on.
The method is defined here in I18n:
def fallbacks
##fallbacks ||= I18n::Locale::Fallbacks.new
end
To turn off the fallbacks feature, the only way is to make I18n.respond_to? :fallbacks return false.
Here you go:
class << I18n
remove_method :fallbacks
end

How to configure locale aliases using i18n & rails?

I am working on a rails app (3.2.13) that is being translated into several languages, including (one of the 3 available flavours of) Norwegian. On public pages, the app uses the browser's language settings to set locale.
Most browsers offer 3 separate Norwegian shortcodes: no, nb & nn. The translations we have are in nb, but I think it would be best if no & nn also defaulted to nb. That way, if a user's browser language preferences were set to no then en, the app would try to supply nb Norwegian first, instead of skipping straight to English.
Is it possible to configure a list of "language aliases" for the i18n gem, something like this?
config.i18n.available_locales = [:sv, :en, :nb, :da, :fi]
config.i18n.aliased_locales = [:nb <= :no, :nb <= :nn]
Short answer
Take a look to the fallbacks
Create a file in initializers like i18n_fallbacks.rb
config.i18n.fallbacks = {:no => [:nb], :nn => [:nb]}
Here the reference
Things related
You can even set multiple fallbacks, and they will be taken in the same order as specified:
for instance:
config.i18n.default_locale = :de
config.i18n.fallbacks = {:de => [:en,:es]}
de.yml
:de:
greeting: Hallo
en.yml
:en:
foo: bar
es.yml
:es:
bar: baz
You get the following:
I18n.t :greeting # found in de.yml, no fallback
# => 'Hallo'
I18n.t :foo # not in :de, try in :en and found
# => "bar"
I18n.t :bar # not in :de, try in :en and in :es
# => "baz"
I81n.t :other # not found anywhere, note the message delivers not found for the current locale:
# => "translation missing: de.other"
In latest i18n gem (0.7.0) I have found it necessary to define fallback locales like this (in config/application.rb):
# Custom I18n fallbacks
config.after_initialize do
I18n.fallbacks = I18n::Locale::Fallbacks.new(at: :"de-DE", ch: :"de-DE", gb: :"en-US")
end
You also need to set config.i18n.fallbacks = true in all config/environments/*.rb files.

Rails: How to raise I18n translation is missing exceptions in the testing environment

I want Rails to raise an exception when an I18n translation is missing in the testing environment (instead of rendering text 'translation missing'). Is there a simple way to achieve this?
As of Rails 4.1.0, there's now a better solution than the 4 year-old answers to this question: add the following line to your config file:
config.action_view.raise_on_missing_translations = true
I like to set this in the test environment only, but you might also want to set it in development. I would strongly advise against setting it to true in production.
To raise exceptions, you can define a class to handle localization errors.
class TestExceptionLocalizationHandler
def call(exception, locale, key, options)
raise exception.to_exception
end
end
Then you attach it to the desired test cases with
I18n.exception_handler = TestExceptionLocalizationHandler.new
This way you get exceptions raised. I don't know how to raise failures (with flunk) to get better results.
Or you can just add those lines to your config/test.rb
config.action_view.raise_on_missing_translations = true
config.i18n.exception_handler = Proc.new { |exception| raise exception.to_exception }
Rails 4.1+
To raise i18n translation missing exceptions you need two things:
1) An initializer config/initializers/i18n_force_exceptions.rb:
module I18n
class ForceMissingTranslationsHandler < ExceptionHandler
def call(exception, locale, key, options)
if Rails.env.test?
raise exception.to_exception
else
super
end
end
end
end
I18n.exception_handler = I18n::ForceMissingTranslationsHandler.new
2) A config setting in config/environments/test.rb (and other environments as needed):
config.action_view.raise_on_missing_translations = true
Note: The config setting is needed in addition to the exception handler because rails wraps calls to I18n.translate in it's view and helpers preventing exceptions from triggering.
I've created this initializer to raise an exception - args are passed so you will know which i18n key is missing!
# only for test
if Rails.env.test?
# raises exception when there is a wrong/no i18n key
module I18n
class JustRaiseExceptionHandler < ExceptionHandler
def call(exception, locale, key, options)
if exception.is_a?(MissingTranslation)
raise exception.to_exception
else
super
end
end
end
end
I18n.exception_handler = I18n::JustRaiseExceptionHandler.new
end
Source
If you're using rails between 4.0.0 to 4.1.0 you should monkey patch this way:
module ActionView::Helpers::TranslationHelper
def t_with_raise(*args)
value = t_without_raise(*args)
if value.to_s.match(/title="translation missing: (.+)"/)
raise "Translation missing: #{$1}"
else
value
end
end
alias_method :translate_with_raise, :t_with_raise
alias_method_chain :t, :raise
alias_method_chain :translate, :raise
end

How to use the I18n fallback features in Rails 3

I am getting an "translation missing" error message from Rails 3:
activerecord:
notices:
messages:
success:
create: "Something was created"
models:
user:
success:
create: "Thanks for registration"
I18n.t("activerecord.notices.models.user.success.create")
# => "Thanks for registration"
I18n.t("activerecord.notices.models.book.success.create")
# => "translation missing: de, activerecord, notices, models, book, success, create"
I don't know why the book model doesn't get the fallback massage. I have set config.i18n.fallbacks = true.
I set in config/application.rb usually
config.i18n.fallbacks = [:de, :fr, :en]
So you can declare the order of the fallback.
But keep attention in some environments/*.rb the configuration is overwritten.
When a :default option is given, its value will be returned if the translation is missing:
I18n.t :missing, :default => 'Not here'
# => 'Not here'
More info here
In rails 3+, this is set in the config/environments files :
# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = true
[Answer is for Rails 2]
Have you enabled fallbacks for your backend? Assuming it's Simple(based on yml in example):
Put this in an initializer:
require "i18n/backend/fallbacks"
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
https://github.com/svenfuchs/i18n/wiki/Fallbacks
I believe the best way to handle a missing string, is to display a default locale, rather than an error message.
Add this line in application.rb to fallback to the english locale.
config.i18n.fallbacks = [:en]
In case you want to specify locale-specific fallbacks, you can use the following:
config.i18n.fallbacks = {:de => [:de,:en], :en => [:en,:de]}
Also, note that you can enable and disable fallbacks based on your environment.
So while on development it might make sense to have an error displayed, you can instead enable fallbacks in your environments/production.rb with the following:
config.i18n.fallbacks = true
There is a misunderstanding with the I18n Fallback feature.
This feature causes that when there is a missing translation exception (in this case, it happens when I18n fails to find the value associated with the "activerecord.notices.models.book.success.create" key in the locale files of your current language) I18n will lookup in the predefined list of fallbacks languages the value of the key that generated the missing translation exception, if it's found I18n will returned that value, but if it's not found in any of those other locale files I18n will return the missing translation exception.
So when you defined config.i18n.fallbacks = true, that doesn't mean that when a missing translation exception occurs, in this case:
I18n.t("activerecord.models.book.success.create")
# => "translation missing: de, activerecord, notices, models, book, success, create"
I18n will lookup a similar key in your locale files to return his value, could be:
I18n.t("activerecord.models.user.success.create")
# => "Thanks for registration"
What will happens it's that I18n will lookup in yours defaults fallback languages for the specific language where the missing translation exception has occurred.
A good example of usage will be:
# using :"en-US" as a default locale:
I18n.default_locale = :"en-US"
I18n.fallbacks[:es] # => [:es, :"en-US", :en]
Locales files:
es:
activerecord:
notices:
messages:
success:
create: "Algo fue creado"
models:
user:
success:
create: "Gracias por registrarte"
en-US:
activerecord:
...
models:
books:
success:
create: "The model was created"
Call in English site:
I18n.t("activerecord.models.books.success.create")
# => "The model was created"
Call in Spanish site:
#with config.i18n.fallbacks = false
I18n.t("activerecord.models.books.success.create")
# => "translation missing: es, activerecord, models, book, success, create"
#with config.i18n.fallbacks = true
I18n.t("activerecord.models.books.success.create")
# => "The model was created"
For more information check: https://github.com/ruby-i18n/i18n

Rails not loading environment.rb correctly

I recently upgraded my application from Rails version 2.1.2 to version 2.2.2. It was tested in on development and on my staging system. When I moved to production it fails to load all the way through the environment.rb file. (Why, oh why, is it always on production!?!)
Below is my environment.rb file
# Be sure to restart your web server when you modify this file.
# Uncomment below to force Rails into production mode when
# you don't control web/app server and can't set it the proper way
# ENV['RAILS_ENV'] ||= 'production'
# Specifies gem version of Rails to use when vendor/rails is not present
#RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION
RAILS_GEM_VERSION = '2.2.2' unless defined? RAILS_GEM_VERSION
puts "loading rails..."
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')
puts "require boot file"
require 'socket'
puts "require socket"
Rails::Initializer.run do |config|
puts "inside config section"
# Settings in config/environments/* take precedence over those specified here
# Skip frameworks you're not going to use (only works if using vendor/rails)
# config.frameworks -= [ :action_web_service, :action_mailer ]
# Only load the plugins named here, by default all plugins in vendor/plugins are loaded
# config.plugins = %W( exception_notification ssl_requirement )
# Add additional load paths for your own custom dirs
# config.load_paths += %W( #{RAILS_ROOT}/extras )
# Force all environments to use the same logger level
# (by default production uses :info, the others :debug)
# config.log_level = :debug
# Use the database for sessions instead of the file system
# (create the session table with 'rake db:sessions:create')
config.action_controller.session_store = :active_record_store
puts "setting session store type"
# Use SQL instead of Active Record's schema dumper when creating the test database.
# This is necessary if your schema can't be completely dumped by the schema dumper,
# like if you have constraints or database-specific column types
# config.active_record.schema_format = :sql
# Activate observers that should always be running
# config.active_record.observers = :cacher, :garbage_collector
# Make Active Record use UTC-base instead of local time
# config.active_record.default_timezone = :utc
#config.gem "will_paginate", :source => "http://gems.rubyforge.org"
# Action Mailer configuration - from page 567-568 of the Agile Development book
# config.action_mailer.delivery_method = :smtp
#
config.action_mailer.smtp_settings = {
:address => "smtp.redacted.com",
:port => "25",
:domain => "redacted.com"
}
puts "setting smtp settings"
# See Rails::Configuration for more options
end
puts "outside config section ... before inflectors"
# Add new inflection rules using the following format
# (all these examples are active by default):
ActiveSupport::Inflector.inflections do |inflect|
# inflect.plural /^(ox)$/i, '\1en'
# inflect.singular /^(ox)en/i, '\1'
# inflect.irregular 'person', 'people'
# inflect.uncountable %w( fish sheep )
inflect.uncountable %w( sid fcc )
end
puts "after inflectors"
# Add new mime types for use in respond_to blocks:
# Mime::Type.register "text/richtext", :rtf
# Mime::Type.register "application/x-mobile", :mobile
# Include your application configuration below
require 'will_paginate'
puts "require will paginate"
# insert at top of ActiveRecord::Base.rb
# Indicates whether field names should be lowercased for legacy databse fields.
# If true, the field Product_Name will be +product_name+. If false, it will remain +Product_Name+.
# This is false, by default.
#cattr_accessor :downcase_legacy_field_names, :instance_writer => false
###downcase_legacy_field_names = false
# insert into column_methods_hash of ActiveRecord::Base.rb
# attr_final = downcase_legacy_field_names ? attr.to_s.downcase : attr
puts "here comes the monkey patch"
module ActiveRecord
class Base
# Indicates whether field names should be lowercased for legacy databse fields.
# If true, the field Product_Name will be +product_name+. If false, it will remain +Product_Name+.
# This is false, by default.
cattr_accessor :downcase_legacy_field_names, :instance_writer => false
##downcase_legacy_field_names = false
end
end
puts "monkey patch part 2"
# set all accessor methods to lowercase (underscore)
# add set_columns_to_lower to each model that needs it
class << ActiveRecord::Base
# Returns a hash of all the methods added to query each of the columns in the table with the name of the method as the key
# and true as the value. This makes it possible to do O(1) lookups in respond_to? to check if a given method for attribute
# is available.
def column_methods_hash #:nodoc:
#dynamic_methods_hash ||= column_names.inject(Hash.new(false)) do |methods, attr|
attr_final = downcase_legacy_field_names ? attr.to_s.downcase : attr
attr_name = attr_final
methods[attr_final.to_sym] = attr_name
methods["#{attr_final}=".to_sym] = attr_name
methods["#{attr_final}?".to_sym] = attr_name
methods["#{attr_final}_before_type_cast".to_sym] = attr_name
methods
end
end
# adapted from: http://wiki.rubyonrails.org/rails/pages/HowToUseLegacySchemas
def downcase_legacy_field_methods
column_names.each do |name|
next if name == primary_key
a = name.to_s.underscore
define_method(a.to_sym) do
read_attribute(name)
end
define_method("#{a}=".to_sym) do |value|
write_attribute(name, value)
end
define_method("#{a}?".to_sym) do
self.send("#{name}?".to_sym)
end
end
end
end
puts "monkey patch part 3"
ActiveRecord::Base.downcase_legacy_field_names = true
puts "monkey patch part 4"
module ActiveSupport
module Inflector
def textize(str)
str.to_s.gsub(/'/, '').downcase
#gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
#gsub(/([a-z\d])([A-Z])/,'\1_\2').
#tr("-", "_").
#downcase
end
end
end
puts "monkey patch part 5"
module ActiveSupport #:nodoc:
module CoreExtensions #:nodoc:
module String #:nodoc:
module Inflections
def textize
Inflector.textize(self)
end
end
end
end
end
###################################################################
### Code moved to the specific environment files.
### This way the schema gets reloaded on a deploy
###################################################################
## Establishes connections for the root classes of the various databases that
## must be connected to for SUI.
puts "load the database if we are in test mode"
if RAILS_ENV == "test" then
puts "if I see this and I'm not loading test, we have a problem"
Ird.load_database
end
puts "setting up the execption notifier"
ExceptionNotifier.exception_recipients = %w(me#redacted.com)
if RAILS_ENV == "Production"
ExceptionNotifier.sender_address = %("SUI Service" <service#redacted.com>)
ExceptionNotifier.email_prefix = "[SUI ERROR] "
else
ExceptionNotifier.sender_address = %("SUI #{RAILS_ENV.to_s.humanize} Service" <service#redacted.com>)
ExceptionNotifier.email_prefix = "[#{RAILS_ENV.to_s.humanize}: SUI ERROR] "
end
puts "local_ip function"
def local_ip
orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true
UDPSocket.open do |s|
s.connect '64.233.187.99', 1
s.addr.last
end
ensure
Socket.do_not_reverse_lookup = orig
end
puts "I am located at:#{local_ip}:"
puts "environment.rb is loaded"
If I set the rails gem to be used to version 2.1.2 everything loads and all the puts statements print as expected. When I change the gem version to 2.2.2 the last statement that I see printed is "setting smtp settings".
When I move the Rails::Initializer do |config| section to the bottom it fails in ways worse than where it is right now.
The ruby version that is loaded on the system is Ruby 1.8.6 patchlevel 111. It is running on RHEL5-64bit.
I'm stumped. Ideas? Suggestions?
Did you run rake rails:update?
Also, you might want to move most of the code into config/initializers/[anything].rb, allthough I hardly think that itself will solve your problems.

Resources