diff --git a/.gitignore b/.gitignore index 93c476de7..3c81b6a1f 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,7 @@ vendor/ruby .idea spec/examples.txt + +# Ignore i18n-js +client/app/libs/i18n/translations.js +client/app/libs/i18n/default.js diff --git a/.travis.yml b/.travis.yml index 4e92b4763..dcbeb15ea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,7 +29,8 @@ install: - npm install npm@latest -g - npm --version - npm install - - npm run build:client && npm run build:server + - rake react_on_rails:locale + - cd client && npm run build:test - rake db:setup # Tip: No need to run xvfb if running headless testing. However, we're going to start with diff --git a/Gemfile b/Gemfile index 338c45e1d..8a6a9d8ea 100644 --- a/Gemfile +++ b/Gemfile @@ -38,7 +38,7 @@ gem "sdoc", group: :doc # Use Rails Html Sanitizer for HTML sanitization gem "rails-html-sanitizer" -gem "react_on_rails", "~> 6.1" +gem "react_on_rails", "~> 6.7.1" # See https://github.com/sstephenson/execjs#readme for more supported runtimes # mini_racer is probably faster than therubyracer diff --git a/Gemfile.lock b/Gemfile.lock index 233be69f4..251d1bb5a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,39 +1,39 @@ GEM remote: https://rubygems.org/ specs: - actioncable (5.0.0.1) - actionpack (= 5.0.0.1) + actioncable (5.0.1) + actionpack (= 5.0.1) nio4r (~> 1.2) websocket-driver (~> 0.6.1) - actionmailer (5.0.0.1) - actionpack (= 5.0.0.1) - actionview (= 5.0.0.1) - activejob (= 5.0.0.1) + actionmailer (5.0.1) + actionpack (= 5.0.1) + actionview (= 5.0.1) + activejob (= 5.0.1) mail (~> 2.5, >= 2.5.4) rails-dom-testing (~> 2.0) - actionpack (5.0.0.1) - actionview (= 5.0.0.1) - activesupport (= 5.0.0.1) + actionpack (5.0.1) + actionview (= 5.0.1) + activesupport (= 5.0.1) rack (~> 2.0) rack-test (~> 0.6.3) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - actionview (5.0.0.1) - activesupport (= 5.0.0.1) + actionview (5.0.1) + activesupport (= 5.0.1) builder (~> 3.1) erubis (~> 2.7.0) rails-dom-testing (~> 2.0) rails-html-sanitizer (~> 1.0, >= 1.0.2) - activejob (5.0.0.1) - activesupport (= 5.0.0.1) + activejob (5.0.1) + activesupport (= 5.0.1) globalid (>= 0.3.6) - activemodel (5.0.0.1) - activesupport (= 5.0.0.1) - activerecord (5.0.0.1) - activemodel (= 5.0.0.1) - activesupport (= 5.0.0.1) + activemodel (5.0.1) + activesupport (= 5.0.1) + activerecord (5.0.1) + activemodel (= 5.0.1) + activesupport (= 5.0.1) arel (~> 7.0) - activesupport (5.0.0.1) + activesupport (5.0.1) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (~> 0.7) minitest (~> 5.1) @@ -50,7 +50,7 @@ GEM binding_of_caller (0.7.2) debug_inspector (>= 0.0.1) brakeman (3.4.1) - builder (3.2.2) + builder (3.2.3) bundler-audit (0.5.0) bundler (~> 1.2) thor (~> 0.18) @@ -82,7 +82,7 @@ GEM coffee-script-source execjs coffee-script-source (1.10.0) - concurrent-ruby (1.0.2) + concurrent-ruby (1.0.5) connection_pool (2.2.1) coveralls (0.8.15) json (>= 1.8, < 3) @@ -109,7 +109,7 @@ GEM railties (>= 3.0.0) globalid (0.3.7) activesupport (>= 4.1.0) - i18n (0.7.0) + i18n (0.8.1) interception (0.5) io-like (0.3.0) jbuilder (2.6.0) @@ -134,10 +134,10 @@ GEM mini_portile2 (2.1.0) mini_racer (0.1.7) libv8 (~> 5.3) - minitest (5.9.1) + minitest (5.10.1) multi_json (1.12.1) nio4r (1.2.1) - nokogiri (1.6.8.1) + nokogiri (1.7.0.1) mini_portile2 (~> 2.1.0) parser (2.3.2.0) ast (~> 2.2) @@ -165,45 +165,44 @@ GEM pry-stack_explorer (0.4.9.2) binding_of_caller (>= 0.7) pry (>= 0.9.11) - public_suffix (2.0.4) + public_suffix (2.0.5) puma (3.6.2) rack (2.0.1) rack-test (0.6.3) rack (>= 1.0) - rails (5.0.0.1) - actioncable (= 5.0.0.1) - actionmailer (= 5.0.0.1) - actionpack (= 5.0.0.1) - actionview (= 5.0.0.1) - activejob (= 5.0.0.1) - activemodel (= 5.0.0.1) - activerecord (= 5.0.0.1) - activesupport (= 5.0.0.1) + rails (5.0.1) + actioncable (= 5.0.1) + actionmailer (= 5.0.1) + actionpack (= 5.0.1) + actionview (= 5.0.1) + activejob (= 5.0.1) + activemodel (= 5.0.1) + activerecord (= 5.0.1) + activesupport (= 5.0.1) bundler (>= 1.3.0, < 2.0) - railties (= 5.0.0.1) + railties (= 5.0.1) sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.1) + rails-dom-testing (2.0.2) activesupport (>= 4.2.0, < 6.0) - nokogiri (~> 1.6.0) + nokogiri (~> 1.6) rails-html-sanitizer (1.0.3) loofah (~> 2.0) - railties (5.0.0.1) - actionpack (= 5.0.0.1) - activesupport (= 5.0.0.1) + railties (5.0.1) + actionpack (= 5.0.1) + activesupport (= 5.0.1) method_source rake (>= 0.8.7) thor (>= 0.18.1, < 2.0) - rainbow (2.1.0) + rainbow (2.2.1) rake (11.3.0) rb-fsevent (0.9.8) rb-inotify (0.9.7) ffi (>= 0.5.0) rdoc (4.3.0) - react_on_rails (6.1.2) + react_on_rails (6.7.1) addressable connection_pool execjs (~> 2.5) - foreman rails (>= 3.2) rainbow (~> 2.1) redis (3.3.0) @@ -265,7 +264,7 @@ GEM activesupport (>= 4.2) spring-commands-rspec (1.0.4) spring (>= 0.9.1) - sprockets (3.7.0) + sprockets (3.7.1) concurrent-ruby (~> 1.0) rack (> 1, < 3) sprockets-rails (3.2.0) @@ -274,8 +273,8 @@ GEM sprockets (>= 3.0.0) term-ansicolor (1.4.0) tins (~> 1.0) - thor (0.19.1) - thread_safe (0.3.5) + thor (0.19.4) + thread_safe (0.3.6) tilt (2.0.5) tins (1.12.0) tzinfo (1.2.2) @@ -289,7 +288,7 @@ GEM debug_inspector railties (>= 5.0) websocket (1.2.3) - websocket-driver (0.6.4) + websocket-driver (0.6.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.2) xpath (2.0.0) @@ -330,7 +329,7 @@ DEPENDENCIES rails rails-html-sanitizer rainbow - react_on_rails (~> 6.1) + react_on_rails (~> 6.7.1) redis rspec-rails (~> 3) rspec-retry diff --git a/Procfile.dev b/Procfile.dev index 0404e3c1b..669571946 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -7,7 +7,7 @@ rails: REACT_ON_RAILS_ENV=HOT rails s -b 0.0.0.0 # Run the hot reload server for client development -hot-assets: sh -c 'rm app/assets/webpack/* || true && HOT_RAILS_PORT=3500 npm run hot-assets' +hot-assets: sh -c 'rm app/assets/webpack/* || true && bundle exec rake react_on_rails:locale && HOT_RAILS_PORT=3500 npm run hot-assets' # Render static client assets rails-static-client-assets: sh -c 'npm run build:dev:client' diff --git a/Procfile.hot b/Procfile.hot index fe4dd92e1..2e6c49324 100644 --- a/Procfile.hot +++ b/Procfile.hot @@ -6,7 +6,7 @@ rails: REACT_ON_RAILS_ENV=HOT rails s -b 0.0.0.0 # Run the hot reload server for client development -hot-assets: sh -c 'rm app/assets/webpack/* || true && HOT_RAILS_PORT=3500 npm run hot-assets' +hot-assets: sh -c 'rm app/assets/webpack/* || true && bundle exec rake react_on_rails:locale && HOT_RAILS_PORT=3500 npm run hot-assets' # Keep the JS fresh for server rendering. Remove if not server rendering rails-server-assets: sh -c 'npm run build:dev:server' diff --git a/Procfile.spec b/Procfile.spec index d26f93be4..7fad064e6 100644 --- a/Procfile.spec +++ b/Procfile.spec @@ -3,7 +3,7 @@ # in rails_helper.rb. # Build client assets, watching for changes. -rails-client-assets: sh -c 'npm run build:dev:client' +rails-client-assets: sh -c 'bundle exec rake react_on_rails:locale && npm run build:dev:client' # Build server assets, watching for changes. Remove if not server rendering. rails-server-assets: sh -c 'npm run build:dev:server' diff --git a/Procfile.static b/Procfile.static index f3508d4bc..ac635a72a 100644 --- a/Procfile.static +++ b/Procfile.static @@ -2,7 +2,7 @@ rails: REACT_ON_RAILS_ENV= rails s -b 0.0.0.0 # Build client assets, watching for changes. -rails-client-assets: rm app/assets/webpack/* || true && npm run build:dev:client +rails-client-assets: rm app/assets/webpack/* || true && bundle exec rake react_on_rails:locale && npm run build:dev:client # Build server assets, watching for changes. Remove if not server rendering. rails-server-assets: npm run build:dev:server diff --git a/Procfile.static.trace b/Procfile.static.trace index c4b58a753..d73acfe5f 100644 --- a/Procfile.static.trace +++ b/Procfile.static.trace @@ -2,7 +2,7 @@ rails: TRACE_REACT_ON_RAILS=TRUE rails s -b 0.0.0.0 # Build client assets, watching for changes. -rails-client-assets: npm run build:dev:client +rails-client-assets: bundle exec rake react_on_rails:locale && npm run build:dev:client # Build server assets, watching for changes. Remove if not server rendering. rails-server-assets: npm run build:dev:server diff --git a/README.md b/README.md index fbf1b24b2..6620ee2c3 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ You can see this tutorial live here: [http://reactrails.com/](http://reactrails. - Enabling the use of npm modules and [Babel](https://babeljs.io/) with a Rails application using [Webpack](https://webpack.github.io/). - Easily enable retrofitting such a JS framework into an existing Rails app. You don't need a brand new single page app! - Example setting up Ruby and JavaScript linting in a real project, with corresponding CI rake tasks. +- Enabling the i18n functionality with [react-intl](https://github.com/yahoo/react-intl). ### Technologies involved diff --git a/client/.eslintignore b/client/.eslintignore index 3c3629e64..369ecb079 100644 --- a/client/.eslintignore +++ b/client/.eslintignore @@ -1 +1,4 @@ node_modules + +app/libs/i18n/translations.js +app/libs/i18n/default.js diff --git a/client/app/bundles/comments/actions/commentsActionCreators.js b/client/app/bundles/comments/actions/commentsActionCreators.js index b02788a2d..418a8675b 100644 --- a/client/app/bundles/comments/actions/commentsActionCreators.js +++ b/client/app/bundles/comments/actions/commentsActionCreators.js @@ -71,3 +71,10 @@ export function submitComment(comment) { ); }; } + +export function setLocale(locale) { + return { + type: actionTypes.SET_LOCALE, + locale, + }; +} diff --git a/client/app/bundles/comments/components/CommentBox/CommentBox.jsx b/client/app/bundles/comments/components/CommentBox/CommentBox.jsx index 5d8b54b48..bf3cd4bbf 100644 --- a/client/app/bundles/comments/components/CommentBox/CommentBox.jsx +++ b/client/app/bundles/comments/components/CommentBox/CommentBox.jsx @@ -1,13 +1,15 @@ import BaseComponent from 'libs/components/BaseComponent'; import React, { PropTypes } from 'react'; - +import { FormattedMessage, injectIntl, intlShape } from 'react-intl'; import CommentForm from './CommentForm/CommentForm'; import CommentList, { CommentPropTypes } from './CommentList/CommentList'; import css from './CommentBox.scss'; import Immutable from 'immutable'; import ActionCable from 'actioncable'; +import { SelectLanguage } from 'libs/i18n/selectLanguage'; +import { defaultMessages, defaultLocale } from 'libs/i18n/default'; -export default class CommentBox extends BaseComponent { +class CommentBox extends BaseComponent { static propTypes = { pollInterval: PropTypes.number.isRequired, actions: PropTypes.shape({ @@ -19,6 +21,7 @@ export default class CommentBox extends BaseComponent { submitCommentError: React.PropTypes.string, $$comments: React.PropTypes.arrayOf(CommentPropTypes), }).isRequired, + intl: intlShape.isRequired, }; constructor() { @@ -26,13 +29,14 @@ export default class CommentBox extends BaseComponent { _.bindAll(this, [ 'refreshComments', ]); + this.cable = null; } subscribeChannel() { const { messageReceived } = this.props.actions; const protocol = window.location.protocol === "https:" ? "wss://" : "ws://" - const cable = ActionCable.createConsumer(protocol+window.location.hostname+":"+window.location.port+"/cable"); - cable.subscriptions.create({channel: "CommentsChannel"}, { + this.cable = ActionCable.createConsumer(protocol+window.location.hostname+":"+window.location.port+"/cable"); + this.cable.subscriptions.create({channel: "CommentsChannel"}, { connected: () => { console.log("connected") }, @@ -52,7 +56,7 @@ export default class CommentBox extends BaseComponent { } componentWillUnmount() { - App.cable.subscriptions.remove({ channel: "CommentsChannel" }); + this.cable.subscriptions.remove({ channel: "CommentsChannel" }); } refreshComments() { @@ -61,37 +65,35 @@ export default class CommentBox extends BaseComponent { } render() { - const { actions, data } = this.props; + const { actions, data, intl } = this.props; + const { formatMessage } = intl; const cssTransitionGroupClassNames = { enter: css.elementEnter, enterActive: css.elementEnterActive, leave: css.elementLeave, leaveActive: css.elementLeaveActive, }; + const locale = data.get('locale') || defaultLocale; return (