Skip to content

Commit

Permalink
i18n_yml_dir (#777)
Browse files Browse the repository at this point in the history
* Add option to specify i18n_yml_dir

LocalesToJs uses all locales on rails i18n load path when generating js files,
so all the locales from config/locales and in gems are included,
using config.i18n_yml_dir option enables only locales from specified
dir to be inluded in translations.js and default.js
  • Loading branch information
danijel authored and justin808 committed Mar 30, 2017
1 parent d04fc4c commit 8cb06ed
Show file tree
Hide file tree
Showing 8 changed files with 130 additions and 42 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Contributors: please follow the recommendations outlined at [keepachangelog.com]
## Improved
- Use <script type="application/json"> for props and store instead of hidden div [#775] (https://github.com/shakacode/react_on_rails/pull/775) by [cheremukhin23](https://github.com/cheremukhin23).

### Added
- Add option to specify i18n_yml_dir in order to include only subset of locale files when generating translations.js & default.js for react-intl
[#777](https://github.com/shakacode/react_on_rails/pull/777) by [danijel](https://github.com/danijel).

## [6.8.2] - 2017-03-24
## Fixed
- Change webpack output path to absolute and update webpack to version ^2.3.1. [#771](https://github.com/shakacode/react_on_rails/pull/771) by [cheremukhin23](https://github.com/cheremukhin23).
Expand Down
17 changes: 12 additions & 5 deletions docs/basics/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,28 @@ You can refer to [react-webpack-rails-tutorial](https://github.com/shakacode/rea
```

2. Add `config.i18n_dir` in `config/initializers/react_on_rails.rb`

`react-intl` requires locale files in json format. React on Rails will generate `translations.js` & `default.js` automatically after you configured your `config.i18n_dir` in `config/initializers/react_on_rails.rb`.

```ruby
# Replace the following line to the location where you keep translation.js & default.js.
config.i18n_dir = Rails.root.join("PATH_TO", "YOUR_JS_I18N_FOLDER")
```


Optionally you can also set `config.i18n_yml_dir` if you do not what to use all the locale files from rails.
```ruby
# Replace the following line to the location where you keep your client i18n yml files
# By default(without this option), all yaml files from Rails.root.join("config", "locales") and installed gems are loaded
config.i18n_yml_dir = Rails.root.join("PATH_TO", "YOUR_YAML_I18N_FOLDER")
```

`translations.js`: All your locales in json format.
`default.js`: Default settings in json format.

3. Add `translations.js` and `default.js` to your `.gitignore` and `.eslintignore`.
4. Javascript locale files must be generated before `yarn build`.

4. Javascript locale files must be generated before `yarn build`.

Once you setup `config.i18n_dir` as in the previous step, react_on_rails will automatically do this for testing (if using the `ReactOnRails::TestHelper.configure_rspec_to_compile_assets` and for production deployments if using the [default precompile rake hook](../additional-reading/heroku-deployment.md). For development, you should adjust your startup scripts (Procfiles) so that they run `bundle exec rake react_on_rails:locale` before running any webpack watch process (`yarn run build:development`).

5. In React, you need to initialize `react-intl`, and set parameters for it.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ ReactOnRails.configure do |config|
# Replace the following line to the location where you keep translation.js & default.js for use
# by the npm packages react-intl. Be sure this directory exists!
# config.i18n_dir = Rails.root.join("client", "app", "libs", "i18n")
#
# Replace the following line to the location where you keep your client i18n yml files
# that will source for automatic generation on translations.js & default.js
# By default(without this option) all yaml files from Rails.root.join("config", "locales") and installed gems are loaded
# config.i18n_yml_dir = Rails.root.join("config", "locales", "client")

################################################################################
# MISCELLANEOUS OPTIONS
Expand Down
16 changes: 14 additions & 2 deletions lib/react_on_rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def self.setup_config_values
ensure_generated_assets_dir_present
ensure_server_bundle_js_file_has_no_path
check_i18n_directory_exists
check_i18n_yml_directory_exists
end

def self.check_i18n_directory_exists
Expand All @@ -24,6 +25,15 @@ def self.check_i18n_directory_exists
"out if not using this i18n with React on Rails."
end

def self.check_i18n_yml_directory_exists
return unless @configuration.i18n_yml_dir.present?
return if Dir.exist?(@configuration.i18n_yml_dir)

raise "Error configuring /config/react_on_rails.rb: invalid value for `config.i18n_yml_dir`. "\
"Directory does not exist: #{@configuration.i18n_yml_dir}. Set to value to nil or comment it "\
"out if not using this i18n with React on Rails, or if you want to use all translation files."
end

def self.ensure_generated_assets_dir_present
return unless @configuration.generated_assets_dir.blank?

Expand Down Expand Up @@ -91,6 +101,7 @@ def self.configuration
symlink_non_digested_assets_regex: /\.(png|jpg|jpeg|gif|tiff|woff|ttf|eot|svg|map)/,
npm_build_test_command: "",
i18n_dir: "",
i18n_yml_dir: "",
npm_build_production_command: ""
)
end
Expand All @@ -103,7 +114,7 @@ class Configuration
:generated_assets_dirs, :generated_assets_dir,
:webpack_generated_files, :rendering_extension, :npm_build_test_command,
:npm_build_production_command,
:i18n_dir,
:i18n_dir, :i18n_yml_dir,
:server_render_method, :symlink_non_digested_assets_regex

def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
Expand All @@ -114,14 +125,15 @@ def initialize(server_bundle_js_file: nil, prerender: nil, replay_console: nil,
generated_assets_dir: nil, webpack_generated_files: nil,
rendering_extension: nil, npm_build_test_command: nil,
npm_build_production_command: nil,
i18n_dir: nil,
i18n_dir: nil, i18n_yml_dir: nil,
server_render_method: nil, symlink_non_digested_assets_regex: nil)
self.server_bundle_js_file = server_bundle_js_file
self.generated_assets_dirs = generated_assets_dirs
self.generated_assets_dir = generated_assets_dir
self.npm_build_test_command = npm_build_test_command
self.npm_build_production_command = npm_build_production_command
self.i18n_dir = i18n_dir
self.i18n_yml_dir = i18n_yml_dir

self.prerender = prerender
self.replay_console = replay_console
Expand Down
13 changes: 11 additions & 2 deletions lib/react_on_rails/locales_to_js.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,23 @@ def js_file(name)
end

def locale_files
@locale_files ||=
(Rails.application && Rails.application.config.i18n.load_path).presence
@locale_files ||= begin
if i18n_yml_dir.present?
Dir["#{i18n_yml_dir}/**/*.yml"]
else
(Rails.application && Rails.application.config.i18n.load_path).presence
end
end
end

def i18n_dir
@i18n_dir ||= ReactOnRails.configuration.i18n_dir
end

def i18n_yml_dir
@i18n_yml_dir ||= ReactOnRails.configuration.i18n_yml_dir
end

def default_locale
@default_locale ||= I18n.default_locale.to_s || "en"
end
Expand Down
4 changes: 4 additions & 0 deletions spec/dummy/config/initializers/react_on_rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ def self.custom_context(view_context)
# Replace the following line to the location where you keep translation.js & default.js for use
# by the npm packages react-intl. Be sure this directory exists!
# config.i18n_dir = Rails.root.join("client", "app", "libs", "i18n")
#
# Replace the following line to the location where you keep your client i18n yml files
# that will source for automatic generation on translations.js & default.js
# config.i18n_yml_dir = Rails.root.join("config", "locales", "client")

################################################################################
# MISCELLANEOUS OPTIONS
Expand Down
19 changes: 19 additions & 0 deletions spec/react_on_rails/configuration_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,25 @@ module ReactOnRails
expect(ReactOnRails.configuration.i18n_dir).to eq(dir)
end

it "raises if the i18n yaml directory does not exist" do
junk_name = "/YYYY/junkYYYY"
expect do
ReactOnRails.configure do |config|
config.i18n_yml_dir = junk_name
end
end.to raise_error(/#{junk_name}/)
end

it "does not raises if the i18n yaml directory does exist" do
dir = File.expand_path(File.dirname(__FILE__))
expect do
ReactOnRails.configure do |config|
config.i18n_yml_dir = dir
end
end.to_not raise_error
expect(ReactOnRails.configuration.i18n_yml_dir).to eq(dir)
end

it "be able to config default configuration of the gem" do
ReactOnRails.configure do |config|
config.server_bundle_js_file = "server.js"
Expand Down
94 changes: 61 additions & 33 deletions spec/react_on_rails/locales_to_js_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,57 +4,85 @@
module ReactOnRails
RSpec.describe LocalesToJs do
let(:i18n_dir) { Pathname.new(Dir.mktmpdir) }
let(:locale_dir) { File.expand_path("../fixtures/i18n/locales", __FILE__) }
let(:translations_path) { "#{i18n_dir}/translations.js" }
let(:default_path) { "#{i18n_dir}/default.js" }
let(:en_path) { "#{locale_dir}/en.yml" }

before do
allow_any_instance_of(ReactOnRails::LocalesToJs).to receive(:locale_files).and_return(Dir["#{locale_dir}/*"])
ReactOnRails.configure do |config|
config.i18n_dir = i18n_dir
shared_examples "locale to js" do
context "with obsolete js files" do
before do
FileUtils.touch(translations_path, mtime: Time.now - 1.year)
FileUtils.touch(en_path, mtime: Time.now - 1.month)
end

it "updates files" do
ReactOnRails::LocalesToJs.new

translations = File.read(translations_path)
default = File.read(default_path)
expect(translations).to include('{"hello":"Hello world"')
expect(translations).to include('{"hello":"Hallo welt"')
expect(default).to include("const defaultLocale = 'en';")
expect(default).to include('{"hello":{"id":"hello","defaultMessage":"Hello world"}}')

expect(File.mtime(translations_path)).to be >= File.mtime(en_path)
end
end
end

after do
ReactOnRails.configure do |config|
config.i18n_dir = nil
context "with up-to-date js files" do
before do
ReactOnRails::LocalesToJs.new
end

it "doesn't update files" do
ref_time = Time.now - 1.minute
FileUtils.touch(translations_path, mtime: ref_time)

update_time = Time.now
ReactOnRails::LocalesToJs.new
expect(update_time).to be > File.mtime(translations_path)
end
end
end

context "with obsolete js files" do
describe "without i18n_yml_dir" do
let(:locale_dir) { File.expand_path("../fixtures/i18n/locales", __FILE__) }
let(:en_path) { "#{locale_dir}/en.yml" }

before do
FileUtils.touch(translations_path, mtime: Time.now - 1.year)
FileUtils.touch(en_path, mtime: Time.now - 1.month)
allow_any_instance_of(ReactOnRails::LocalesToJs).to receive(:locale_files).and_return(Dir["#{locale_dir}/*"])
ReactOnRails.configure do |config|
config.i18n_dir = i18n_dir
end
end

it "updates files" do
ReactOnRails::LocalesToJs.new

translations = File.read(translations_path)
default = File.read(default_path)
expect(translations).to include('{"hello":"Hello world"')
expect(translations).to include('{"hello":"Hallo welt"')
expect(default).to include("const defaultLocale = 'en';")
expect(default).to include('{"hello":{"id":"hello","defaultMessage":"Hello world"}}')

expect(File.mtime(translations_path)).to be >= File.mtime(en_path)
after do
ReactOnRails.configure do |config|
config.i18n_dir = nil
end
end

it_behaves_like "locale to js"
end

context "with up-to-date js files" do
describe "with i18n_yml_dir" do
let(:locale_dir) { File.expand_path("../fixtures/i18n/locales", __FILE__) }
let(:en_path) { "#{locale_dir}/en.yml" }

before do
ReactOnRails::LocalesToJs.new
ReactOnRails.configure do |config|
config.i18n_dir = i18n_dir
config.i18n_yml_dir = locale_dir
end
end

it "doesn't update files" do
ref_time = Time.now - 1.minute
FileUtils.touch(translations_path, mtime: ref_time)

update_time = Time.now
ReactOnRails::LocalesToJs.new
expect(update_time).to be > File.mtime(translations_path)
after do
ReactOnRails.configure do |config|
config.i18n_dir = nil
config.i18n_yml_dir = nil
end
end

it_behaves_like "locale to js"
end
end
end

0 comments on commit 8cb06ed

Please sign in to comment.