Locale/localeapp

Rails: Missing translations not sent anymore

A5308Y opened this issue · 9 comments

It seems like a similar problem like the one in #126.
Using I18.t() instead of t() works. But with t() the log does not show the

** [Localeapp] translation missing: de-CH.dashboard

I would expect and nothing gets sent to locale.

I don't have a clear indication of when the change happened. (The translators didn't want to bother us programmers again, with the same thing.) But in #126 @markedmondson wrote he saw the problem in RCs of Rails 4.1 which lead me here:

kassio/rails@433628a

which might mean something to you. This discussion: rails/rails#13429 might also be helpful.

Thanks a lot in advance!
Andy

Yep, I'm seeing the same thing with Rails 4.1.4. As soon as I prefixed I18n. to my t() call, then missing translations went up.

lou commented

I have the exact same issue with Rails 4.1.7
I'd like to use the t() method but it doesn't work.
It only works with the I18n prefix.
Does someone found a workaround ?

lou commented

It seems that Rails has moved all the translate logic in ActionView.
So I have added the following i18n_helper.rb to my app, and it works as expected (on Rails 4.1.7):

module I18nHelper
  def translate(key, options={})
    super(key, options.merge(raise: true))
  rescue I18n::MissingTranslationData
    if Rails.env.development?
      if key.first == '.'
        tk = "#{controller.class.name.gsub('::', '.').gsub('Controller', '').downcase}.#{action_name}#{key}"
      else
        tk = key
      end
      Localeapp.sender.post_translation(I18n.locale, tk, options)
    end
    super(key, options)
  end
  alias :t :translate
end

Thanks @lou!
I got it working after reading your idea!
But I had to do some things a little differently. I'll write that down for others having a similar problem:

First: A missing dot.

tk = "#{controller_name}.#{action_name}#{key}"

should be:

tk = "#{controller_name}.#{action_name}.#{key}"

Secondly: The translation key should only be built with controller and action_name, if the first character of a translation is a ".":

translation_key = key.first == '.' ? "#{controller_name}.#{action_name}.#{key}" : key

Thirdly: I had trouble loading the helper at the right place. I ended up including it in initializers/localeapp.rb like this:

module ActionView

  module Helpers
    module TranslationHelper
      def t

This meant that I couldn't use super anymore though, because I'm overwriting the method here. So I defined t explicitly and used translate in this method. This only works because we never use translate (always t) in the views!

So I'd say this should only be a temporary fix. I think the "right way" should be to use a custom exception handler instead. That's the way the do it in this gem right?
I wrote a support request to localeapp on November 11th, but haven't received an answer yet.

lou commented

Hi @A5308H,
I have updated my code.
It now reflects what you mentioned with the translation keys which do not begin with a "."
And it also handles the case when controller is nested under namespaces.

I think that this solution is not ideal because it's very slow when you have many missing translation keys.
Indeed it will send N requests to localeapp server with N representing the number of translation keys present on the page.
Maybe we can intercept the missing translations and construct an Array with it and send the whole Array of translation keys only one time. I suspect it will not be easy to find the right hooks to achieve this.

lou commented

So I finally found the solution inside the localeapp gem code.
There is a method to add missing translations and they are already send in an after_filter method by the gem.
So we just have to add missing translations in our helper and also deactivate the Localeapp caching system so it does not keep deleted translations keys.

Here is the full code:

config/initializers/localeapp.rb :

require 'localeapp/rails'

Localeapp.configure do |config|
  ...
  config.polling_environments = [:development]
  config.cache_missing_translations = false
end

app/helpers/i18n_helper.rb :

module I18nHelper
  def translate(key, options={})
    super(key, options.merge(raise: true))
  rescue I18n::MissingTranslationData
    if Rails.env.development?
      if key.first == '.'
        tk = "#{controller.class.name.gsub('::', '.').gsub('Controller', '').downcase}.#{action_name}#{key}"
      else
        tk = key
      end
      Localeapp.missing_translations.add(I18n.locale, tk)
    end
    super(key, options)
  end
  alias :t :translate
end

OK, there was a regression bug introduced in Rails 4.1 that prevents custom exception handlers form being called.

I've submitted rails/rails#17676 which addresses the issue but in the mean time, overloading the translate might be the best option (even if it is quite yucky). Using I18n.t instead of just t bypasses ActionView so that is also a possible temporary solution also.

I'm looking into what we can do from within the gem itself right now.

Thanks @tigrish!

This should be fixed in gem version 0.9.1