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!

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
user1185081
  • 1,898
  • 2
  • 21
  • 46
  • 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. – sawa Nov 30 '18 at 07:11
  • I'm not understanding why your last attempt using `array - array` isn't working. Check my answer. Try it `rails console`. – Dom Nov 30 '18 at 07:51
  • 2
    @Jurgen string vs symbol – Sergio Tulentsev Nov 30 '18 at 07:57
  • _"user_language is a String"_ – consider turning that into a symbol. – Stefan Nov 30 '18 at 11:13
  • @Stefan: presumably, it comes from a database. – Sergio Tulentsev Nov 30 '18 at 11:16
  • 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. – Stefan Nov 30 '18 at 11:26
  • I can suggest to use `p` instead of `puts` for debugging or append `.inspect`: https://stackoverflow.com/questions/1255324/p-vs-puts-in-ruby – iGian Nov 30 '18 at 11:27

4 Answers4

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.

Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367
  • 3
    @Jurgen: thanks, but sawa called it 50 mins ago, and nobody listened :) – Sergio Tulentsev Nov 30 '18 at 08:01
  • 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)` – 3limin4t0r Nov 30 '18 at 10:56
  • @Stefan: why did I think it was duping the array? :facepalm: – Sergio Tulentsev Nov 30 '18 at 11:05
  • 1
    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`](https://api.rubyonrails.org/classes/Array.html#method-i-without). – Stefan Nov 30 '18 at 11:12
  • @Stefan: ah, Array#without. I was wondering why something like that doesn't exist. Post that as an answer :) – Sergio Tulentsev Nov 30 '18 at 11:13
1

Try this

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

#=> ["fr","de","it"]
Talha Junaid
  • 904
  • 1
  • 7
  • 15
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]
Stefan
  • 109,145
  • 14
  • 143
  • 218
  • Thank you all! I finally took the solution of Johan Wentholt to convert to an array of strings and use it .without(user_language). – user1185081 Nov 30 '18 at 21:25
0

This solution should meet your need:

l = I18n.config.available_locales
l.pop
I18n.config.available_locales = l
killernova
  • 150
  • 1
  • 11
  • 1
    op wants to remove the user's selected language, your method doesn't guarantee you're removing the right item in the array. – Dom Nov 30 '18 at 07:40
  • 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` – killernova Nov 30 '18 at 07:45