Skip to content

Commit

Permalink
feat: support i18n (ory#130)
Browse files Browse the repository at this point in the history
* chore: fix types and deprecation warnings

* feat: localize messages

* feat: generate Kratos messages

* chore: format

* chore: finish up MVP

* feat: add es,de and make storybook work

* chore: format

* fix: make user auth card title optional

* feat: add user settings screen

* autogen: update english locales

* WIP

* fix: build error

* fix: use IntlProvider in examples

* chore: update translations

* chore: move delete style to translations

* fix: translation error due to duplicate code

* fix: space between text & link
  • Loading branch information
zepatrik authored Aug 30, 2023
1 parent 85546a1 commit e3eac67
Show file tree
Hide file tree
Showing 76 changed files with 4,052 additions and 540 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@ module.exports = {
jsx: true,
},
},
plugins: ["react", "@typescript-eslint", "eslint-plugin-tsdoc"],
plugins: ["react", "@typescript-eslint", "eslint-plugin-tsdoc", "formatjs"],
rules: {
"tsdoc/syntax": "warn",
"formatjs/no-offset": "error",
},
}
3 changes: 3 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@ public
storybook-static
.github/pull_request_template.md
CONTRIBUTING.md
docs
.next
.cache
33 changes: 30 additions & 3 deletions .storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { ThemeProvider } from "@ory/elements"
import { ThemeProvider, IntlProvider, locales } from "@ory/elements"
import { StoryFn } from "@storybook/react"

import "@ory/elements/assets/normalize.css"

import "@ory/elements/assets/fa-brands.min.css"
Expand All @@ -23,9 +25,28 @@ export const globalTypes = {
name: true,
},
},
locale: {
name: "Locale",
defaultValue: "en",
toolbar: {
icon: "globe",
items: Object.keys(locales).map((locale) => ({
value: locale,
icon: "globe",
title: locale,
})),
},
},
}

