message text t() and formatting improvements

pull/437/head
gabrielburnworth 2017-08-30 22:12:11 -07:00
parent 5b6c119e18
commit 45e42689da
16 changed files with 96 additions and 61 deletions

View File

@ -20,7 +20,7 @@ export class DeleteAccount extends
<WidgetHeader title="Delete Account" />
<WidgetBody>
<div>
{Content.ACCOUNT_DELETE_WARNING}
{t(Content.ACCOUNT_DELETE_WARNING)}
<br /><br />
{t(`If you are sure you want to delete your account, type in
your password below to continue.`)}

View File

@ -1,4 +1,5 @@
import * as React from "react";
import { t } from "i18next";
import { connect } from "react-redux";
import { Settings, DeleteAccount, ChangePassword } from "./components";
import { Props } from "./interfaces";
@ -33,7 +34,7 @@ export class Account extends React.Component<Props, State> {
onSave = () => this
.props
.dispatch(save(this.props.user.uuid))
.then(() => success("saved"), updateNO);
.then(() => success(t("saved")), updateNO);
render() {
return <Page className="account">

View File

@ -1,4 +1,5 @@
import * as React from "react";
import * as React from "react";
import { t } from "i18next";
import { connect } from "react-redux";
import * as _ from "lodash";
import { init, error } from "farmbot-toastr";
@ -11,21 +12,15 @@ import { ResourceName, TaggedUser } from "./resources/tagged_resources";
import { selectAllLogs, maybeFetchUser } from "./resources/selectors";
import { HotKeys } from "./hotkeys";
import { ControlsPopup } from "./controls_popup";
import { Content } from "./constants";
/** Remove 300ms delay on touch devices - https://github.com/ftlabs/fastclick */
/** Remove 300ms delay on touch devices - https://github.com/ftlabs/fastclick */
const fastClick = require("fastclick");
fastClick.attach(document.body);
/** For the logger module */
/** For the logger module */
init();
/**
* If the sync object takes more than 10s to load, the user will be granted
* access into the app, but still warned.
*/
const TIMEOUT_MESSAGE = `App could not be fully loaded, we recommend you try
refreshing the page.`;
interface AppProps {
dispatch: Function;
loaded: ResourceName[];
@ -67,10 +62,14 @@ export class App extends React.Component<AppProps, {}> {
_.intersection(this.props.loaded, MUST_LOAD).length);
}
/**
* If the sync object takes more than 10s to load, the user will be granted
* access into the app, but still warned.
*/
componentDidMount() {
setTimeout(() => {
if (!this.isLoaded) {
error(TIMEOUT_MESSAGE, "Warning");
error(t(Content.APP_LOAD_TIMEOUT_MESSAGE), t("Warning"));
}
}, 10000);
}

View File

@ -126,7 +126,7 @@ export function logout() {
// In those cases, seeing a logout message may confuse the user.
// To circumvent this, we must check if the user had a token.
// If there was infact a token, we can safely show the message.
if (Session.getAll()) { success("You have been logged out."); }
if (Session.getAll()) { success(t("You have been logged out.")); }
Session.clear();
// Technically this is unreachable code:
return {

View File

@ -255,9 +255,9 @@ export namespace Content {
your FarmBot so that is goes back into configuration mode for pairing with
another user account. When this happens, all of the data on your FarmBot
will be overwritten with the new account's data. If the account is brand
new, then FarmBot will become a blank slate.`;
new, then FarmBot will become a blank slate.`.replace(/\s+/g, " ");
// Controls
// Device
export const FACTORY_RESET_WARNING =
`Factory resetting your FarmBot will destroy all data on the device,
revoking your FarmBot's abilily to connect to your web app account and your
@ -265,14 +265,58 @@ export namespace Content {
Configurator mode. Factory resetting your FarmBot will not affect any data
or settings from your web app account, allowing you to do a complete restore
to your device once it is back online and paired with your web app
account.`;
account.`.replace(/\s+/g, " ");
export const TIMEZONE_GUESS_BROWSER =
`This account did not have a timezone set. Farmbot requires a timezone to
operate. We have updated your timezone settings based on your browser.
Please verify these settings in the device settings panel. Device sync is
recommended.`.replace(/\s+/g, " ");
export const TIMEZONE_GUESS_UTC =
`Warning: Farmbot could not guess your timezone. We have defaulted your
timezone to UTC, which is less than ideal for most users. Please select
your timezone from the dropdown. Device sync is recommended.`.replace(/\s+/g, " ");
// Hardware Settings
export const RESTORE_DEFAULT_HARDWARE_SETTINGS =
`Restoring hardware parameter defaults will destroy the
current settings, resetting them to default values.`.replace(/\s+/g, " ");
// App
export const APP_LOAD_TIMEOUT_MESSAGE =
`App could not be fully loaded, we recommend you try
refreshing the page.`.replace(/\s+/g, " ");
export const MQTT_DISCONNECTED =
`Your web browser is unable to connect to the message broker (MQTT).
You might be behind a firewall or disconnected from the Internet. Check
your network settings.`.replace(/\s+/g, " ");
export const MALFORMED_MESSAGE_REC_UPGRADE =
`FarmBot sent a malformed message. You may need to upgrade
FarmBot OS. Please upgrade FarmBot OS and log back in.`.replace(/\s+/g, " ");
// Experimental Warning
export const EXPERIMENTAL_WARNING =
`Warning! This is an EXPERIMENTAL feature. This feature may be broken and may
break or otherwise hinder your usage of the rest of the app. This feature may
disappear or break at any time.`;
disappear or break at any time.`.replace(/\s+/g, " ");
// Front Page
export const TOS_UPDATE =
`The terms of service have recently changed. You must accept the new
terms of service to continue using the site.`.replace(/\s+/g, " ");
// Farm Events
export const REGIMEN_TODAY_SKIPPED_ITEM_RISK =
`You are scheduling a regimen to run today. Be aware that
running a regimen too late in the day may result in skipped
regimen tasks. Consider rescheduling this event to tomorrow if
this is a concern.`.replace(/\s+/g, " ");
export const INVALID_RUN_TIME =
`This Farm Event does not appear to have a valid run time.
Perhaps you entered bad dates?`.replace(/\s+/g, " ");
}
export enum Actions {

View File

@ -34,10 +34,10 @@ export class Peripherals extends React.Component<PeripheralsProps, PeripheralSta
if (allAreSmall) {
this.props.dispatch(saveAll(this.props.peripherals, this.toggle));
} else {
error("Pin numbers must be less than 1000.");
error(t("Pin numbers must be less than 1000."));
}
} else {
error("Pin numbers are required and must be positive and unique.");
error(t("Pin numbers are required and must be positive and unique."));
}
}

View File

@ -25,7 +25,7 @@ import { getDeviceAccountSettings } from "../resources/selectors";
import { TaggedDevice } from "../resources/tagged_resources";
import { versionOK } from "./reducer";
import { oneOf, HttpData } from "../util";
import { Actions } from "../constants";
import { Actions, Content } from "../constants";
import { mcuParamValidator } from "./update_interceptor";
const ON = 1, OFF = 0;
@ -130,7 +130,7 @@ export function sync(): Thunk {
.controller_version) {
badVersion();
} else {
info("FarmBot is not connected.", "Disconnected", "red");
info(t("FarmBot is not connected."), t("Disconnected"), "red");
}
}
};
@ -178,7 +178,7 @@ export function save(input: TaggedDevice) {
return axios
.put(API.current.devicePath, input.body)
.then((resp: HttpData<User>) => dispatch({ type: "SAVE_DEVICE_OK", payload: resp.data }))
.catch(resp => error("Error saving device settings."));
.catch(resp => error(t("Error saving device settings.")));
};
}
@ -268,9 +268,7 @@ export function connectDevice(token: string): ConnectDeviceReturn {
bot.on("online", () => dispatch(setMqttStatus(true)));
bot.on("offline", () => {
dispatch(setMqttStatus(false));
error(t("Your web browser is unable to connect to the message broker " +
"(MQTT). You might be behind a firewall or disconnected from the " +
"Internet. Check your network settings."));
error(t(Content.MQTT_DISCONNECTED));
});
return bot
.connect()
@ -313,8 +311,7 @@ export function connectDevice(token: string): ConnectDeviceReturn {
let alreadyToldYou = false;
bot.on("malformed", function () {
if (!alreadyToldYou) {
warning(t(`FarmBot sent a malformed message. You may need to upgrade
FarmBot OS. Please upgrade FarmBot OS and log back in.`));
warning(t(Content.MALFORMED_MESSAGE_REC_UPGRADE));
alreadyToldYou = true;
}
});
@ -413,7 +410,7 @@ export function setSyncStatus(payload: SyncStatus) {
}
function badVersion() {
info("You are running an old version of FarmBot OS.", "Please Update", "red");
info(t("You are running an old version of FarmBot OS."), t("Please Update"), "red");
}
export let setMqttStatus = (payload: boolean) => ({

View File

@ -4,6 +4,7 @@ import { DangerZoneProps } from "../interfaces";
import { Row, Col } from "../../../ui/index";
import { Header } from "./header";
import { Collapse } from "@blueprintjs/core";
import { Content } from "../../../constants";
export function DangerZone(props: DangerZoneProps) {
@ -25,8 +26,7 @@ export function DangerZone(props: DangerZoneProps) {
</Col>
<Col xs={6}>
<p>
{t(`Restoring hardware parameter defaults will destroy the
current settings, resetting them to default values.`)}
{t(Content.RESTORE_DEFAULT_HARDWARE_SETTINGS)}
<br />
<b>
{t("Will reboot device.")}

View File

@ -1,4 +1,6 @@
import { t } from "i18next";
import * as _ from "lodash";
import { Content } from "../../constants";
/** Remove this in October 2017 - RC */
const ONLY_ONCE = {
need_to_talk: true
@ -11,21 +13,14 @@ export function inferTimezone(current: string | undefined): string {
const browserTime = maybeResolveTZ();
if (browserTime) {
if (ONLY_ONCE.need_to_talk) {
alert("This account did not have a timezone set. " +
"Farmbot requires a timezone to operate. " +
"We have updated your timezone settings based on your browser. " +
"Please verify these settings in the device settings panel. " +
"Device sync is recommended.");
alert(t(Content.TIMEZONE_GUESS_BROWSER));
ONLY_ONCE.need_to_talk = false;
}
// WARNING SIDE EFFECTS!!!
return browserTime;
}
if (ONLY_ONCE.need_to_talk) {
alert("Warning: Farmbot could not guess your timezone. " +
"We have defaulted your timezone to UTC, which is less than ideal for " +
"most users. Please select your timezone from the dropdown. Device " +
"sync is recommended.");
alert(t(Content.TIMEZONE_GUESS_UTC));
ONLY_ONCE.need_to_talk = false;
}
return "UTC";

View File

@ -35,6 +35,7 @@ import { TzWarning } from "./tz_warning";
import { FarmEventRepeatForm } from "./farm_event_repeat_form";
import { scheduleForFarmEvent } from "./calendar/scheduler";
import { executableType } from "../util";
import { Content } from "../../constants";
type FormEvent = React.SyntheticEvent<HTMLInputElement>;
export const NEVER: TimeUnit = "never";
@ -184,21 +185,17 @@ export class EditFEForm extends React.Component<EditFEProps, State> {
if (nextRun) {
// TODO: Internationalizing this will be a challenge.
success(`This Farm Event will run ${nextRun.fromNow()}, but
you must first SYNC YOUR DEVICE. If you do not sync, the event will\
not run.`);
you must first SYNC YOUR DEVICE. If you do not sync, the event will
not run.`.replace(/\s+/g, " "));
this.props.dispatch(maybeWarnAboutMissedTasks(frmEvnt, function () {
alert(`You are scheduling a regimen to run today. Be aware that
running a regimen too late in the day may result in skipped
regimen tasks. Consider rescheduling this event to tomorrow if
this is a concern.`.replace(/\s+/g, " "));
alert(t(Content.REGIMEN_TODAY_SKIPPED_ITEM_RISK));
}));
} else {
error(`This Farm Event does not appear to have a valid run time.
Perhaps you entered bad dates?`);
error(t(Content.INVALID_RUN_TIME));
}
})
.catch(() => {
error("Unable to save farm event.");
error(t("Unable to save farm event."));
this.setState({ specialStatusLocal: SpecialStatus.DIRTY });
});
}
@ -267,7 +264,7 @@ export class EditFEForm extends React.Component<EditFEProps, State> {
onClick={() => {
this.dispatch(destroy(fe.uuid)).then(() => {
history.push("/app/designer/farm_events");
success("Deleted farm event.", "Deleted");
success(t("Deleted farm event."), t("Deleted"));
});
}}>
{t("Delete")}

View File

@ -1,4 +1,5 @@
import * as React from "react";
import { t } from "i18next";
import { EditPlantInfoProps } from "../interfaces";
import { history } from "../../history";
import { destroy } from "../../api/crud";
@ -17,7 +18,7 @@ export abstract class PlantInfoBase extends
destroy = (plantUUID: string) => {
this.props.dispatch(destroy(plantUUID))
.then(() => history.push("/app/designer/plants"))
.catch(() => error("Could not delete plant.", "Error"));
.catch(() => error(t("Could not delete plant."), t("Error")));
}
fallback = () => {

View File

@ -59,7 +59,7 @@ export class FarmwarePanel extends React.Component<FWProps, Partial<FWState>> {
.installFarmware(this.state.packageUrl)
.then(() => this.setState({ packageUrl: "" }));
} else {
alert("Enter a URL");
alert(t("Enter a URL"));
}
}

View File

@ -38,7 +38,7 @@ export class Photos extends React.Component<PhotosProps, {}> {
takePhoto = () => {
const ok = () => success(t("Processing now. Refresh page to see result."));
const no = () => error("Error taking photo");
const no = () => error(t("Error taking photo"));
devices.current.takePhoto().then(ok, no);
}
@ -58,8 +58,8 @@ export class Photos extends React.Component<PhotosProps, {}> {
const img = this.props.currentImage || this.props.images[0];
if (img && img.uuid) {
this.props.dispatch(destroy(img.uuid))
.then(() => success("Image Deleted.", "Success"))
.catch(() => error("Could not delete image.", "Error"));
.then(() => success(t("Image Deleted."), t("Success")))
.catch(() => error(t("Could not delete image."), t("Error")));
}
}

View File

@ -116,7 +116,7 @@ export class FrontPage extends React.Component<{}, Partial<FrontPageState>> {
const data = { email };
axios.post(API.current.passwordResetPath, data)
.then(() => {
success("Email has been sent.", "Forgot Password");
success(t("Email has been sent."), t("Forgot Password"));
this.setState({ forgotPassword: false });
}).catch(error => {
let errorMessage = prettyPrintApiErrors(error);
@ -124,7 +124,7 @@ export class FrontPage extends React.Component<{}, Partial<FrontPageState>> {
errorMessage =
`That email address is not associated with an account.`;
}
log(errorMessage);
log(t(errorMessage));
});
}

View File

@ -11,6 +11,7 @@ import { API } from "./api/index";
import { AuthState } from "./auth/interfaces";
import * as _ from "lodash";
import { AxiosRequestConfig, AxiosResponse } from "axios";
import { Content } from "./constants";
export function responseFulfilled(input: AxiosResponse): AxiosResponse {
let method = input.config.method;
@ -44,8 +45,7 @@ export function responseRejected(x: SafeError | undefined) {
break;
case 451:
// DONT REFACTOR: I want to use alert() because it's blocking.
alert(t("The terms of service have recently changed. You must " +
"accept the new terms of service to continue using the site."));
alert(t(Content.TOS_UPDATE));
window.location.href = "/tos_update";
break;
}

View File

@ -1,4 +1,5 @@
import * as React from "react";
import { t } from "i18next";
import { SequenceBodyItem as Step } from "farmbot";
import { error } from "farmbot-toastr";
import { StepDragger, NULL_DRAGGER_ID } from "../../draggable/step_dragger";
@ -12,7 +13,7 @@ const stepClick = (dispatch: Function, step: Step, seq: TaggedSequence | undefin
if (seq) {
pushStep(step, dispatch, seq);
} else {
error("Select a sequence first");
error(t("Select a sequence first"));
}
};