Skip to content

Commit

Permalink
Merge pull request #442 from platanus/enum-translations
Browse files Browse the repository at this point in the history
Enum translations
  • Loading branch information
difernandez committed Feb 17, 2023
2 parents 00fb5fd + e2bd5f9 commit beb1cd8
Show file tree
Hide file tree
Showing 14 changed files with 299 additions and 25 deletions.
13 changes: 10 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
version: 2.1

ruby-image: &ruby-image cimg/ruby:<<parameters.ruby-version>>
env-vars: &env-vars
RAILS_ENV: test
NODE_ENV: test
BUNDLE_PATH: vendor/bundle
SPROCKETS: false

orbs:
ruby: circleci/ruby@1.8.0
node: circleci/node@5.0.2
browser-tools: circleci/browser-tools@1.1.3

executors:
Expand All @@ -19,7 +18,7 @@ executors:
default: "2.7"
type: string
docker:
- image: cimg/ruby:<<parameters.ruby-version>>-node
- image: *ruby-image
environment: *env-vars

commands:
Expand All @@ -39,6 +38,7 @@ commands:
cd spec/dummy/
xargs -a Aptfile sudo apt-get install
sudo apt-get install libvips
sudo apt-get install file
- run:
name: Install bundle dependencies
command: |
Expand All @@ -52,6 +52,13 @@ commands:
- run:
name: Setup database
command: (cd spec/dummy && bundle exec rake db:setup)
- run:
name: Install node and yarn
command: |
curl -sL https://deb.nodesource.com/setup_$(cat .node-version).x | sudo -E bash -
sudo apt-get install -y nodejs
curl -o- -sL https://yarnpkg.com/install.sh | bash
sudo ln -s $HOME/.yarn/bin/yarn /usr/local/bin/yarn
- run:
name: Prepare Assets
command: |
Expand Down
1 change: 1 addition & 0 deletions .node-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
16
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
--format=doc
--require spec_helper
--color
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Unreleased

#### Changed

* Added translation support for Rails built-in enums in select filters and tag column/row [#442](https://github.com/platanus/activeadmin_addons/pull/442)

### 1.9.0

##### Changed
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ Installing this gem will enable the following changes by default:

* The default date input will be `:datepicker` instead of `:date_select`
* Filters and selects will offer integration with [enumerize](https://github.com/brainspec/enumerize)
* Select filters will show translated values when used with Rails built-in `enums`
* All select boxes will use select2

## Addons
Expand Down
16 changes: 16 additions & 0 deletions docs/enum_integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,19 @@ ActiveAdmin.register Invoice do
end
```

## Translation

Tag row and column, as well as the interactive option of the latter, support automatic translation with `I18n` when using Rails built-in `enums`. For this, you just have to define the translations in the correct path in your YAML files:

```yaml
# en.yml
en:
activerecord:
attributes:
invoice:
statuses:
active: Activo
archived: Archivado
```

This is the same structure used for tanslation of select inputs in filters and edit/create forms.
16 changes: 10 additions & 6 deletions lib/activeadmin_addons/addons/tag_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def select_tag

context.div(interactive_tag_select_params) do
context.select do
possible_values.each do |val|
context.option(value: val, selected: val == data) do
context.text_node val.capitalize
possible_values.each do |label, value|
context.option(value: value, selected: value == data) do
context.text_node label
end
end
end
Expand All @@ -36,7 +36,11 @@ def select_tag
end

def display_data
@enum_attr == :enumerize ? data.text : data
if @enum_attr == :enumerize
data.text
else
EnumUtils.translate_enum_option(model.class, attribute.to_s, data)
end
end

def interactive_params(klass)
Expand Down Expand Up @@ -69,9 +73,9 @@ def interactive_tag_select_params
def possible_values
klass = model.class
if @enum_attr == :enumerize
klass.enumerized_attributes[attribute.to_s].values
klass.enumerized_attributes[attribute.to_s].values.map { |value| [value.capitalize, value] }
else
klass.defined_enums[attribute.to_s].keys
EnumUtils.options_for_select(klass, attribute.to_s)
end
end

Expand Down
17 changes: 17 additions & 0 deletions lib/activeadmin_addons/support/enum_utils.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module ActiveAdminAddons
class EnumUtils
def self.options_for_select(klass, enum_name, use_db_value: false)
enum_options_hash = klass.defined_enums[enum_name]
enum_options_hash.map do |enum_option_name, db_value|
value = use_db_value ? db_value : enum_option_name
[translate_enum_option(klass, enum_name, enum_option_name), value]
end
end

def self.translate_enum_option(klass, enum_name, enum_option_name)

This comment has been minimized.

Copy link
@stadia

stadia Mar 6, 2023

if value of enum_option_name is blank, the view of tag_column is broken.
if it is blank, just need to return empty string, ""

This comment has been minimized.

Copy link
@difernandez

difernandez Mar 6, 2023

Author Contributor

Thanks for reporting this. You're right, it is not working correctly with blank enum_option_name, will make a PR to fix it

klass_key = klass.model_name.i18n_key
key = "activerecord.attributes.#{klass_key}.#{enum_name.pluralize}.#{enum_option_name}"
I18n.t(key, default: enum_option_name)
end
end
end
19 changes: 19 additions & 0 deletions lib/activeadmin_addons/support/select_filter_input_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module ActiveAdminAddons
module SelectFilterInputExtension
def collection_from_enum?
klass.respond_to?(:defined_enums) && klass.defined_enums.has_key?(method.to_s)
end

def collection
if !options[:collection] && collection_from_enum?
EnumUtils.options_for_select(klass, method.to_s, use_db_value: true)
else
super
end
end
end
end

::ActiveAdmin::Inputs::Filters::SelectInput.send(
:prepend, ActiveAdminAddons::SelectFilterInputExtension
)
3 changes: 3 additions & 0 deletions spec/dummy/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ en:
attributes:
invoice:
item_ids: Items
statuses:
active: Activo
archived: Archivado
activeadmin:
addons:
boolean:
Expand Down
6 changes: 6 additions & 0 deletions spec/features/inputs/select2_spec.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
require "rails_helper"

describe "Select 2", type: :feature do
let!(:initial_default_select) { ActiveadminAddons.default_select }

after do
ActiveadminAddons.default_select = initial_default_select
end

it { expect(ActiveadminAddons.default_select).to eq('select2') }

context "when default config is select 2" do
Expand Down
80 changes: 80 additions & 0 deletions spec/features/inputs/select_filter_input_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
require "rails_helper"

describe "Select Filter Input", type: :feature do
context 'when used with an enum column' do
let!(:active_invoice) { Invoice.create!(status: :active) }
let!(:archived_invoice) { Invoice.create!(status: :archived) }
let(:option_selector) { '.filter_form select[name="q[status_eq]"] option' }

context "with collection option" do
before do
register_page(Invoice) do
filter :status, as: :select, collection: [
['Activo, si se considera', 0],
['Archivado, ya no se considera', 1],
['Estado que no existe', 42]
]
end

visit admin_invoices_path
end

it "uses collection directly" do
expect(page.find("#{option_selector}[value='0']").text).to eq('Activo, si se considera')
expect(page.find("#{option_selector}[value='1']").text).to(
eq('Archivado, ya no se considera')
)
expect(page.find("#{option_selector}[value='42']").text).to eq('Estado que no existe')
end

it 'displays all records' do
expect(page).to have_css('.col-id', text: /#{active_invoice.id}/)
expect(page).to have_css('.col-id', text: /#{archived_invoice.id}/)
end

context 'when selecting a value', js: true do
before do
pick_select2_entered_option('Activo, si se considera')
click_filter_btn
end

it 'displays only elements with that value' do
expect(page).to have_css('.col-id', text: /#{active_invoice.id}/)
expect(page).not_to have_css('.col-id', text: /#{archived_invoice.id}/)
end
end
end

context "without collection option" do
before do
register_page(Invoice) do
filter :status, as: :select
end

visit admin_invoices_path
end

it "renders options with enum db values and translated labels" do
expect(page.find("#{option_selector}[value='0']").text).to eq('Activo')
expect(page.find("#{option_selector}[value='1']").text).to eq('Archivado')
end

it 'displays all records' do
expect(page).to have_css('.col-id', text: /#{active_invoice.id}/)
expect(page).to have_css('.col-id', text: /#{archived_invoice.id}/)
end

context 'when selecting a value', js: true do
before do
pick_select2_entered_option('Archivado')
click_filter_btn
end

it 'displays only elements with that value' do
expect(page).to have_css('.col-id', text: /#{archived_invoice.id}/)
expect(page).not_to have_css('.col-id', text: /#{active_invoice.id}/)
end
end
end
end
end
83 changes: 67 additions & 16 deletions spec/features/tag_builder_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,22 +102,7 @@
end

context "using Rails Enum" do
context "changing state value" do
before do
register_index(Invoice) do
tag_column :status
end

create_invoice(status: :archived)
visit admin_invoices_path
end

it "shows set value" do
expect(page).to have_css('.archived')
end
end

context 'with interactive option' do
shared_examples 'interactive select rendering' do
let!(:invoice) { create_invoice(status: :active) }

before do
Expand Down Expand Up @@ -161,5 +146,71 @@
expect(page).to have_css('.interactive-tag-select[data-value="active"]')
end
end

context 'with no translations' do
around do |example|
I18n.with_locale('de') do
example.run
end
end

context "without interactive option" do
before do
register_index(Invoice) do
tag_column :status
end

create_invoice(status: :archived)
visit admin_invoices_path
end

it "shows untranslated text as value" do
expect(page.find('td.col-status').text).to eq('Archived')
end
end

context 'with interactive option' do
include_examples 'interactive select rendering'

it 'renders an option for each enum value, with translated text' do
option_selector = '.interactive-tag-select option'
expect(page.find("#{option_selector}[value='active']").text).to eq('active')
expect(page.find("#{option_selector}[value='archived']").text).to eq('archived')
end
end
end

context 'with translations' do
around do |example|
I18n.with_locale('en') do
example.run
end
end

context "without interactive option" do
before do
register_index(Invoice) do
tag_column :status
end

create_invoice(status: :archived)
visit admin_invoices_path
end

it "shows translated text as value" do
expect(page.find('td.col-status').text).to eq('Archivado')
end
end

context 'with interactive option' do
include_examples 'interactive select rendering'

it 'renders an option for each enum value, with translated text' do
option_selector = '.interactive-tag-select option'
expect(page.find("#{option_selector}[value='active']").text).to eq('Activo')
expect(page.find("#{option_selector}[value='archived']").text).to eq('Archivado')
end
end
end
end
end
Loading

0 comments on commit beb1cd8

Please sign in to comment.