Commit e2ccbbce authored by MrMan's avatar MrMan

Merge branch 'topic-28-add-japanese-language-support' into 'master'

Topic 28 add japanese language support

Add support for languages (japanese being the first), using simple i18n templating/replacement.

See merge request !5
parents 1f45ed3a c412bfba
Pipeline #2549930 skipped
......@@ -21,6 +21,7 @@ System.config({
"babel-runtime": "npm:babel-runtime@5.8.25",
"core-js": "npm:core-js@1.2.6",
"fontawesome": "bower:fontawesome@4.4.0",
"lipis/flag-icon-css": "github:lipis/flag-icon-css@2.1.0",
"lodash": "npm:lodash@3.10.1",
"moment": "npm:moment@2.10.6",
"pure": "bower:pure@0.6.0",
......
......@@ -4,6 +4,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="jspm_packages/bower/pure@0.6.0/pure-min.css"/>
<link rel="stylesheet" href="jspm_packages/bower/fontawesome@4.4.0/css/font-awesome.min.css"/>
<link rel="stylesheet" href="public/vendor/flag-icon-css/css/flag-icon.min.css"/>
<link rel="stylesheet" href="public/styles/kindling.css"/>
<title>Kindling</title>
</head>
......
......@@ -2,6 +2,7 @@ import Reflux from "reflux";
export default Reflux.createActions([
"authenticateWithTinder",
"changeLocaleByCode",
"error",
"getCurrentRec",
"getNextTinderRecommendation",
......
import React from "react";
import { Link, PropTypes } from "react-router";
import FBAuthStore from "../stores/fb-auth";
import LocaleStore from "../stores/locale";
import ErrorStore from "../stores/error";
import TinderLocationStore from "../stores/tinder-location";
import TinderRecommendationsStore from "../stores/tinder-recommendation";
......@@ -8,16 +9,20 @@ import TinderSentimentsStore from "../stores/tinder-sentiment";
import Actions from "../actions";
import Constants from "../constants";
import _ from "lodash";
import { generateI18NTemplateFn } from "../i18n";
class AppPage extends React.Component {
constructor(props) {
super(props);
this.unsubFunctions = {};
this.i18n = generateI18NTemplateFn("en-US");
this.state = {i18n: LocaleStore.state.i18nTemplateFn};
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
console.log("[APP PAGE COMPONENT] Received locale update!", locale);
this.setSTate({i18n: locale.i18nTemplateFn});
});
this.unsubFunctions["store-auth"] = FBAuthStore.listen(auth => {
// Redirect to login if logout happens
if (!auth.loggedIn) {
......@@ -54,10 +59,10 @@ class AppPage extends React.Component {
return (
<div className={`app-page-container full-height ${appBgClass}`}>
<h1 className="no-vertical-margins slim-text picture-overlay-text">{this.i18n`app.name`}</h1>
<h4 className="no-vertical-margins slim-text picture-overlay-text">{this.i18n`app.subtitle`}</h4>
<h1 className="no-bottom-margin slim-text picture-overlay-text">{this.i18n`app.tagline.first`}</h1>
<h1 className="no-vertical-margins slim-text picture-overlay-text alizarin-face">{this.i18n`app.tagline.last`}</h1>
<h1 className="no-vertical-margins slim-text picture-overlay-text">{this.state.i18n`app.name`}</h1>
<h4 className="no-vertical-margins slim-text picture-overlay-text">{this.state.i18n`app.subtitle`}</h4>
<h1 className="no-bottom-margin slim-text picture-overlay-text">{this.state.i18n`app.tagline.first`}</h1>
<h1 className="no-vertical-margins slim-text picture-overlay-text alizarin-face">{this.state.i18n`app.tagline.last`}</h1>
<div className="pinned-to-bottom app-page-controls">
......@@ -65,7 +70,7 @@ class AppPage extends React.Component {
<button id="recs-page-link-button"
onClick={this.viewRecs.bind(this)}
className="pure-u-1 pure-button button-lg squared button-success">
<i className="fa fa-binoculars"></i> {this.i18n`nav.sections.findAMatch`}
<i className="fa fa-binoculars"></i> {this.state.i18n`nav.sections.findAMatch`}
</button>
</div>
......@@ -73,7 +78,7 @@ class AppPage extends React.Component {
<button id="matches-page-link-button"
onClick={this.viewMatches.bind(this)}
className="pure-u-1 pure-button button-lg squared button-error">
<i className="fa fa-heart"></i> {this.i18n`nav.sections.matches`}
<i className="fa fa-heart"></i> {this.state.i18n`nav.sections.matches`}
</button>
</div>
......@@ -81,7 +86,7 @@ class AppPage extends React.Component {
<button id="preferences-page-link-button"
onClick={this.goToPreferencesPage.bind(this)}
className="pure-u-1 pure-button button-lg squared button-secondary wet-asphalt-bg">
<i className="fa fa-wrench"></i> {this.i18n`nav.sections.preferences`}
<i className="fa fa-wrench"></i> {this.state.i18n`nav.sections.preferences`}
</button>
</div>
......@@ -89,7 +94,7 @@ class AppPage extends React.Component {
<button id="logout-button"
onClick={this.doLogout.bind(this)}
className="pure-u-1 pure-button button-lg squared">
<i className="fa fa-sign-out"></i> {this.i18n`nav.sections.logout`}
<i className="fa fa-sign-out"></i> {this.state.i18n`nav.sections.logout`}
</button>
</div>
</div>
......
import React from "react";
import { generateI18NTemplateFn } from "../i18n";
import LocaleStore from "../stores/locale";
import _ from "lodash";
class DistanceDescription extends React.Component {
constructor(props) {
super(props);
this.i18n = generateI18NTemplateFn("en-US");
this.unsubFunctions = {};
this.state = {
i18n: LocaleStore.state.i18nTemplateFn,
distance: props.distance || 0
};
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
this.setState({i18n: locale.i18nTemplateFn});
});
}
componentWillUnmount() {
_.each(this.unsubFunctions);
}
render() {
// Determine which icon to use
let distanceIconClass = "fa-bicycle";
......@@ -22,9 +34,9 @@ class DistanceDescription extends React.Component {
}
// Determine how to express units
let unit = (this.state.distance == 1) ? this.i18n`distances.mile.single` : this.i18n`distances.mile.multiple`;
let unit = (this.state.distance == 1) ? this.state.i18n`distances.mile.single` : this.state.i18n`distances.mile.multiple`;
return (<span><i className={`fa ${distanceIconClass}`}></i> {this.i18n`distances.unitsAway ${this.state.distance} ${unit}`}</span>);
return (<span><i className={`fa ${distanceIconClass}`}></i> {this.state.i18n`distances.unitsAway ${this.state.distance} ${unit}`}</span>);
}
}
......
import React from "react";
import Actions from "../actions";
import LocaleStore from "../stores/locale";
import { isValidLocaleCode, getLocaleData } from "../i18n";
import _ from "lodash";
class LocaleSelectBox extends React.Component {
constructor(props) {
super(props);
this.unsubFunctions = {};
this.state = {
i18n: LocaleStore.state.i18nTemplateFn,
supportedLocales: LocaleStore.state.supportedLocales,
defaultSelectedLocaleCode: LocaleStore.state.defaultLocale,
selectedLocale: LocaleStore.state.defaultLocale
};
// Set the selected locale to the current locale LocaleStore is using, if set
console.log("LocaleStore.state.locale?", LocaleStore.state.locale);
if (LocaleStore.state.locale) {
this.state.defaultSelectedLocaleCode = LocaleStore.state.locale.code;
}
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
this.setState({
selectedLocale: locale.locale,
i18n: locale.i18nTemplateFn
});
});
}
componentWillUnmount() {
_.each(this.unsubFunctions);
}
changeLocaleByCode(e) {
let code = e.target.value;
if (isValidLocaleCode(code)) {
console.log(`[LOCALE SELECT BOX] Changing locales to locale with code [${code}]`);
Actions.changeLocaleByCode(code);
}
}
render() {
let options = _(this.state.supportedLocales)
.values()
.sortBy('name')
.map(l => {
return (
<option className={`locale-option ${l.localeClassName}`} key={l.code} value={l.code}>
{l.nameInLocale}
</option>
);
})
.value();
return (
<div className="locale-select-box-component">
<div className="pure-g">
<div className="pure-u-1">
<h3 className="no-margin">{this.state.i18n`general.firstCapitalizedLanguage`}</h3>
</div>
<div className="pure-u-1">
<label htmlFor="locale-select" className="pure-u-1-6"><span className={`flag-icon ${this.state.selectedLocale.flagIconClass}`}></span></label>
<select id="locale-select"
className="pure-u-5-6"
onChange={this.changeLocaleByCode.bind(this)}
defaultValue={this.state.defaultSelectedLocaleCode}>
{options}
</select>
</div>
</div>
</div>
);
}
}
export default LocaleSelectBox;
import React from "react";
import { PropTypes } from "react-router";
import FBAuthStore from "../stores/fb-auth";
import LocaleStore from "../stores/locale";
import LocaleSelectBox from "./locale-select-box";
import Actions from "../actions";
import Constants from "../constants";
import { parseLocationHashForLoginResp } from "../util";
import { generateI18NTemplateFn } from "../i18n";
import _ from "lodash";
class LoginPage extends React.Component {
constructor(props, context) {
super(props);
this.i18n = generateI18NTemplateFn("en-US");
console.log("[LOGIN PAGE COMPONENT] Initializing LoginPage!");
this.unsubFunctions = {};
this.state = { i18n: LocaleStore.state.i18nTemplateFn };
console.log("[LOGIN PAGE COMPONENT] Initializing LoginPage, initial state:");
// Detect if the page was loaded as a result of a FB login
let result = parseLocationHashForLoginResp(location.hash);
if (result != null && 'accessToken' in result) {
console.log("[LOGIN PAGE COMPONENT], Detected valid access stoken, storing token and receivedTime/expiresIn.");
Actions.loggedIn(result);
}
if (!_.isNull(result) && _.has(result, 'accessToken')) { Actions.loggedIn(result); }
}
componentDidMount() {
......@@ -27,7 +27,12 @@ class LoginPage extends React.Component {
this.context.history.pushState(null, '/app');
}
this.unsubscribe = FBAuthStore.listen(auth => {
this.unsubFunctions["locale-store"] = LocaleStore.listen(locale => {
console.log("Got new locale value!", locale);
this.setState({i18n: locale.i18nTemplateFn});
});
this.unsubFunctions["fb-auth-store"] = FBAuthStore.listen(auth => {
// Check if the user has been logged in and redirect
// This code might be triggered in the case where the user has already logged in once
// (so value would be read from localstorage), rather than causing redirect for authentication
......@@ -39,7 +44,7 @@ class LoginPage extends React.Component {
}
componentWillUnmount() {
this.unsubscribe();
_.each(this.unsubFunctions);
}
doLogin() {
......@@ -52,12 +57,32 @@ class LoginPage extends React.Component {
return (
<div className={`full-height ${appBgClass}`}>
<div className="row">
<h1 className="slim-text no-top-margin">{this.i18n`app.name`}</h1>
<h2 className="slim-text">{this.i18n`app.subtitle`}</h2>
<button id="login-button" onClick={this.doLogin.bind(this)} className="pure-button button-fb">
<i className="fa fa-facebook-square"></i> {this.i18n`pages.login.login`}
</button>
<div className="pure-g">
<div className="pure-u-1">
<h1 className="slim-text no-top-margin">{this.state.i18n`app.name`}</h1>
<h2 className="slim-text">{this.state.i18n`app.subtitle`}</h2>
</div>
<div className="pure-u-1">
<div className="pure-u-1-5"></div>
<button id="login-button"
className="pure-button pure-u-3-5 button-fb"
onClick={this.doLogin.bind(this)}>
<i className="fa fa-facebook-square"></i> {this.state.i18n`pages.login.login`}
</button>
<div className="pure-u-1-5"></div>
</div>
<div className="pure-u-1">
<div className="pure-u-1-5"></div>
<div className="pure-u-3-5">
<div className="half-opacity-black-bg slim-pad med-margin-top">
<LocaleSelectBox/>
</div>
</div>
<div className="pure-u-1-5"></div>
</div>
</div>
</div>
);
......
import React from "react";
import TinderMatchStore from "../stores/tinder-match";
import LocaleStore from "../stores/locale";
import Actions from "../actions";
import MomentFuzzyDate from "./moment-fuzzy-date";
import _ from "lodash";
import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_STATE = {
matchId: null,
......@@ -16,12 +16,11 @@ const DEFAULT_STATE = {
class MatchConvoLink extends React.Component {
constructor(props) {
super(props);
this.state = DEFAULT_STATE;
this.unsubFunctions = {};
this.i18n = generateI18NTemplateFn("en-US");
// Process props
this.state = _.extend(this.state, {
this.state = _.extend(DEFAULT_STATE, {
i18n: LocaleStore.state.i18nTemplateFn,
matchId: props.matchId || this.state.matchId,
matchedUserId: props.matchedUserId || this.state.matchedUserId,
matchedUser: props.matchedUser || this.state.matchedUser,
......@@ -33,6 +32,10 @@ class MatchConvoLink extends React.Component {
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
this.setState({i18n: locale.i18nTemplateFn});
});
this.unsubFunctions["store-tinder-match"] = TinderMatchStore.listen(store => {
console.log("[MATCH CONVO LINK COMPONENT] Detected tinder match store update:", store);
......@@ -51,7 +54,7 @@ class MatchConvoLink extends React.Component {
}
componentWillUnmount() {
_.each(this.unsubFunctions, f => f());
_.each(this.unsubFunctions);
}
render() {
......@@ -64,7 +67,7 @@ class MatchConvoLink extends React.Component {
return (
<div className="match-convo-link-container">
<div className="pure-g">
<div className="pure-u-1 center-aligned-text">{this.i18n`nav.loadingMessage`}</div>
<div className="pure-u-1 center-aligned-text">{this.state.i18n`nav.loadingMessage`}</div>
</div>
</div>
);
......
import React from "react";
import Actions from "../actions";
import LocaleStore from "../stores/locale";
import MomentFuzzyDate from "./moment-fuzzy-date";
import _ from "lodash";
import { updatePropertyWithEventTargetValue } from "../util";
import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_CLOSE_FN = () => console.log("[MATCH CONVO PAGE COMPONENT] Would have closed convo page!");
const DEFAULT_STATE = {messageText: ""};
......@@ -11,13 +11,22 @@ const DEFAULT_STATE = {messageText: ""};
class MatchConvoPage extends React.Component {
constructor(props) {
super(props);
this.state = DEFAULT_STATE;
this.state = _.extend(DEFAULT_STATE, {i18n: LocaleStore.state.i18nTemplateFn});
this.unsubFunctions = {};
this.i18n = generateI18NTemplateFn("en-US");
console.log("[MATCH CONVO PAGE COMPONENT] Match convo link component constructed, initial state:", this.state);
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
this.setState({i18n: locale.i18nTemplateFn});
});
}
componentWillUnmount() {
_.each(this.unsubFunctions);
}
sendMessageToMatch() {
if (!_.has(this.props, "match")) {
throw new Error("Match not provided for convo page");
......
......@@ -2,22 +2,21 @@ import React from "react";
import { PropTypes } from "react-router";
import Actions from "../actions";
import LHSNav from "./lhs-nav";
import LocaleStore from "../stores/locale";
import TinderMatchStore from "../stores/tinder-match";
import TinderUserStore from "../stores/tinder-user";
import MatchConvoLink from "./match-convo-link";
import MatchConvoPage from "./match-convo-page";
import Constants from "../constants";
import _ from "lodash";
import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_STATE = { matches: [], matchedUserInfo: {}, selectedMatch: null, user: null};
class MatchesPage extends React.Component {
constructor(props) {
super(props);
this.state = DEFAULT_STATE;
this.state = _.extend(DEFAULT_STATE, {i18n: LocaleStore.state.i18nTemplateFn});
this.unsubFunctions = {};
this.i18n = generateI18NTemplateFn("en-US");
// Set matches if user is available through the TinderMatchStore
if (_.isNull(this.state.matches) && !_.isNull(TinderMatchStore.state.user)) {
......@@ -35,6 +34,10 @@ class MatchesPage extends React.Component {
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
this.setState({i18n: locale.i18nTemplateFn});
});
this.unsubFunctions["store-tinder-match"] = TinderMatchStore.listen(store => {
console.log("[MATCHES PAGE COMPONENT] Detected tinder match store update", store);
this.setState({matches: store.matches, matchedUserInfo: store.matchedUserInfo});
......@@ -79,10 +82,10 @@ class MatchesPage extends React.Component {
// Generate no matches message
matchListElem = (
<div id="no-matches-message" className="pure-u-1 center-aligned-text">
<h3 className="slim-text">No matches found</h3>
<h3 className="slim-text">{this.state.i18n`pages.matches.noMatchesFound`}</h3>
<button onClick={this.gotoRecsPage.bind(this)}
className="pure-button button-success">
<i className="fa fa-binoculars"></i> {this.i18n`pages.matches.findSomeoneNew`}
<i className="fa fa-binoculars"></i> {this.state.i18n`pages.matches.findSomeoneNew`}
</button>
</div>
);
......@@ -122,8 +125,8 @@ class MatchesPage extends React.Component {
<div className="pure-g">
<div className="pure-u-1 right-aligned-text">
<div className="right-aligned-text">
<h1 className="no-vertical-margins slim-text">{this.i18n`nav.sections.matches`}</h1>
<h3 className="no-vertical-margins super-slim-text">{this.i18n`pages.matches.pageSubtitle`}</h3>
<h1 className="no-vertical-margins slim-text">{this.state.i18n`nav.sections.matches`}</h1>
<h3 className="no-vertical-margins super-slim-text">{this.state.i18n`pages.matches.pageSubtitle`}</h3>
</div>
</div>
</div>
......
import React from "react";
import Actions from "../actions";
import LHSNav from "./lhs-nav";
import LocaleStore from "../stores/locale";
import LocaleSelectBox from "./locale-select-box";
import TinderUserStore from "../stores/tinder-user";
import CollapsibleLabeledFormSection from "./collapsible-labeled-form-section";
import Constants from "../constants";
import _ from "lodash";
import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_STATE = { prefs: null, useCurrentGPS: true };
......@@ -14,7 +15,9 @@ class PreferencesPage extends React.Component {
super(props);
this.state = DEFAULT_STATE;
this.unsubFunctions = {};
this.i18n = generateI18NTemplateFn("en-US");
// Add i18n default templating function
this.state = _.extend(this.state, {i18n: LocaleStore.state.i18nTemplateFn});
// Set prefs if user is available through the TinderUserStore
if (_.isNull(this.state.prefs) && !_.isNull(TinderUserStore.state.user)) {
......@@ -30,6 +33,11 @@ class PreferencesPage extends React.Component {
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
console.log("[PREFERENCES PAGE COMPONENT] Received locale update!", locale);
this.setState({i18n: locale.i18nTemplateFn});
});
this.unsubFunctions["store-tinder-user"] = TinderUserStore.listen(store => {
console.log("[PREFERENCES PAGE COMPONENT] Detected tinder user update, updating state");
this.setState({prefs: this.buildPreferencesFromUser(store.user)});
......@@ -37,7 +45,7 @@ class PreferencesPage extends React.Component {
}
componentWillUnmount() {
_.each(this.unsubFunctions, f => f());
_.each(this.unsubFunctions);
}
/**
......@@ -112,7 +120,7 @@ class PreferencesPage extends React.Component {
let genderFilter = _.get(this.state, "prefs.gender");
let genderIsMale = genderFilter === Constants.TINDER_GENDER_MALE;
let genderIsFemale = genderFilter === Constants.TINDER_GENDER_FEMALE;
let genderName = genderIsMale ? this.i18n`general.firstCapitalizedMale` : this.i18n`general.firstCapitalizedFemale`;
let genderName = genderIsMale ? this.state.i18n`general.firstCapitalizedMale` : this.state.i18n`general.firstCapitalizedFemale`;
// Request user to build prefs if not provided yet
if (_.isNull(this.state.prefs)) {
......@@ -128,19 +136,20 @@ class PreferencesPage extends React.Component {
return (
<div>
<LHSNav />
<div className="preference-page-container">
<div className="preference-page-container contains-page-bottom-controls">
<div className="pure-g">
<div className="pure-u-1">
<div className="right-aligned-text">
<h1 className="no-vertical-margins slim-text">{this.i18n`nav.sections.preferences`}</h1>
<h3 className="no-vertical-margins super-slim-text">{this.i18n`pages.preferences.pageSubtitle`}</h3>
<h1 className="no-vertical-margins slim-text">{this.state.i18n`nav.sections.preferences`}</h1>
<h3 className="no-vertical-margins super-slim-text">{this.state.i18n`pages.preferences.pageSubtitle`}</h3>
<form className="pure-form pure-form-stacked preference-update-form left-aligned-text"
onSubmit={this.updatePreferences.bind(this)}>
<fieldset>
<CollapsibleLabeledFormSection labelFor="gender"
labelText={this.i18n`pages.preferences.genderSectionHeading`}>
labelText={this.state.i18n`pages.preferences.genderSectionHeading`}>
<div className="pure-g">
<div className="pure-u-1-3">
<div className="two-button-options">
......@@ -166,7 +175,7 @@ class PreferencesPage extends React.Component {
</CollapsibleLabeledFormSection>
<CollapsibleLabeledFormSection labelFor="age-filter"
labelText={this.i18n`pages.preferences.ageSectionHeading`}>
labelText={this.state.i18n`pages.preferences.ageSectionHeading`}>
<div className="pure-g">
<div className="pure-u-1-3 center-aligned-text">
<select id="age-filter-min"
......@@ -177,7 +186,7 @@ class PreferencesPage extends React.Component {
</select>
</div>
<div className="pure-u-1-3 center-aligned-text hacked-vertical-center">
<span className="large">{this.i18n`pages.preferences.inbetweenAges`}</span>
<span className="large">{this.state.i18n`pages.preferences.inbetweenAges`}</span>
</div>
<div className="pure-u-1-3 center-aligned-text">
<select id="age-filter-max"
......@@ -191,7 +200,7 @@ class PreferencesPage extends React.Component {
</CollapsibleLabeledFormSection>
<CollapsibleLabeledFormSection labelFor="distance-filter"
labelText={this.i18n`pages.preferences.distanceSectionHeading`}>
labelText={this.state.i18n`pages.preferences.distanceSectionHeading`}>
<div className="pure-g">
<div className="pure-u-1-2">
<input id="distance-filter"
......@@ -201,25 +210,25 @@ class PreferencesPage extends React.Component {
value={this.state.prefs.distance_filter}/>
</div>
<div className="pure-u-1-2 hacked-vertical-center">
<span className="large">{this.i18n`distances.milesAway`}</span>
<span className="large">{this.state.i18n`distances.milesAway`}</span>
</div>
</div>
</CollapsibleLabeledFormSection>
<CollapsibleLabeledFormSection labelFor="location-gps"
labelText={this.i18n`pages.preferences.locationSectionHeading`}>
labelText={this.state.i18n`pages.preferences.locationSectionHeading`}>
<div className="pure-g">
<div className="row">
<button type="button"
onClick={() => this.setState({useCurrentGPS: true})}
className="pure-u-1-2 pure-button squared button-secondary">
<i className="fa fa-map-marker"></i> {this.i18n`pages.preferences.fromGPS`}
<i className="fa fa-map-marker"></i> {this.state.i18n`pages.preferences.fromGPS`}
</button>
<button type="button"
className="pure-u-1-2 pure-button squared pure-button-disabled">
<i className="fa fa-pencil"></i> {this.i18n`pages.preferences.customLocation`}
<i className="fa fa-pencil"></i> {this.state.i18n`pages.preferences.customLocation`}
</button>
</div>
</div>
......@@ -228,6 +237,10 @@ class PreferencesPage extends React.Component {
</fieldset>
</form>
</div>
</div> {/* /.pure-u-1 */}
<div className="pure-u-1">
<LocaleSelectBox />
</div>
<div className="pinned-to-bottom page-bottom-controls">
......@@ -238,7 +251,7 @@ class PreferencesPage extends React.Component {
className="pure-u-1 pure-button button-success button-lg squared"
onClick={this.updatePreferences.bind(this)}>
<div><i className="fa fa-save"></i></div>
<div className="center-aligned-text small-text">{this.i18n`pages.preferences.updatePreferences`}</div>
<div className="center-aligned-text small-text">{this.state.i18n`pages.preferences.updatePreferences`}</div>
</button>
</div>
......@@ -247,7 +260,7 @@ class PreferencesPage extends React.Component {
className="pure-u-1 pure-button button-lg squared"
onClick={this.resetPreferences.bind(this)}>
<div><i className="fa fa-trash"></i></div>
<div className="center-aligned-text small-text">{this.i18n`pages.preferences.undoChanges`}</div>
<div className="center-aligned-text small-text">{this.state.i18n`pages.preferences.undoChanges`}</div>
</button>
</div>
......
import React from "react";
import { Link, PropTypes } from "react-router";
import LocaleStore from "../stores/locale";
import TinderRecommendationStore from "../stores/tinder-recommendation";
import LHSNav from "./lhs-nav";
import GenderIcon from "./gender-icon";
......@@ -8,7 +9,6 @@ import MomentFuzzyDate from "./moment-fuzzy-date";
import PictureStrip from "./picture-strip";
import Actions from "../actions";
import _ from "lodash";
import { generateI18NTemplateFn } from "../i18n";
const DEFAULT_STATE = {recPhotoIndex: 0, rec: null, detailVisible: true};
......@@ -16,8 +16,7 @@ class RecsPage extends React.Component {
constructor(props) {
super(props);
this.unsubFunctions = {};
this.state = DEFAULT_STATE;
this.i18n = generateI18NTemplateFn("en-US");
this.state = _.extend(DEFAULT_STATE, {i18n: LocaleStore.state.i18nTemplateFn});
// Set rec if available through the TinderRecommendationStore
if (_.isNull(this.state.rec) && !_.isNull(TinderRecommendationStore.state.currentRec)) {
......@@ -27,6 +26,10 @@ class RecsPage extends React.Component {
}
componentDidMount() {
this.unsubFunctions["locale"] = LocaleStore.listen(locale => {
this.setState({i18n: locale.i18nTemplateFn});
});
// Setup subscriptions
this.unsubFunctions["store-tinder-recommendations"] = TinderRecommendationStore.listen(state => {
// Update current recommendation
......@@ -39,7 +42,7 @@ class RecsPage extends React.Component {
}
componentWillUnmount() {
_.each(this.unsubFunctions, f => f());
_.each(this.unsubFunctions);
}
toggleDetail() { this.setState({detailVisible: !this.state.detailVisible}); }
......@@ -53,32 +56,38 @@ class RecsPage extends React.Component {
// If there is no current rec, request some
if (_.isNull(this.state.rec)) { this.pullRecommendations(); }
let recsFetchFailedMessage = this.state.recsFetchFailed ? this.i18n`pages.recs.recsFetchFailed` : "";
let recsFetchFailedMessage = "";
if (this.state.recsFetchFailed) {
recsFetchFailedMessage = (
<div className="pure-u-1">
<div className="alizarin-bg white-face slim-pad slim-margin">
{this.state.i18n`pages.recs.recsFetchFailed`}
</div>
</div>