1

I develop on Ruby on Rails 5.2. With the purpose of managing translations, I wish to allow the user to select a language which is different from his current language. The list of configured languages of the application is

 all_languages = I18n.config.available_locales

all_languages is an Array. puts all_languages returns:

en fr de it

The user language is defined in the users table. A method returns current user's language

user_language = current_user.language

user_language is a String. puts user_language returns:

en

I try to apply the delete(obj) method to the array, but this does not alter the array:

all_languages.delete(user_language)

I try to work on arrays only, still it does not alter the languages array:

remove_language = Array.new
remove_language << user_language

puts remove_language returns:

en

puts all_languages - remove_language returns:

en fr de it

where the en language should be removed. I don't understand why it remains in the list!

7
  • 5
    Use p instead of puts, which will show the object in more detail. puts removes information such as whether you have a bare item or an array that includes it, as well as whether you have a string or a symbol. Commented Nov 30, 2018 at 7:11
  • I'm not understanding why your last attempt using array - array isn't working. Check my answer. Try it rails console. Commented Nov 30, 2018 at 7:51
  • 2
    @Jurgen string vs symbol Commented Nov 30, 2018 at 7:57
  • "user_language is a String" – consider turning that into a symbol. Commented Nov 30, 2018 at 11:13
  • 2
    @SergioTulentsev sure, but current_user.language is a method call. You could override language or maybe have the ORM convert it. The code becomes easier if you are dealing with the correct "type" right from the start. Commented Nov 30, 2018 at 11:26

4 Answers 4

7

I18n.config.available_locales returns symbols *. And your current_user.language is a string. "en" is not at all the same thing as :en. That said, this should work:

all_languages = I18n.config.available_locales.dup # copy the array
all_languages.delete(:en)
# or, for your case
all_languages.delete(current_user.language.to_sym)


# non-mutating way
all_langs_without_en = I18n.config.available_locales.reject { |loc| loc == :en }

* at least in rails 4.2, where I checked this.

Sign up to request clarification or add additional context in comments.

5 Comments

@Jurgen: thanks, but sawa called it 50 mins ago, and nobody listened :)
Alternatively you could change the available locales into strings instead of changing to user language into a symbol. all_languages = I18n.config.available_locales.map(&:to_s)
@Stefan: why did I think it was duping the array? :facepalm:
It probably depends on the backend being used, but unless the API guarantees it, dup is the safer choice. BTW, in Rails there's also Array#without.
@Stefan: ah, Array#without. I was wondering why something like that doesn't exist. Post that as an answer :)
1

Your code doesn't work, because available_locales returns an array of symbols and you are attempting to remove a string.

a = [:en, :fr, :de, :it]
a.delete('en')
#=> nil

a #=> [:en, :fr, :de, :it]

To fix this, you have to turn your string into a symbol. Furthermore, you should avoid delete because it modifies the receiver (modifying available_locales might result in bugs later on). You can use Rails' Array#without instead which returns a new array:

all_languages = I18n.config.available_locales
#=> [:en, :fr, :de, :it]

user_language = current_user.language.to_sym
#=> :en

all_languages.without(user_language)
#=> [:fr, :de, :it]

1 Comment

Thank you all! I finally took the solution of Johan Wentholt to convert to an array of strings and use it .without(user_language).
1

Try this

all_languages = ["en","fr","de","it"]
user_language = "en"
all_languages.delete_at(all_languages.index(user_language))

#=> ["fr","de","it"]

3 Comments

The delete should have worked. What makes it fail, will prevent this one from working too.
I believe delete is not working because of conflict with active record delete method. Is it possible?
No, that is not what's happening.
0

This solution should meet your need:

l = I18n.config.available_locales
l.pop
I18n.config.available_locales = l

2 Comments

op wants to remove the user's selected language, your method doesn't guarantee you're removing the right item in the array.
This is just an example, and if you want to remove the specific item, you could use delete method to get the desired array and then assign it to I18n.config.available_locales

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.