Commit c412bfba authored by MrMan's avatar MrMan

Resolves #28, Add japanese support to all pages on the app

parent e882b4b3
Pipeline #2549897 skipped
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>);
}
}
......
......@@ -8,19 +8,28 @@ class LocaleSelectBox extends React.Component {
constructor(props) {
super(props);
this.unsubFunctions = {};
this.i18n = LocaleStore.state.i18nTemplateFn;
this.state = {
i18n: LocaleStore.state.i18nTemplateFn,
supportedLocales: LocaleStore.state.supportedLocales,
defaultSelectedLocale: LocaleStore.state.defaultLocale,
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});
this.i18n = locale.i18nTemplateFn;
this.setState({
selectedLocale: locale.locale,
i18n: locale.i18nTemplateFn
});
});
}
......@@ -54,15 +63,15 @@ class LocaleSelectBox extends React.Component {
<div className="pure-g">
<div className="pure-u-1">
<h3 className="no-margin">{this.i18n`general.firstCapitalizedLanguage`}</h3>
<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"
<select id="locale-select"
className="pure-u-5-6"
onChange={this.changeLocaleByCode.bind(this)}
defaultValue={this.state.defaultSelectedLocale}>
onChange={this.changeLocaleByCode.bind(this)}
defaultValue={this.state.defaultSelectedLocaleCode}>
{options}
</select>
</div>
......
......@@ -6,7 +6,6 @@ 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 {
......
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>
......
......@@ -7,7 +7,6 @@ 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 };
......
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>
);
}
// Return early if there is no rec
if (_.isNull(this.state.rec) || this.state.recsFetchFailed) {
return (
<div class="pure-g">
<div className="pure-u-1 center-aligned-text">
<h3>{this.i18n`pages.recs.noRecsMessage`}</h3>
<h4>{_.isNull(this.state.rec) && !this.state.recsFetchFailed ? this.i18n`pages.recs.updatePrefsMaybe` : this.i18n`pages.recs.hitDailyLimitMaybe`}</h4>
<h3>{this.state.i18n`pages.recs.noRecsMessage`}</h3>
<h4>{_.isNull(this.state.rec) && !this.state.recsFetchFailed ? this.state.i18n`pages.recs.updatePrefsMaybe` : this.state.i18n`pages.recs.hitDailyLimitMaybe`}</h4>
</div>
<div className="pure-u-1">
<div className="alizarin-bg white-face slim-pad slim-margin">
{recsFetchFailedMessage}
</div>
</div>
{recsFetchFailedMessage}
<div className="pure-u-1">
<button className="pure-button button-secondary in-stack">
<i className="fa fa-wrench"></i> {this.i18n`pages.recs.managePrefs`}
<i className="fa fa-wrench"></i> {this.state.i18n`pages.recs.managePrefs`}
</button>
</div>
<div className="pure-u-1">
<button onClick={this.context.history.goBack} className="pure-button button-error">
<i className="fa fa-arrow-left"></i> {this.i18n`nav.back`}
<i className="fa fa-arrow-left"></i> {this.state.i18n`nav.back`}
</button>
</div>
......@@ -96,9 +105,9 @@ class RecsPage extends React.Component {
let detailFragment = (
<div className={`rec-detail picture-overlay-text ${this.state.detailVisible ? "visible" : "invisible"}`} >
<p className="picture-overlay-text"><DistanceDescription distance={this.state.rec.distance_mi}/></p>
<p className="picture-overlay-text"><i className="fa fa-users"></i> {this.i18n`pages.recs.friendsInCommon ${this.state.rec.common_friend_count}`}</p>
<p className="picture-overlay-text"><i className="fa fa-thumbs-up"></i> {this.i18n`pages.recs.commonInterests ${this.state.rec.common_like_count}`}</p>
<p className="picture-overlay-text"><i className="fa fa-clock-o"></i> {this.i18n`pages.recs.lastActive`} <MomentFuzzyDate date={this.state.rec.ping_time}/></p>
<p className="picture-overlay-text"><i className="fa fa-users"></i> {this.state.i18n`pages.recs.friendsInCommon ${this.state.rec.common_friend_count}`}</p>
<p className="picture-overlay-text"><i className="fa fa-thumbs-up"></i> {this.state.i18n`pages.recs.commonInterests ${this.state.rec.common_like_count}`}</p>
<p className="picture-overlay-text"><i className="fa fa-clock-o"></i> {this.state.i18n`pages.recs.lastActive`} <MomentFuzzyDate date={this.state.rec.ping_time}/></p>
</div>
);
......@@ -140,14 +149,14 @@ class RecsPage extends React.Component {
<div className="pure-u-1-2">
<button onClick={this.pass.bind(this)} className="pure-u-1 pure-button button-lg squared button-error">
<div><i className="fa fa-binoculars"></i></div>
<div className="center-aligned-text small-text">{this.i18n`pages.recs.keepSearching`}</div>
<div className="center-aligned-text small-text">{this.state.i18n`pages.recs.keepSearching`}</div>
</button>
</div>
<div className="pure-u-1-2">
<button onClick={this.like.bind(this)} className="pure-u-1 pure-button button-lg squared button-success">
<div><i className="fa fa-heart"></i></div>
<div className="center-aligned-text small-text">{this.i18n`pages.recs.like`}</div>
<div className="center-aligned-text small-text">{this.state.i18n`pages.recs.like`}</div>
</button>
</div>
</div>
......
......@@ -64,6 +64,7 @@ export default {
matches: {
pageSubtitle: "Talk with your matches",
findSomeoneNew: "Find someone new",
noMatchesFound: "No matches found",
lastMessageSent: "Last message sent"
}
}
......
......@@ -58,12 +58,13 @@ export default {
commonInterests: "{} 趣味(共通)",
lastActive: "最後に見た",
keepSearching: "まだ勧告を見る",
interested: "ライク",
like: "ライク",
recsFetchFailed: "勧告探しは二同出来ませんでしたのでKindlingをクロースして、もうオーペンしてください。"
},
matches: {
pageSubtitle: "合わせた人と話す",
findSomeoneNew: "新しい人を探す",
noMatchesFound: "よく合わせる人わ見つけられませんでした",
lastMessageSent: "最後通信したのメッセージ"
}
}
......
......@@ -13,8 +13,7 @@ const DEFAULT_LOCALE_CODE = DEFAULT_LOCALE_DATA.code;
const DEFAULT_STATE = {
locale: DEFAULT_LOCALE_DATA, // Will return default locale
defaultLocale: DEFAULT_LOCALE_DATA,
supportedLocales: SUPPORTED_LOCALES,
i18nTemplateFn: generateI18NTemplateFn(DEFAULT_LOCALE_DATA.code)
supportedLocales: SUPPORTED_LOCALES
};
const LocalStorageBackupMixin = LocalStorageBackupMixinGenerator(Constants.LOCALSTORAGE_KEY_LOCALE_STORE_STATE);
......@@ -22,19 +21,14 @@ const LocalStorageBackupMixin = LocalStorageBackupMixinGenerator(Constants.LOCAL
let LocaleStore = Reflux.createStore({
mixins: [LocalStorageBackupMixin],
init() {
console.log("[LOCALE STORE] Initializing app locale store...");
// Subscribe to actions
this.listenTo(Actions.changeLocaleByCode, this.changeLocaleByCode);
// Gather state for the store from localstorage/other sources
this.state = _.extend(DEFAULT_STATE, this.gatherState());
// Generate locale if not present
var localeIsPresent = !_.isUndefined(this.state.locale) || !_.isNull(this.state.locale);
if (localeIsPresent && _.isNull(this.state.i18nTemplateFn)) {
this.state.i18nTemplateFn = generateI18NTemplateFn(this.state.locale.code);
}
// Generate locale templating function
this.state.i18nTemplateFn = generateI18NTemplateFn(this.state.locale.code);
console.log("[LOCALE STORE] Initial state:", _.extend({}, this.state));
},
......@@ -49,6 +43,7 @@ let LocaleStore = Reflux.createStore({
console.log(`[LOCALE STORE] Changing locale to [${code}]`);
this.state.locale = getLocaleData(code);
this.state.i18nTemplateFn = generateI18NTemplateFn(this.state.locale.code);
this.backupState();
this.trigger(this.state);
}
......
......@@ -142,6 +142,7 @@ let TinderSentimentStore = Reflux.createStore({
.then(resolve)
.catch(err => {
alert("Failed to save like/dislike to Tinder.");
Actions.logout(); // Logout if there was a failure to process
// If processing a sentiment fails, save it in the pending list
this.state.pendingSentiments.push(sentiment);
reject(err);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment