Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add json locale format #1271

Merged
merged 13 commits into from
May 18, 2020
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ for details.
* Removal of support for old Rubies and Rails.
* Removal of config.symlink_non_digested_assets_regex as it's no longer needed with rails/webpacker.
If any business needs this, we can move the code to a separate gem.
* Added support to export locales in JSON format.

### [11.3.0] - 2019-05-24
#### Added
Expand Down
5 changes: 3 additions & 2 deletions docs/basics/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,9 @@ ReactOnRails.configure do |config|
# and installed gems are loaded
config.i18n_yml_dir = Rails.root.join("config", "locales", "client")

# Possible output formats are js and json
config.i18n_output_format = 'js'

################################################################################
################################################################################
# CLIENT RENDERING OPTIONS
Expand Down Expand Up @@ -208,5 +211,3 @@ module RenderingExtension
end
end
```


7 changes: 7 additions & 0 deletions docs/basics/i18n.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ You can refer to [react-webpack-rails-tutorial](https://github.com/shakacode/rea
{ formatMessage(defaultMessages.yourLocaleKeyInCamelCase) }
)
```

# Generate JSON locale files

In case if you need pure json files, you can specify the format as follows in `react_on_rails.rb`:
```rb
config.i18n_output_format = 'json'
```

# Notes

Expand Down
4 changes: 3 additions & 1 deletion lib/react_on_rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@
require "react_on_rails/test_helper/webpack_assets_compiler"
require "react_on_rails/test_helper/webpack_assets_status_checker"
require "react_on_rails/test_helper/ensure_assets_compiled"
require "react_on_rails/locales_to_js"
require "react_on_rails/locales/base"
require "react_on_rails/locales/to_js"
require "react_on_rails/locales/to_json"
8 changes: 5 additions & 3 deletions lib/react_on_rails/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ def self.configuration
server_render_method: nil,
build_test_command: "",
build_production_command: "",
random_dom_id: DEFAULT_RANDOM_DOM_ID
random_dom_id: DEFAULT_RANDOM_DOM_ID,
i18n_output_format: nil
)
end

Expand All @@ -45,7 +46,7 @@ class Configuration
:generated_assets_dirs, :generated_assets_dir,
:webpack_generated_files, :rendering_extension, :build_test_command,
:build_production_command,
:i18n_dir, :i18n_yml_dir,
:i18n_dir, :i18n_yml_dir, :i18n_output_format,
:server_render_method, :random_dom_id

def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender: nil,
Expand All @@ -57,7 +58,7 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
generated_assets_dir: nil, webpack_generated_files: nil,
rendering_extension: nil, build_test_command: nil,
build_production_command: nil,
i18n_dir: nil, i18n_yml_dir: nil, random_dom_id: nil,
i18n_dir: nil, i18n_yml_dir: nil, i18n_output_format: nil, random_dom_id: nil,
server_render_method: nil)
self.node_modules_location = node_modules_location.present? ? node_modules_location : Rails.root
self.server_bundle_js_file = server_bundle_js_file
Expand All @@ -67,6 +68,7 @@ def initialize(node_modules_location: nil, server_bundle_js_file: nil, prerender
self.build_production_command = build_production_command
self.i18n_dir = i18n_dir
self.i18n_yml_dir = i18n_yml_dir
self.i18n_output_format = i18n_output_format

self.random_dom_id = random_dom_id
self.prerender = prerender
Expand Down
142 changes: 142 additions & 0 deletions lib/react_on_rails/locales/base.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# frozen_string_literal: true

require "erb"

module ReactOnRails
module Locales
class Base
def initialize
return if i18n_dir.nil?
return unless obsolete?

@translations, @defaults = generate_translations
convert
end

private

def file_format; end

def obsolete?
return true if exist_files.empty?

files_are_outdated
end

def exist_files
@exist_files ||= files.select(&File.method(:exist?))
end

def files_are_outdated
latest_yml = locale_files.map(&File.method(:mtime)).max
earliest = exist_files.map(&File.method(:mtime)).min
latest_yml > earliest
end

def file_names
%w[translations default]
end

def files
@files ||= file_names.map { |n| file(n) }
end

def file(name)
"#{i18n_dir}/#{name}.#{file_format}"
end

def locale_files
@locale_files ||= begin
if i18n_yml_dir.present?
Dir["#{i18n_yml_dir}/**/*.yml"]
else
ReactOnRails::Utils.truthy_presence(
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

def convert
file_names.each do |name|
template = send("template_#{name}")
path = file(name)
generate_file(template, path)
end
end

def generate_file(template, path)
result = ERB.new(template).result()
File.open(path, "w") do |f|
f.write(result)
end
end

def generate_translations
translations = {}
defaults = {}
locale_files.each do |f|
translation = YAML.safe_load(File.open(f))
key = translation.keys[0]
val = flatten(translation[key])
translations = translations.deep_merge(key => val)
defaults = defaults.deep_merge(flatten_defaults(val)) if key == default_locale
end
[translations.to_json, defaults.to_json]
end

def format(input)
input.to_s.tr(".", "_").camelize(:lower).to_sym
end

def flatten_defaults(val)
flatten(val).each_with_object({}) do |(k, v), h|
key = format(k)
h[key] = { id: k, defaultMessage: v }
end
end

def flatten(translations)
translations.each_with_object({}) do |(k, v), h|
if v.is_a? Hash
flatten(v).map { |hk, hv| h["#{k}.#{hk}".to_sym] = hv }
elsif v.is_a?(String)
h[k] = v.gsub("%{", "{")
elsif !v.is_a?(Array)
h[k] = v
end
end
end

def template_translations
<<-JS.strip_heredoc
export const translations = #{@translations};
JS
end

def template_default
<<-JS.strip_heredoc
import { defineMessages } from 'react-intl';

const defaultLocale = \'#{default_locale}\';

const defaultMessages = defineMessages(#{@defaults});

export { defaultMessages, defaultLocale };
JS
end
end
end
end
37 changes: 37 additions & 0 deletions lib/react_on_rails/locales/to_js.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require "erb"

module ReactOnRails
module Locales
class ToJs < Base
def initialize
super
end

private

def file_format
"js"
end

def template_translations
<<-JS.strip_heredoc
export const translations = #{@translations};
JS
end

def template_default
<<-JS.strip_heredoc
import { defineMessages } from 'react-intl';

const defaultLocale = \'#{default_locale}\';

const defaultMessages = defineMessages(#{@defaults});

export { defaultMessages, defaultLocale };
JS
end
end
end
end
27 changes: 27 additions & 0 deletions lib/react_on_rails/locales/to_json.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

require "erb"

module ReactOnRails
module Locales
class ToJson < Base
def initialize
super
end

private

def file_format
"json"
end

def template_translations
@translations
end

def template_default
@defaults
end
end
end
end
Loading