Cyril Duchon-Doris
Cyril Duchon-Doris

Reputation: 13939

Intercept and handle missing translations in helper

I have a helper function that generates useful HTML markup. My functions are usually called with some parameters, including some text translated with I18n my_helper( t(:translation_symbol) ).

I use I18n t translation helper for that, which (if left untouched) outputs some <span class="translation missing">...</span> for texts without translation

I was wondering how to best "intercept" this translation missing so

In my views I should be able to call both

<%= my_helper(t(:my_text)) %> # My helper needs to handle missing translations
<%= t(:my_text) %> # I want default I18n markup (or a custom one) '<span class="translation missing">fr.my_text</span>

My helper

def my_helper(text=nil)
  # Suppose my_text doesn't have a translation, text will have value 
  # => '<span class="translation-missing">fr.my_text</span>'
  if translation_missing?(text)
    # Code to handle missing translation
    doSomething(remove_translation_missing_markup(text))
    notify_translation_missing
  else
    doSomething(text)
  end
end

def translation_missing?(text)
  # Uses some regex pattern to detect '<span class="translation-missing">'
end
def remove_translation_missing_markup(text)
  # Uses some regex pattern to extract my_text from '<span class="translation-missing">fr.my_text</span>'
end

Is there a better way around this ? I feel bad about using a dirty regex solution.

EDIT : extra requirements

EDIT2 : I am thinking of something like that

Upvotes: 3

Views: 1520

Answers (3)

Paul Fioravanti
Paul Fioravanti

Reputation: 16793

Since missing translations seems to be a pain point in your app, rather than have your app code be constantly on the lookout for whether a translation exists or not, if possible I would advocate ensuring that you always have translations for every potential call to t, regardless of locale (this is all on the assumption that the :translation_symbol keys in your calls to my_helper(t(:translation_symbol)) are all static, kept in your config/locales directory, and aren't generated dynamically).

You can do this using the I18n-tasks gem to:

  • Ensure your app does not have missing or unused keys, so you should be able to delete the missing translation handling parts of your helper methods
  • Make your test suite/build process fail if there are any missing or unused translations, so no one else that touches the codebase accidentally sneaks any through. See instructions on copying over their RSpec test.

Upvotes: 2

Matouš Bor&#225;k
Matouš Bor&#225;k

Reputation: 15944

I think you can leverage the fact that I18n can be configured to raise an exception when translation missing. You can either set ActionView::Base.raise_on_missing_translations = true to globally raise the exception upon missing translations or you can pass :raise => true option to the t translation helper.

Update: since you are already using t helpers in your views and you don't want to change them, I think the only option for you is overriding the t helper in your ApplicationHelper:

# ApplicationHelper

def t(key, options = {})
  # try to translate as usual
  I18n.t(key, options.merge(raise: true)
rescue I18n::MissingTranslationData => e
  # do whatever you want on translation missing, e.g. send notification to someone
  # ...
  "Oh-oh!"
end

This helper either returns the translated text or "oh-oh" if translation missing. And it should work as-is in your current views.

Upvotes: 3

Prakash Murthy
Prakash Murthy

Reputation: 13057

Why not set the default option to the translate method as follows:

<%= t(:my_text, default: "not here") %>

See http://guides.rubyonrails.org/i18n.html#defaults for details about setting defaults for the I18n.translate method.

Upvotes: 1

Related Questions