3

Below code is what I have in one of coffeescript files in rails application. I'm struggling to add i18n support for string values like "Select Account First" and "Select One". In regular javascript files I have been using something like I18n.t("shared.select_account_first") to get the internationalized value for a string using i18n-js gem.

jQuery ->
  networks = $('#account_offering_network_id').html()
  select_network_options = new Option("Select Account First", "", true, false)

  filter_networks_by_account = (account) ->
    if account is 'Select One'
      $('#account_offering_network_id').html(select_network_options)
    else
      escaped_account = account.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1')
      options = $(networks).filter("optgroup[label='#{escaped_account}']")
      $('#account_offering_network_id').html(options.html())

  # Show proper network dropdown first time
  filter_networks_by_account($('#account_offering_account_id :selected').text())

  # Show proper network dropdown on account change
  $('#account_offering_account_id').change -> filter_networks_by_account($('#account_offering_account_id :selected').text())

The goal of all this is to filter networks dropdown based on account selected. If no account is selected (the value of account dropdown shows 'Select One' or corresponding i18n value), network dropdown should say 'Select Account First' in selected locale.

I'm using i18s-js gem(https://github.com/fnando/i18n-js) to enable translations in javascript. Here are the changes I had to make in application to support the gem.

In application.js:

//= require i18n
//= require i18n/translations

Properties added in production.rb and development.rb:

# Enable locale fallbacks for I18n (makes lookups for any locale fall back to
# the I18n.default_locale when a translation can not be found)
config.i18n.fallbacks = true
config.i18n.available_locales = [:en, :ru]

In application.html.erb:

<%# For localization/i18n in javascript %>
<script type="text/javascript">
  I18n.defaultLocale = "<%= I18n.default_locale %>";
  I18n.locale = "<%= I18n.locale %>";
  I18n.fallbacks = true;
</script>

Finally I had run "rake i18n:js:export", which will create a translations file (app/javascripts/i18n/translations.js) loaded with name-value pairs. Now, from any javascript I can access the translations using I18n.t(name).

Srini K
  • 3,315
  • 10
  • 37
  • 47
  • If `I18n.t("shared.select_account_first")` works in your JavaScript then why wouldn't it work in your CoffeeScript? – mu is too short Aug 24 '12 at 19:18
  • not sure, may be I should include something in coffee script to get access to outside functions. – Srini K Aug 24 '12 at 20:39
  • Where do you define `I18n` and how do you use it in your JavaScript? – mu is too short Aug 24 '12 at 21:08
  • Updated the question with more info. Let me now if that helps. Thanks. – Srini K Aug 25 '12 at 15:02
  • So what's wrong with using `I18n.t()` just like you would in JavaScript? I'd recommend using language-independent values for your ` – mu is too short Aug 25 '12 at 18:49
  • It doesn't work. Not sure why, hence the question. So what I'm trying is to replace 'Select Account First' and 'Select One' with something like I18n.t('xxx.select_account_first') and I18n.t('xxx.select_one'). Seems silly, but isn't working. – Srini K Aug 25 '12 at 20:50
  • Did you run `$ rake i18n:js:setup` to copy `i18n-js.yml` to the **config** folder? Not sure if it will be of assistance, but I outlined how I got `I18n.t()` working in [this StackOverflow answer](http://stackoverflow.com/a/11332683/567863) – Paul Fioravanti Aug 26 '12 at 02:28
  • mu, I feel so stupid now. Not sure what changed and when it stated working, but it does work now. I'm wondering if I tried testing after I ran 'rake i18n:js:export'. I think I did, but not sure any more. I tried it now, just to give you the errors and realized that it is working. Sorry for wasting your time. – Srini K Aug 26 '12 at 03:46
  • Paul, I did run that. I18n has been working in javascript for a long time, but had some issues using it in CoffeeScript. They are resolved now. See the comment above. Thanks for trying to help. – Srini K Aug 26 '12 at 03:48

3 Answers3

0

I was trying to do the same thing, but I don't think you can, as apparently the people who made coffeescript made a design decision forbidding the injection of ruby variables into coffeescript files, to avoid having to recompile the coffeescript on each request - a bit of a bummer if you ask me! One horrible way to do this would be to pass the translation you need inline, but that sounds horrible!

have a look at this: How to access instance variables in CoffeeScript engine inside a Slim template

hope this helps!

Community
  • 1
  • 1
mulus
  • 475
  • 1
  • 4
  • 7
0

Just want to chime in here as this is something I have to do on a regular basis on a few projects. It's not pretty, but it's the best solution I've been able to come up with so far.

Using your example code above:

networks = $('#account_offering_network_id').html()
select_network_options = new Option("Select Account First", "", true, false)

I am going to assume your HTML code looks something like this:

<select id="account_offering_network_id">
    ...you generate a list of stuff here...
</select>

But your real issue is that you want the text "Select Account First" translated. So here's what I do:

<select id="account_offering_network_id" data-default-option-text="Select Account First">
  ...you generate a list of stuff here...
</select>

Then in your coffee script, you already have this:

networks = $('#account_offering_network_id').html()

To access the translated value (which you defined in your HTML / ERB file and not your coffee script file), you can access it as:

networks = $('#account_offering_network_id').html()
default_text = $('#account_offering_network_id').attr('data-default-option-text');

Of course, in your ERB file you won't pass the hard-coded English translation, because you want the current locale translation, so your actual select box definition will look something like this:

<select id="account_offering_network_id" data-default-option-text="<%=I18n.t("views.default_select_text")%>">
  ...you generate a list of stuff here...
</select>

This will get you the translated version of anything you want accessible in your coffeescript code accessible via the data-attributes of whatever elements you're working with.

Like I said - it's not awesome, but it works extremely well and I use it on a regular basis.

humandoing
  • 109
  • 1
  • 7
0

@mulus 's suggestion makes sense because you want to minify your js and cache it; doing a .js.erb is not the optimal way.

Anyway, here's a quick and easy way to do it:

I'm using Ruby on Rails so in my application layout (app/views/layouts/application.html.erb) I have the following:

<head>
  ...
  <meta name='locale' content="<%= params[:locale] %>"><meta>
  ...
</head>

This will allow me to pass the locale from Ruby on Rails to Javascript at 'runtime'.

I then created a Translator.coffee file

class Translator
  @en = {
    internet_connection_lost: "You internet connection has been lost"
    bid_received: "Bid received. New balance $$bid_balance$$"
  }

  @ar = {
    internet_connection_lost: "ra7et el connection"
    bid_received: "Bid received. New balance $$bid_balance$$"
  }

  # you can place the variables above in here too
  # or you can have them in different files. Organize stuff as needed
  @get_translations: (locale) ->
    switch (locale)
      when 'en'
        @en
      when 'ar'
        @ar

  @translate: (val, interpolation) ->
    # get locale from meta
    locale = $("meta[name='locale']").attr("content") || "en"

    # get the translation for the val
    translation = Translator.get_translations(locale)[val]

    # substitute values
    for k,v of interpolation
      translation = translation.replace(k, v)

    return translation

window.Translator = Translator

Call your Translator like this:

message = Translator.translate("bid_received", { "$$bid_balance$$": "$10.00" })
console.log(message)
Abdo
  • 13,549
  • 10
  • 79
  • 98