Skip to content

feat: add multilingual support #238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
"env": {
"browser": true,
"node": true,
"es6": true
"es6": true,
"jest": true
},
"settings": {
"react": {
Expand Down
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,12 @@ netlifyIdentity.close();

// Log out the user
netlifyIdentity.logout();
// refresh the user's JWT
// refresh the user's JWT
// Note: this method returns a promise.
netlifyIdentity.refresh().then((jwt)=>console.log(jwt))

// Change language
netlifyIdentity.setLocale('en');
```

#### A note on script tag versioning
Expand All @@ -86,7 +89,7 @@ and will only reflect breaking changes in the markup API.
Netlify Identity Widget also has a
[module API](https://www.npmjs.com/package/netlify-identity-widget):

```
```bash
yarn add netlify-identity-widget
```

Expand All @@ -97,6 +100,7 @@ const netlifyIdentity = require('netlify-identity-widget');

netlifyIdentity.init({
container: '#netlify-modal' // defaults to document.body,
locale: 'en' // defaults to 'en'
});

netlifyIdentity.open(); // open the modal
Expand All @@ -116,10 +120,13 @@ netlifyIdentity.close();
// Log out the user
netlifyIdentity.logout();

// refresh the user's JWT
// refresh the user's JWT
// Note: this method returns a promise.
netlifyIdentity.refresh().then((jwt)=>console.log(jwt))

// Change language
netlifyIdentity.setLocale('en');

// Access the underlying GoTrue JS client.
// Note that doing things directly through the GoTrue client brings a risk of getting out of
// sync between your state and the widget’s state.
Expand All @@ -136,6 +143,7 @@ module API. Options include:
container: '#some-query-selector'; // container to attach to
APIUrl: 'https://www.example.com/.netlify/functions/identity'; // Absolute url to endpoint. ONLY USE IN SPECIAL CASES!
namePlaceholder: 'some-placeholder-for-Name'; // custom placeholder for name input form
locale: 'en'; // language code for translations - available: en, fr - default to en
}
```

Expand All @@ -162,7 +170,6 @@ https://olddvdscreensaver.com

![](devmode.png)


## List of Alternatives

**Lowest level JS Library**: If you want to use the official Javascript bindings to GoTrue, Netlify's underlying Identity service written in Go, use https://github.com/netlify/gotrue-js
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"dependencies": {},
"devDependencies": {
"@babel/cli": "^7.10.1",
"@babel/register": "^7.10.1",
"@babel/core": "^7.10.2",
"@babel/plugin-proposal-class-properties": "^7.10.1",
"@babel/plugin-proposal-decorators": "^7.10.1",
Expand All @@ -18,6 +17,7 @@
"@babel/plugin-transform-react-jsx": "^7.10.1",
"@babel/polyfill": "^7.10.1",
"@babel/preset-env": "^7.10.2",
"@babel/register": "^7.10.1",
"auto-changelog": "^2.0.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26.0.1",
Expand All @@ -34,6 +34,7 @@
"gh-release": "^3.4.0",
"gotrue-js": "^0.9.21",
"html-webpack-plugin": "^4.3.0",
"jest": "^26.0.1",
"mkdirp": "^0.5.1",
"mobx": "^3.2.2",
"mobx-preact": "^1.1.0",
Expand Down Expand Up @@ -79,7 +80,9 @@
"react-demo": "cd example && yarn && yarn start",
"release": "node ./script/release.js",
"lint": "eslint src",
"test": "run-s lint format-check",
"test": "run-s lint format-check test:unit",
"test:unit": "jest",
"test:unit:watch": "jest --watch",
"version": "run-s release changelog"
}
}
44 changes: 25 additions & 19 deletions src/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,48 @@ const pagesWithHeader = { login: true, signup: true };
const pages = {
login: {
login: true,
button: "Log in",
button_saving: "Logging in",
button: "log_in",
button_saving: "logging_in",
email: true,
password: true,
link: "amnesia",
link_text: "Forgot password?",
link_text: "forgot_password",
providers: true
},
signup: {
signup: true,
button: "Sign up",
button_saving: "Signing Up",
button: "sign_up",
button_saving: "signing_up",
name: true,
email: true,
password: true,
providers: true
},
amnesia: {
title: "Recover password",
button: "Send recovery email",
button_saving: "Sending recovery email",
title: "recover_password",
button: "send_recovery_email",
button_saving: "sending_recovery_email",
email: true,
link: "login",
link_text: "Never mind"
link_text: "never_mind"
},
recovery: {
title: "Recover password",
button: "Update password",
button_saving: "Updating password",
title: "recover_password",
button: "update_password",
button_saving: "updating_password",
password: true,
link: "login",
link_text: "Never mind"
link_text: "never_mind"
},
invite: {
title: "Complete your signup",
button: "Sign up",
button_saving: "Signing Up",
title: "complete_your_signup",
button: "sign_up",
button_saving: "signing_up",
password: true,
providers: true
},
user: {
title: "Logged in"
title: "logged_in"
}
};

Expand Down Expand Up @@ -96,6 +96,7 @@ class App extends Component {
<SiteURLForm
devMode={store.siteURL != null}
onSiteURL={store.siteURL ? this.clearSiteURL : this.handleSiteURL}
t={store.translate}
/>
);
}
Expand All @@ -108,11 +109,12 @@ class App extends Component {
user={store.user}
saving={store.saving}
onLogout={this.handleLogout}
t={store.translate}
/>
);
}
if (store.modal.page === "signup" && store.settings.disable_signup) {
return <Message type="signup_disabled" />;
return <Message type="signup_disabled" t={store.translate} />;
}

return (
Expand All @@ -123,19 +125,21 @@ class App extends Component {
saving={store.saving}
onSubmit={this.handleUser}
namePlaceholder={store.namePlaceholder}
t={store.translate}
/>
{!store.user && page.link && store.gotrue && (
<button
onclick={pageLinkHandler}
className="btnLink forgotPasswordLink"
>
{page.link_text}
{store.translate(page.link_text)}
</button>
)}
{store.isLocal ? (
<SiteURLForm
devMode={store.siteURL != null}
onSiteURL={store.siteURL ? this.clearSiteURL : this.handleSiteURL}
t={store.translate}
/>
) : (
<div />
Expand Down Expand Up @@ -172,6 +176,7 @@ class App extends Component {
providers={providers}
labels={store.settings.external_labels || {}}
onLogin={this.handleExternalLogin}
t={store.translate}
/>
) : null;
}
Expand All @@ -195,6 +200,7 @@ class App extends Component {
onPage={this.handlePage}
onClose={this.handleClose}
logo={store.modal.logo}
t={store.translate}
>
{this.renderBody()}
{this.renderProviders()}
Expand Down
12 changes: 6 additions & 6 deletions src/components/controls.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class Controls extends Component {
};

render() {
const { user } = this.props.store;
const { user, translate: t } = this.props.store;

if (this.props.mode === "button") {
return (
Expand All @@ -33,7 +33,7 @@ class Controls extends Component {
href="#"
onClick={this.handleButton}
>
{this.props.text || (user ? "Log out" : "Log in")}
{this.props.text || (user ? t("log_out") : t("log_in"))}
</a>
);
}
Expand All @@ -42,7 +42,7 @@ class Controls extends Component {
return (
<ul className="netlify-identity-menu">
<li className="netlify-identity-item netlify-identity-user-details">
Logged in as{" "}
{t("logged_in_as")}{" "}
<span className="netlify-identity-user">
{user.user_metadata.name || user.email}
</span>
Expand All @@ -53,7 +53,7 @@ class Controls extends Component {
href="#"
onClick={this.handleLogout}
>
Log out
{t("log_out")}
</a>
</li>
</ul>
Expand All @@ -68,7 +68,7 @@ class Controls extends Component {
href="#"
onClick={this.handleSignup}
>
Sign up
{t("sign_up")}
</a>
</li>
<li className="netlify-identity-item">
Expand All @@ -77,7 +77,7 @@ class Controls extends Component {
href="#"
onClick={this.handleLogin}
>
Log in
{t("log_in")}
</a>
</li>
</ul>
Expand Down
10 changes: 7 additions & 3 deletions src/components/forms/logout.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,26 @@ export default class LogoutForm extends Component {
this.props.onLogout();
};
render() {
const { user, saving } = this.props;
const { user, saving, t } = this.props;

return (
<form
onSubmit={this.handleLogout}
className={`form ${saving ? "disabled" : ""}`}
>
<p className="infoText">
Logged in as <br />
{t("logged_in_as")} <br />
<span className="infoTextEmail">
{user.user_metadata.full_name ||
user.user_metadata.name ||
user.email}
</span>
</p>
<Button saving={saving} text="Log out" saving_text="Logging out" />
<Button
saving={saving}
text={t("log_out")}
saving_text={t("logging_out")}
/>
</form>
);
}
Expand Down
18 changes: 7 additions & 11 deletions src/components/forms/message.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,34 @@ import { h, Component } from "preact";
const messages = {
confirm: {
type: "success",
text:
"A confirmation message was sent to your email, click the link there to continue."
text: "message_confirm"
},
password_mail: {
type: "success",
text:
"We've sent a recovery email to your account, follow the link there to reset your password."
text: "message_password_mail"
},
email_changed: {
type: "sucess",
text: "Your email address has been updated!"
text: "message_email_changed"
},
verfication_error: {
type: "error",
text:
"There was an error verifying your account. Please try again or contact an administrator."
text: "message_verfication_error"
},
signup_disabled: {
type: "error",
text:
"Public signups are disabled. Contact an administrator and ask for an invite."
text: "message_signup_disabled"
}
};

export default class Message extends Component {
render() {
const { type } = this.props;
const { type, t } = this.props;
const msg = messages[type];

return (
<div className={`flashMessage ${msg.type}`}>
<span>{msg.text}</span>
<span>{t(msg.text)}</span>
</div>
);
}
Expand Down
7 changes: 4 additions & 3 deletions src/components/forms/providers.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ class Provider extends Component {
};

render() {
const { provider, label } = this.props;
const { provider, label, t } = this.props;

return (
<button
onClick={this.handleLogin}
className={`provider${provider} btn btnProvider`}
>
Continue with {label}
{`${t("continue_with")} ${label}`}
</button>
);
}
Expand All @@ -30,7 +30,7 @@ export default class Providers extends Component {
}

render() {
const { providers, onLogin } = this.props;
const { providers, onLogin, t } = this.props;

return (
<div className="providersGroup">
Expand All @@ -41,6 +41,7 @@ export default class Providers extends Component {
provider={p}
label={this.getLabel(p)}
onLogin={onLogin}
t={t}
/>
))}
</div>
Expand Down
Loading