export const withTheme = (StoryFn, context) => {
type Context = {
globals: {
theme: "light" | "dark"
locale: keyof typeof locales
}
}

export const withTheme = (StoryFn: StoryFn, context: Context) => {
const theme = context.globals.theme
return (
<ThemeProvider theme={theme} enableFontSmoothing={true}>
Expand All @@ -34,4 +55,10 @@ export const withTheme = (StoryFn, context) => {
)
}

export const decorators = [withTheme]
export const withIntl = (StoryFn: StoryFn, context: Context) => (
<IntlProvider locale={context.globals.locale}>
<StoryFn />
</IntlProvider>
)

export const decorators = [withTheme, withIntl]
100 changes: 51 additions & 49 deletions examples/nextjs-spa/src/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Nav, ThemeProvider } from "@ory/elements"
import { IntlProvider, Nav, ThemeProvider } from "@ory/elements"
import Head from "next/head"

interface LayoutProps {
Expand All @@ -8,55 +8,57 @@ interface LayoutProps {
export default function Layout({ children }: LayoutProps) {
return (
<ThemeProvider themeOverrides={{}}>
<Head>
<title>Next.js w/ Elements</title>
<link rel="icon" href="/ory.svg" />
</Head>
<div className="mainContainer">
{/* An Ory Elements dynamic nav component */}
<Nav
className="main-nav"
navTitle="Next.js w/ Elements"
navSections={[
{
title: "Navigation",
links: [
{
name: "Home",
href: "/",
},
{
name: "Login",
href: "/login",
},
{
name: "Register",
href: "/registration",
},
{
name: "Settings",
href: "/settings",
},
{
name: "Verification",
href: "/verification",
},
{
name: "Recovery",
href: "/recovery",
},
{
name: "Logout",
href: "/logout",
},
],
},
]}
/>
<div className="contentContainer">
<div className="content">{children}</div>
<IntlProvider>
<Head>
<title>Next.js w/ Elements</title>
<link rel="icon" href="/ory.svg" />
</Head>
<div className="mainContainer">
{/* An Ory Elements dynamic nav component */}
<Nav
className="main-nav"
navTitle="Next.js w/ Elements"
navSections={[
{
title: "Navigation",
links: [
{
name: "Home",
href: "/",
},
{
name: "Login",
href: "/login",
},
{
name: "Register",
href: "/registration",
},
{
name: "Settings",
href: "/settings",
},
{
name: "Verification",
href: "/verification",
},
{
name: "Recovery",
href: "/recovery",
},
{
name: "Logout",
href: "/logout",
},
],
},
]}
/>
<div className="contentContainer">
<div className="content">{children}</div>
</div>
</div>
</div>
</IntlProvider>
</ThemeProvider>
)
}
1 change: 0 additions & 1 deletion examples/nextjs-spa/src/pages/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ const Login: NextPageWithLayout = () => {
// create a login form that dynamically renders based on the flow data using Ory Elements
<UserAuthCard
cardImage="/ory.svg"
title={"Login"}
// This defines what kind of card we want to render.
flowType={"login"}
// we always need the flow data which populates the form fields and error messages dynamically
Expand Down
1 change: 0 additions & 1 deletion examples/nextjs-spa/src/pages/recovery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ const Recovery: NextPageWithLayout = () => {
// create a recovery form that dynamically renders based on the flow data using Ory Elements
<UserAuthCard
cardImage="/ory.svg"
title={"Recovery"}
// This defines what kind of card we want to render.
flowType={"recovery"}
// we always need the flow data which populates the form fields and error messages dynamically
Expand Down
1 change: 0 additions & 1 deletion examples/nextjs-spa/src/pages/verification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ const Verification: NextPageWithLayout = () => {
// create a verification form that dynamically renders based on the flow data using Ory Elements
<UserAuthCard
cardImage="/ory.svg"
title={"Verification"}
flowType={"verification"}
// we always need the flow data which populates the form fields and error messages dynamically
flow={flow}
Expand Down
2 changes: 1 addition & 1 deletion examples/preact-spa/src/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useLocation } from "wouter"
export const Login = () => {
const [flow, setFlow] = useState<LoginFlow | null>(null)

const [location, setLocation] = useLocation()
const [, setLocation] = useLocation()

// Get the flow based on the flowId in the URL (.e.g redirect to this page after flow initialized)
const getFlow = useCallback(
Expand Down
22 changes: 12 additions & 10 deletions examples/preact-spa/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Recovery } from "./recovery"
import { Register } from "./register"
import { Settings } from "./settings"
import { Verification } from "./verification"
import { IntlProvider, ThemeProvider } from "@ory/elements-preact"

// Ory Elements
// optional fontawesome icons
Expand All @@ -23,21 +24,22 @@ import "@ory/elements-preact/assets/inter-font.css"
import "@ory/elements-preact/assets/jetbrains-mono-font.css"

// required styles for Ory Elements
import { ThemeProvider } from "@ory/elements-preact"
import "@ory/elements-preact/style.css"

const Main = () => {
return (
<ThemeProvider>
<Router>
<Route path="/" component={Dashboard} />
<Route path="/login" component={Login} />
<Route path="/registration" component={Register} />
<Route path="/verification" component={Verification} />
<Route path="/recovery" component={Recovery} />
<Route path="/settings" component={Settings} />
<Route path="/error" component={Error} />
</Router>
<IntlProvider>
<Router>
<Route path="/" component={Dashboard} />
<Route path="/login" component={Login} />
<Route path="/registration" component={Register} />
<Route path="/verification" component={Verification} />
<Route path="/recovery" component={Recovery} />
<Route path="/settings" component={Settings} />
<Route path="/error" component={Error} />
</Router>
</IntlProvider>
</ThemeProvider>
)
}
Expand Down
2 changes: 1 addition & 1 deletion examples/preact-spa/src/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { SettingsFlow, UpdateSettingsFlowBody } from "@ory/client"
export const Settings = () => {
const [flow, setFlow] = useState<SettingsFlow | null>(null)

const [location, setLocation] = useLocation()
const [, setLocation] = useLocation()

// Get the flow based on the flowId in the URL (.e.g redirect to this page after flow initialized)
const getFlow = useCallback(
Expand Down
2 changes: 1 addition & 1 deletion examples/preact-spa/src/verification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const Verification = () => {
flow={flow}
flowType={"verification"}
additionalProps={{
loginURL: "/login",
signupURL: "/registration",
}}
title="Verification"
// submit the verification form data to Ory
Expand Down
3 changes: 1 addition & 2 deletions examples/react-spa/src/Verification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,12 @@ export const Verification = (): JSX.Element => {
return flow ? (
// create a new verification form with the flow data using Ory Elements
<UserAuthCard
title="Verification"
flowType={"verification"}
// we always need to provide the flow data since it contains the form fields, error messages and csrf token
flow={flow}
// we want users to be able to go back to the login page from the verification page
additionalProps={{
loginURL: "/login",
signupURL: "/registration",
}}
// submit the verification form data to Ory
onSubmit={({ body }) => submitFlow(body as UpdateVerificationFlowBody)}
Expand Down
22 changes: 12 additions & 10 deletions examples/react-spa/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ThemeProvider } from "@ory/elements"
import { ThemeProvider, IntlProvider } from "@ory/elements"

// optional global css reset
import "@ory/elements/assets/normalize.css"
Expand Down Expand Up @@ -33,15 +33,17 @@ ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<BrowserRouter>
{/* We add the Ory themes here */}
<ThemeProvider themeOverrides={{}}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/login" element={<Login />} />
<Route path="/registration" element={<Registration />} />
<Route path="/verification" element={<Verification />} />
<Route path="/recovery" element={<Recovery />} />
<Route path="/settings" element={<Settings />} />
<Route path="/error" element={<Error />} />
</Routes>
<IntlProvider>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/login" element={<Login />} />
<Route path="/registration" element={<Registration />} />
<Route path="/verification" element={<Verification />} />
<Route path="/recovery" element={<Recovery />} />
<Route path="/settings" element={<Settings />} />
<Route path="/error" element={<Error />} />
</Routes>
</IntlProvider>
</ThemeProvider>
</BrowserRouter>
</React.StrictMode>,
Expand Down
Loading

0 comments on commit e3eac67

Please sign in to comment.