From f7cdcd0b55114e6442dc369d46945f32be9e3985 Mon Sep 17 00:00:00 2001 From: Sebastian Ilves Date: Fri, 26 May 2017 14:02:36 +0200 Subject: [PATCH] Added support for different translation functions --- CHANGELOG.md | 5 + README.md | 14 ++- imports/helpers.js | 9 +- imports/ui/components/Button.jsx | 3 +- imports/ui/components/Field.jsx | 3 +- imports/ui/components/Form.jsx | 16 ++-- imports/ui/components/LoginForm.jsx | 100 +++++++++++--------- imports/ui/components/PasswordOrService.jsx | 7 +- package.js | 2 +- 9 files changed, 94 insertions(+), 65 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 057432b..fca3ed3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # ChangeLog +### v1.2.21 +26-May-2017 + +* Added functionality to include your own translation function. + ### v1.2.20 13-March-2017 diff --git a/README.md b/README.md index dfb2766..f88f1bc 100644 --- a/README.md +++ b/README.md @@ -399,14 +399,15 @@ To install the dependencies added in your package.json run: // main.jsx import React from 'react'; +import PropTypes from 'prop-types'; import { Accounts, STATES } from 'meteor/std:accounts-ui'; /** * Form.propTypes = { - * fields: React.PropTypes.object.isRequired, - * buttons: React.PropTypes.object.isRequired, - * error: React.PropTypes.string, - * ready: React.PropTypes.bool + * fields: PropTypes.object.isRequired, + * buttons: PropTypes.object.isRequired, + * error: PropTypes.string, + * ready: PropTypes.bool * }; */ class Form extends Accounts.ui.Form { @@ -482,6 +483,11 @@ class NewLogin extends Accounts.ui.LoginForm { return super.fields(); } + translate(text) { + // Here you specify your own translation function, e.g. + return this.props.t(text); + } + signUp(options = {}) { const { firstname = null } = this.state; if (firstname !== null) { diff --git a/imports/helpers.js b/imports/helpers.js index 53b6842..2be5fb7 100644 --- a/imports/helpers.js +++ b/imports/helpers.js @@ -64,10 +64,10 @@ export function validateEmail(email, showMessage, clearMessage) { if (Accounts.ui._options.emailPattern.test(email)) { return true; } else if (!email || email.length === 0) { - showMessage(T9n.get("error.emailRequired"), 'warning', false, 'email'); + showMessage("error.emailRequired", 'warning', false, 'email'); return false; } else { - showMessage(T9n.get("error.accounts.Invalid email"), 'warning', false, 'email'); + showMessage("error.accounts.Invalid email", 'warning', false, 'email'); return false; } } @@ -76,7 +76,8 @@ export function validatePassword(password = '', showMessage, clearMessage){ if (password.length >= Accounts.ui._options.minimumPasswordLength) { return true; } else { - const errMsg = T9n.get("error.minChar").replace(/7/, Accounts.ui._options.minimumPasswordLength); + // const errMsg = T9n.get("error.minChar").replace(/7/, Accounts.ui._options.minimumPasswordLength); + const errMsg = "error.minChar" showMessage(errMsg, 'warning', false, 'password'); return false; } @@ -87,7 +88,7 @@ export function validateUsername(username, showMessage, clearMessage, formState) return true; } else { const fieldName = (passwordSignupFields() === 'USERNAME_ONLY' || formState === STATES.SIGN_UP) ? 'username' : 'usernameOrEmail'; - showMessage(T9n.get("error.usernameRequired"), 'warning', false, fieldName); + showMessage("error.usernameRequired", 'warning', false, fieldName); return false; } } diff --git a/imports/ui/components/Button.jsx b/imports/ui/components/Button.jsx index a22198b..d2e7ee6 100644 --- a/imports/ui/components/Button.jsx +++ b/imports/ui/components/Button.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { Accounts } from 'meteor/accounts-base'; let Link; try { Link = require('react-router').Link; } catch(e) {} @@ -28,7 +29,7 @@ export class Button extends React.Component { } } Button.propTypes = { - onClick: React.PropTypes.func + onClick: PropTypes.func }; Accounts.ui.Button = Button; diff --git a/imports/ui/components/Field.jsx b/imports/ui/components/Field.jsx index 79e0076..8e1a1f6 100644 --- a/imports/ui/components/Field.jsx +++ b/imports/ui/components/Field.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { Accounts } from 'meteor/accounts-base'; export class Field extends React.Component { @@ -69,7 +70,7 @@ export class Field extends React.Component { } } Field.propTypes = { - onChange: React.PropTypes.func + onChange: PropTypes.func }; Accounts.ui.Field = Field; diff --git a/imports/ui/components/Form.jsx b/imports/ui/components/Form.jsx index a4301c0..9efe2c2 100644 --- a/imports/ui/components/Form.jsx +++ b/imports/ui/components/Form.jsx @@ -1,5 +1,6 @@ import React from 'react'; import ReactDOM from 'react-dom'; +import PropTypes from 'prop-types'; import { Accounts } from 'meteor/accounts-base'; import './Fields.jsx'; import './Buttons.jsx'; @@ -26,9 +27,11 @@ export class Form extends React.Component { buttons, error, messages, + translate, ready = true, className } = this.props; + console.log(this.props); return (
this.form = ref} @@ -38,7 +41,7 @@ export class Form extends React.Component { > - + @@ -46,11 +49,12 @@ export class Form extends React.Component { } } Form.propTypes = { - oauthServices: React.PropTypes.object, - fields: React.PropTypes.object.isRequired, - buttons: React.PropTypes.object.isRequired, - error: React.PropTypes.string, - ready: React.PropTypes.bool + oauthServices: PropTypes.object, + fields: PropTypes.object.isRequired, + buttons: PropTypes.object.isRequired, + translate: PropTypes.func.isRequired, + error: PropTypes.string, + ready: PropTypes.bool }; Accounts.ui.Form = Form; diff --git a/imports/ui/components/LoginForm.jsx b/imports/ui/components/LoginForm.jsx index cc51186..baba645 100644 --- a/imports/ui/components/LoginForm.jsx +++ b/imports/ui/components/LoginForm.jsx @@ -45,6 +45,7 @@ export class LoginForm extends Tracker.Component { onPreSignUpHook: props.onPreSignUpHook || Accounts.ui._options.onPreSignUpHook, onPostSignUpHook: props.onPostSignUpHook || Accounts.ui._options.onPostSignUpHook, }; + this.translate = this.translate.bind(this); } componentDidMount() { @@ -71,21 +72,21 @@ export class LoginForm extends Tracker.Component { Session.set(KEY_PREFIX + 'state', null); break; } - + // Add default field values once the form did mount on the client this.setState(prevState => ({ ...this.getDefaultFieldValues(), })); - + // Listen for the user to login/logout. this.autorun(() => { - + // Add the services list to the user. this.subscribe('servicesList'); this.setState({ user: Accounts.user() }); - + }); } @@ -106,6 +107,13 @@ export class LoginForm extends Tracker.Component { } } + translate(text) { + // if (this.props.t) { + // return this.props.t(text); + // } + return T9n.get(text); + } + validateField(field, value) { const { formState } = this.state; switch(field) { @@ -131,8 +139,8 @@ export class LoginForm extends Tracker.Component { getUsernameOrEmailField() { return { id: 'usernameOrEmail', - hint: T9n.get('enterUsernameOrEmail'), - label: T9n.get('usernameOrEmail'), + hint: this.translate('enterUsernameOrEmail'), + label: this.translate('usernameOrEmail'), required: true, defaultValue: this.state.username || "", onChange: this.handleChange.bind(this, 'usernameOrEmail'), @@ -143,8 +151,8 @@ export class LoginForm extends Tracker.Component { getUsernameField() { return { id: 'username', - hint: T9n.get('enterUsername'), - label: T9n.get('username'), + hint: this.translate('enterUsername'), + label: this.translate('username'), required: true, defaultValue: this.state.username || "", onChange: this.handleChange.bind(this, 'username'), @@ -155,8 +163,8 @@ export class LoginForm extends Tracker.Component { getEmailField() { return { id: 'email', - hint: T9n.get('enterEmail'), - label: T9n.get('email'), + hint: this.translate('enterEmail'), + label: this.translate('email'), type: 'email', required: true, defaultValue: this.state.email || "", @@ -168,8 +176,8 @@ export class LoginForm extends Tracker.Component { getPasswordField() { return { id: 'password', - hint: T9n.get('enterPassword'), - label: T9n.get('password'), + hint: this.translate('enterPassword'), + label: this.translate('password'), type: 'password', required: true, defaultValue: this.state.password || "", @@ -181,8 +189,8 @@ export class LoginForm extends Tracker.Component { getSetPasswordField() { return { id: 'newPassword', - hint: T9n.get('enterPassword'), - label: T9n.get('choosePassword'), + hint: this.translate('enterPassword'), + label: this.translate('choosePassword'), type: 'password', required: true, onChange: this.handleChange.bind(this, 'newPassword') @@ -192,8 +200,8 @@ export class LoginForm extends Tracker.Component { getNewPasswordField() { return { id: 'newPassword', - hint: T9n.get('enterNewPassword'), - label: T9n.get('newPassword'), + hint: this.translate('enterNewPassword'), + label: this.translate('newPassword'), type: 'password', required: true, onChange: this.handleChange.bind(this, 'newPassword'), @@ -315,7 +323,7 @@ export class LoginForm extends Tracker.Component { if (user && formState == STATES.PROFILE) { loginButtons.push({ id: 'signOut', - label: T9n.get('signOut'), + label: this.translate('signOut'), disabled: waiting, onClick: this.signOut.bind(this) }); @@ -324,7 +332,7 @@ export class LoginForm extends Tracker.Component { if (this.showCreateAccountLink()) { loginButtons.push({ id: 'switchToSignUp', - label: T9n.get('signUp'), + label: this.translate('signUp'), type: 'link', href: signUpPath, onClick: this.switchToSignUp.bind(this) @@ -334,7 +342,7 @@ export class LoginForm extends Tracker.Component { if (formState == STATES.SIGN_UP || formState == STATES.PASSWORD_RESET) { loginButtons.push({ id: 'switchToSignIn', - label: T9n.get('signIn'), + label: this.translate('signIn'), type: 'link', href: loginPath, onClick: this.switchToSignIn.bind(this) @@ -344,7 +352,7 @@ export class LoginForm extends Tracker.Component { if (this.showForgotPasswordLink()) { loginButtons.push({ id: 'switchToPasswordReset', - label: T9n.get('forgotPassword'), + label: this.translate('forgotPassword'), type: 'link', href: resetPasswordPath, onClick: this.switchToPasswordReset.bind(this) @@ -359,7 +367,7 @@ export class LoginForm extends Tracker.Component { && (user.services && 'password' in user.services)) { loginButtons.push({ id: 'switchToChangePassword', - label: T9n.get('changePassword'), + label: this.translate('changePassword'), type: 'link', href: changePasswordPath, onClick: this.switchToChangePassword.bind(this) @@ -369,7 +377,7 @@ export class LoginForm extends Tracker.Component { if (formState == STATES.SIGN_UP) { loginButtons.push({ id: 'signUp', - label: T9n.get('signUp'), + label: this.translate('signUp'), type: hasPasswordService() ? 'submit' : 'link', className: 'active', disabled: waiting, @@ -380,7 +388,7 @@ export class LoginForm extends Tracker.Component { if (this.showSignInLink()) { loginButtons.push({ id: 'signIn', - label: T9n.get('signIn'), + label: this.translate('signIn'), type: hasPasswordService() ? 'submit' : 'link', className: 'active', disabled: waiting, @@ -391,7 +399,7 @@ export class LoginForm extends Tracker.Component { if (formState == STATES.PASSWORD_RESET) { loginButtons.push({ id: 'emailResetLink', - label: T9n.get('resetYourPassword'), + label: this.translate('resetYourPassword'), type: 'submit', disabled: waiting, onClick: this.passwordReset.bind(this) @@ -401,7 +409,7 @@ export class LoginForm extends Tracker.Component { if (this.showPasswordChangeForm() || this.showEnrollAccountForm()) { loginButtons.push({ id: 'changePassword', - label: (this.showPasswordChangeForm() ? T9n.get('changePassword') : T9n.get('setPassword')), + label: (this.showPasswordChangeForm() ? this.translate('changePassword') : this.translate('setPassword')), type: 'submit', disabled: waiting, onClick: this.passwordChange.bind(this) @@ -410,7 +418,7 @@ export class LoginForm extends Tracker.Component { if (Accounts.user()) { loginButtons.push({ id: 'switchToSignOut', - label: T9n.get('cancel'), + label: this.translate('cancel'), type: 'link', href: profilePath, onClick: this.switchToSignOut.bind(this) @@ -418,7 +426,7 @@ export class LoginForm extends Tracker.Component { } else { loginButtons.push({ id: 'cancelResetPassword', - label: T9n.get('cancel'), + label: this.translate('cancel'), type: 'link', onClick: this.cancelResetPassword.bind(this), }); @@ -627,7 +635,7 @@ export class LoginForm extends Tracker.Component { Meteor.loginWithPassword(loginSelector, password, (error, result) => { onSubmitHook(error,formState); if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error"), 'error'); + this.showMessage(`error.accounts.${error.reason}` || "unknown_error", 'error'); } else { loginResultCallback(() => this.state.onSignedInHook()); @@ -683,10 +691,11 @@ export class LoginForm extends Tracker.Component { options.forceApprovalPrompt = Accounts.ui._options.forceApprovalPrompt[serviceName]; this.clearMessages(); + const self = this loginWithService(options, (error) => { onSubmitHook(error,formState); if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error")); + this.showMessage(`error.accounts.${error.reason}` || "unknown_error"); } else { this.setState({ formState: STATES.PROFILE }); this.clearDefaultFieldValues(); @@ -753,12 +762,12 @@ export class LoginForm extends Tracker.Component { const SignUp = function(_options) { Accounts.createUser(_options, (error) => { if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error"), 'error'); - if (T9n.get(`error.accounts.${error.reason}`)) { + this.showMessage(`error.accounts.${error.reason}` || "unknown_error", 'error'); + if (this.translate(`error.accounts.${error.reason}`)) { onSubmitHook(`error.accounts.${error.reason}`, formState); } else { - onSubmitHook("Unknown error", formState); + onSubmitHook("unknown_error", formState); } } else { @@ -804,10 +813,10 @@ export class LoginForm extends Tracker.Component { Accounts.loginWithoutPassword({ email: email }, (error) => { if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error"), 'error'); + this.showMessage(`error.accounts.${error.reason}` || "unknown_error", 'error'); } else { - this.showMessage(T9n.get("info.emailSent"), 'success', 5000); + this.showMessage(this.translate("info.emailSent"), 'success', 5000); this.clearDefaultFieldValues(); } onSubmitHook(error, formState); @@ -818,10 +827,10 @@ export class LoginForm extends Tracker.Component { Accounts.loginWithoutPassword({ email: usernameOrEmail, username: usernameOrEmail }, (error) => { if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error"), 'error'); + this.showMessage(`error.accounts.${error.reason}` || "unknown_error", 'error'); } else { - this.showMessage(T9n.get("info.emailSent"), 'success', 5000); + this.showMessage(this.translate("info.emailSent"), 'success', 5000); this.clearDefaultFieldValues(); } onSubmitHook(error, formState); @@ -830,10 +839,10 @@ export class LoginForm extends Tracker.Component { } else { let errMsg = null; if (_.contains([ "USERNAME_AND_EMAIL_NO_PASSWORD" ], passwordSignupFields())) { - errMsg = T9n.get("error.accounts.Invalid email or username"); + errMsg = this.translate("error.accounts.invalid_email"); } else { - errMsg = T9n.get("error.accounts.Invalid email"); + errMsg = this.translate("error.accounts.invalid_email"); } this.showMessage(errMsg,'warning'); onSubmitHook(errMsg, formState); @@ -858,10 +867,10 @@ export class LoginForm extends Tracker.Component { Accounts.forgotPassword({ email: email }, (error) => { if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error"), 'error'); + this.showMessage(`error.accounts.${error.reason}` || "unknown_error", 'error'); } else { - this.showMessage(T9n.get("info.emailSent"), 'success', 5000); + this.showMessage(this.translate("info.emailSent"), 'success', 5000); this.clearDefaultFieldValues(); } onSubmitHook(error, formState); @@ -891,11 +900,11 @@ export class LoginForm extends Tracker.Component { if (token) { Accounts.resetPassword(token, newPassword, (error) => { if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error"), 'error'); + this.showMessage(`error.accounts.${error.reason}` || "unknown_error", 'error'); onSubmitHook(error, formState); } else { - this.showMessage(T9n.get('info.passwordChanged'), 'success', 5000); + this.showMessage(this.translate('info.passwordChanged'), 'success', 5000); onSubmitHook(null, formState); this.setState({ formState: STATES.PROFILE }); Accounts._loginButtonsSession.set('resetPasswordToken', null); @@ -907,11 +916,11 @@ export class LoginForm extends Tracker.Component { else { Accounts.changePassword(password, newPassword, (error) => { if (error) { - this.showMessage(T9n.get(`error.accounts.${error.reason}`) || T9n.get("Unknown error"), 'error'); + this.showMessage(`error.accounts.${error.reason}` || "unknown_error", 'error'); onSubmitHook(error, formState); } else { - this.showMessage(T9n.get('info.passwordChanged'), 'success', 5000); + this.showMessage('info.passwordChanged', 'success', 5000); onSubmitHook(null, formState); this.setState({ formState: STATES.PROFILE }); this.clearDefaultFieldValues(); @@ -921,7 +930,7 @@ export class LoginForm extends Tracker.Component { } showMessage(message, type, clearTimeout, field){ - message = message.trim(); + message = this.translate(message).trim(); if (message) { this.setState(({ messages = [] }) => { messages.push({ @@ -994,6 +1003,7 @@ export class LoginForm extends Tracker.Component { buttons={this.buttons()} {...this.state} message={message} + translate={this.translate} /> ); } diff --git a/imports/ui/components/PasswordOrService.jsx b/imports/ui/components/PasswordOrService.jsx index c0cc786..b399931 100644 --- a/imports/ui/components/PasswordOrService.jsx +++ b/imports/ui/components/PasswordOrService.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import PropTypes from 'prop-types'; import { Accounts } from 'meteor/accounts-base'; import { T9n } from 'meteor/softwarerero:accounts-t9n'; import { hasPasswordService } from '../../helpers.js'; @@ -15,7 +16,7 @@ export class PasswordOrService extends React.Component { } render () { - let { className = "password-or-service", style = {} } = this.props; + let { className = "password-or-service", style = {}, translate } = this.props; let { hasPasswordService, services } = this.state; labels = services; if (services.length > 2) { @@ -25,7 +26,7 @@ export class PasswordOrService extends React.Component { if (hasPasswordService && services.length > 0) { return (
- { `${T9n.get('orUse')} ${ labels.join(' / ') }` } + { `${translate('orUse')} ${ labels.join(' / ') }` }
); } @@ -33,7 +34,7 @@ export class PasswordOrService extends React.Component { } } PasswordOrService.propTypes = { - oauthServices: React.PropTypes.object + oauthServices: PropTypes.object }; Accounts.ui.PasswordOrService = PasswordOrService; diff --git a/package.js b/package.js index cbab22e..5f4ddd8 100644 --- a/package.js +++ b/package.js @@ -1,6 +1,6 @@ Package.describe({ name: 'std:accounts-ui', - version: '1.2.20', + version: '1.2.21', summary: 'Accounts UI for React in Meteor 1.3+', git: 'https://github.com/studiointeract/accounts-ui', documentation: 'README.md'