activescaffold / active_scaffold

Save time and headaches, and create a more easily maintainable set of pages, with ActiveScaffold. ActiveScaffold handles all your CRUD (create, read, update, delete) user interface needs, leaving you more time to focus on more challenging (and interesting!) problems.
MIT License
1.09k stars 327 forks source link

Can't use I18n for confirmation messages #649

Open spatarel opened 3 years ago

spatarel commented 3 years ago

How to replicate:

#/app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :set_locale

  def set_locale
    if request.subdomains.first == 'ro'
      I18n.locale = 'ro'
    elsif request.subdomains.first == 'en'
      I18n.locale = 'en'
    else
      I18n.locale = 'en'
    end
  end
end

#/app/controllers/some_table_controller.rb
class SomeTableController < ApplicationController
  active_scaffold :some_table do |conf|
    conf.action_links.add :some_action,
      type: :collection, crud_type: :update,
      method: :put, position: false,
      confirm: I18n.t('some_table.some_action.confirmation_message')
  end
end

Expected behaviour: The confirmation message should be translated in ro or en, depdending on the subdomain.

Actual behaviour: The confirmation message is translated in the default language.

Why is this happening? set_locale method runs after active_scaffold is configured.

How to fix it?

Option 1: Allow confirm parameter to be either a string or a Proc. Then this code should work:

#/active_scaffold/lib/active_scaffold/data_structures/action_link.rb
    def confirm(label = '')
      return @confirm if !confirm? || @confirm.is_a?(String)
      return @confirm.call if !confirm? || @confirm.is_a?(Proc) # this line is new
      ActiveScaffold::Registry.cache(:translations, @confirm) { as_(@confirm) } % {label: label}
    end

#/app/controllers/some_table_controller.rb
class SomeTableController < ApplicationController
  active_scaffold :some_table do |conf|
    conf.action_links.add :some_action,
      type: :collection, crud_type: :update,
      method: :put, position: false,
      confirm: -> { I18n.t('some_table.some_action.confirmation_message') } # this line is changed
  end
end

Option 2: Perhaps there is some other way of sending that confirmation message. But I don't understand what this line does: ActiveScaffold::Registry.cache(:translations, @confirm) { as_(@confirm) } % {label: label}

Conclusion: I would choose Option 1, since even if there is already support for Option 2, Option 1 offers more flexibility.

scambra commented 3 years ago

If you put I18n.t in active_scaffold block, is evaluated when app starts, so language doesn't change. You must set a symbol there, then active_scaffold will translate it, it will look for symbol under active_scaffold scope.

ActiveScaffold::Registry.cache is caching translation for current action, because when you have a long list, with many rows with same actions, it's faster to translate one and then use interpolation to replace %{label}, than translate many times.

spatarel commented 3 years ago

It works like a charm! Thank you!

I will write down what I did, in case other people are interested in the topic:

#/config/locales/ro.yml
ro:
  active_scaffold:
    some_action_confirmation: 'RO message'

#/config/locales/en.yml
en:
  active_scaffold:
    some_action_confirmation: 'EN message'

#/app/controllers/some_table_controller.rb
class SomeTableController < ApplicationController
  active_scaffold :some_table do |conf|
    conf.action_links.add :some_action,
      type: :collection, crud_type: :update,
      method: :put, position: false,
      confirm: :some_action_confirmation
  end
end

I suppose there's no chance for Proc support, right?

scambra commented 3 years ago

I could accept a patch supporting proc, but I don't know if it would be any improvement