Skip to content

Instantly share code, notes, and snippets.

@jhilden
Last active October 3, 2021 10:32
Show Gist options
  • Save jhilden/44378421ad54e617b900 to your computer and use it in GitHub Desktop.
Save jhilden/44378421ad54e617b900 to your computer and use it in GitHub Desktop.
Setup for using i18n-js together with react-rails i18n-js for server side prerendering

When using react-rails for an internationalized app it makes a lot of sense to use i18n-js for translations, so that you can reuse the the strings from your rails app's .yml files (and all the tooling & services that exist around that).

When you use the prerender feature of react-rails you face 2 problems:

  • The first is that translation.js & i18n.js from i18n-js need to be loaded inside the server-side JS prerendering processes, which is achieved by loading them inside the components.js.
  • The second problem is the server processes need to be aware of the current locale of each HTTP request. This is done by adding a custom renderer and using the before_render hook to configure i18n-js accordingly for each render call.
require 'i18n_js_renderer'
module MyRailsApp
class Application < Rails::Application
config.react.server_renderer = React::ServerRendering::I18nJsRenderer
end
end
//= require i18n
//= require i18n/translations
//= require_tree ./components
module React
module ServerRendering
class I18nJsRenderer < SprocketsRenderer
def before_render(component_name, props, prerender_options)
super + "I18n.defaultLocale = '#{MyRailsApp::Application.config.i18n.default_locale}'; I18n.fallbacks = true; I18n.locale = '#{I18n.locale}';"
end
end
end
end
@balakirevs
Copy link

My gist: https://gist.github.com/giedriusr/650ec9d6dbe57faf53c5cd470e0ff1ee

The problem is that react component is not aware of the other locale when I try to change it. Even if I change default locale to something else rather than "en", it still defaults to EN. No idea how to work around this. Anyone?

@giedriusr, have you managed to resolve it?

@MichaelSeeberger
Copy link

When using Rails 6, this will not work due to webpacker (I18n is not global). Here's my solution that should work with both server and client side rendering.

In config/application.rb:

module MyApp
  class Application < Rails::Application
    #...
    # other config stuff

    config.react.server_renderer = Class.new(React::ServerRendering::BundleRenderer) do
      def before_render(component_name, props, prerender_options)
        custom_before = <<-EOF
          global.I18n.defaultLocale='#{MyApp::Application.config.i18n.default_locale}';
          global.I18n.locale='#{I18n.locale}';
          I18n.fallbacks = true;
        EOF
        super + custom_before
      end
    end
  end
end

(I don't like the anonymous class, but I couldn't work out in what file to put this class)

app/javascript/packs/server_rendering.js:

// other code

import I18n from 'i18n-js/index.js.erb'
global.I18n = I18n

app/javascript/packs/application.js:

// other code

import I18n from 'i18n-js/index.js.erb'
I18n.locale = LOCALE

app/javascript/i18n-js/index.js.erb:

import I18n from "i18n-js"
I18n.translations = <%= I18n::JS.filtered_translations.to_json %>

export default I18n

In application.html.erb I added

<script type="text/javascript">
  const LOCALE = "<%= I18n.locale %>";
</script>

Somehow, this feels quite "hacky". If anyone has a better solution, please let me know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment