Skip to content

Commit

Permalink
feat: allow custom languages in IntlProvider
Browse files Browse the repository at this point in the history
  • Loading branch information
Benehiko committed Oct 10, 2023
1 parent 880456c commit ec3d744
Show file tree
Hide file tree
Showing 8 changed files with 386 additions and 25 deletions.
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,59 @@ have explicitly told our React app to use through the `VITE_ORY_SDK_URL` export.
Now you can see Ory Elements in action by opening <http://localhost:3000> in
your browser!

## Adding Translations

Ory Elements supports translations out-of-the-box with the `IntlProvider`. The
`IntlProvider` is required by Ory Elements so that the default languages can be
mapped correctly, specifically English.

The `IntlProvider` has the ability to accept custom translations through a
`CustomLanguageFormats` object. You can specify to the `<IntlProvider>` that you
would like to use a `CustomTranslations` type instead of the
`SupportedLanguages` which will require providing the `customTranslations` prop.

When providing a language, it is important to note that it will be merged with
an existing supported language, with your provided values taking precedent. This
is to reduce the work needed to get up and running and provide the ability to
just modify one key from an already supported language, rather than modifying
the entire translation file :)

For example, I want to adjust the English translation to say `Email` instead of
`ID` when a Login card is shown. So I provide the key-value pair
`"identities.messages.1070004": "Email"`. By Default this value is `ID`. Ory
Elements will now use the updated value `Email` instead of `ID` for this
specific label, but will still keep the other defaults in-tact.

Another scenario is when we add partial keys to an unsupported language such as
`af` (Afrikaans). I add my key-value only for one entry
`"identities.messages.1070004": "E-posadres"`, however, the language has no
default inside Ory Elements. As a safe-guard we fall-back to English for the
rest of the labels.

```tsx
import { ThemeProvider, IntlProvider, CustomTranslations } from "@ory/elements"

const RootComponent = () => {
const myCustomTranslations: CustomLanguageFormats = {
en: {
"login.title": "Login",
},
}

return (
<ThemeProvider>
<IntlProvider<CustomTranslations>
customTranslations={myCustomTranslations}
locale="en"
defaultLocale="en"
>
// children
</IntlProvider>
</ThemeProvider>
)
}
```

## End-to-end Testing with Playwright

Ory Elements provides an end-to-end library based on
Expand Down
43 changes: 41 additions & 2 deletions examples/nextjs-spa/src/components/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,53 @@
import { IntlProvider, Nav, ThemeProvider } from "@ory/elements"
import {
CustomLanguageFormats,
CustomTranslations,
IntlProvider,
Nav,
ThemeProvider,
} from "@ory/elements"
import Head from "next/head"

interface LayoutProps {
children: React.ReactNode
}

export default function Layout({ children }: LayoutProps) {
// adds custom translations labels to the default translations
// this merges the custom translations with the default translations
// if a custom language is provided, but no standard translation
// exists, the english translation will be merged instead for missing values.
//
// For example, if you provide a custom translation for the "login.title" label
// in the "af" language (Afrikaans), but no standard translation exists for "af",
// the english translation will be used for the remaining labels.
//
// You can also contribute your custom translations to the Ory Elements project
// by submitting a pull request to the following repository:
// https://github.com/ory/elements
const customTranslations: CustomLanguageFormats = {
en: {
"login.title": "Login",
"identities.messages.1070004": "Email",
},
nl: {
"login.title": "Inloggen",
"identities.messages.1070004": "E-mail",
},
af: {
"login.title": "Meld aan",
"identities.messages.1070004": "E-posadres",
},
}
return (
<ThemeProvider themeOverrides={{}}>
<IntlProvider>
{/* We dont need to pass any custom translations */}
{/* <IntlProvider> */}
{/* We pass custom translations */}
<IntlProvider<CustomTranslations>
customTranslations={customTranslations}
locale="af"
defaultLocale="en"
>
<Head>
<title>Next.js w/ Elements</title>
<link rel="icon" href="/ory.svg" />
Expand Down
42 changes: 40 additions & 2 deletions examples/preact-spa/src/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import { Recovery } from "./recovery"
import { Register } from "./register"
import { Settings } from "./settings"
import { Verification } from "./verification"
import { IntlProvider, ThemeProvider } from "@ory/elements-preact"
import {
CustomLanguageFormats,
CustomTranslations,
IntlProvider,
ThemeProvider,
} from "@ory/elements-preact"

// Ory Elements
// optional fontawesome icons
Expand All @@ -27,9 +32,42 @@ import "@ory/elements-preact/assets/jetbrains-mono-font.css"
import "@ory/elements-preact/style.css"

const Main = () => {
// adds custom translations labels to the default translations
// this merges the custom translations with the default translations
// if a custom language is provided, but no standard translation
// exists, the english translation will be merged instead for missing values.
//
// For example, if you provide a custom translation for the "login.title" label
// in the "af" language (Afrikaans), but no standard translation exists for "af",
// the english translation will be used for the remaining labels.
//
// You can also contribute your custom translations to the Ory Elements project
// by submitting a pull request to the following repository:
// https://github.com/ory/elements
const customTranslations: CustomLanguageFormats = {
en: {
"login.title": "Login",
"identities.messages.1070004": "Email",
},
nl: {
"login.title": "Inloggen",
"identities.messages.1070004": "E-mail",
},
af: {
"login.title": "Meld aan",
"identities.messages.1070004": "E-posadres",
},
}
return (
<ThemeProvider>
<IntlProvider>
{/* We dont need to pass any custom translations */}
{/* <IntlProvider> */}
{/* We pass custom translations */}
<IntlProvider<CustomTranslations>
customTranslations={customTranslations}
locale="af"
defaultLocale="en"
>
<Router>
<Route path="/" component={Dashboard} />
<Route path="/login" component={Login} />
Expand Down
1 change: 0 additions & 1 deletion examples/react-spa/src/Login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,6 @@ export const Login = (): JSX.Element => {
return flow ? (
// we render the login form using Ory Elements
<UserAuthCard
title={"Login"}
flowType={"login"}
// we always need the flow data which populates the form fields and error messages dynamically
flow={flow}
Expand Down
1 change: 0 additions & 1 deletion examples/react-spa/src/Recovery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ export const Recovery = () => {
return flow ? (
// We create a dynamic Recovery form based on the flow using Ory Elements
<UserAuthCard
title="Recovery"
flowType={"recovery"}
// the flow is always required since it contains the UI form elements, UI error messages and csrf token
flow={flow}
Expand Down
1 change: 0 additions & 1 deletion examples/react-spa/src/Registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export const Registration = () => {
return flow ? (
// create a registration form that dynamically renders based on the flow data using Ory Elements
<UserAuthCard
title={"Registration"}
flowType={"registration"}
// we always need to pass the flow to the card since it contains the form fields, error messages and csrf token
flow={flow}
Expand Down
43 changes: 41 additions & 2 deletions examples/react-spa/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { ThemeProvider, IntlProvider } from "@ory/elements"
import {
ThemeProvider,
IntlProvider,
CustomTranslations,
CustomLanguageFormats,
} from "@ory/elements"

// optional global css reset
import "@ory/elements/assets/normalize.css"
Expand Down Expand Up @@ -28,12 +33,46 @@ import "@ory/elements/assets/jetbrains-mono-font.css"
// required styles for Ory Elements
import "@ory/elements/style.css"

// adds custom translations labels to the default translations
// this merges the custom translations with the default translations
// if a custom language is provided, but no standard translation
// exists, the english translation will be merged instead for missing values.
//
// For example, if you provide a custom translation for the "login.title" label
// in the "af" language (Afrikaans), but no standard translation exists for "af",
// the english translation will be used for the remaining labels.
//
// You can also contribute your custom translations to the Ory Elements project
// by submitting a pull request to the following repository:
// https://github.com/ory/elements
const customTranslations: CustomLanguageFormats = {
en: {
"login.title": "Login",
"identities.messages.1070004": "Email",
},
nl: {
"login.title": "Inloggen",
"identities.messages.1070004": "E-mail",
},
af: {
"login.title": "Meld aan",
"identities.messages.1070004": "E-posadres",
},
}

ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
<React.StrictMode>
<BrowserRouter>
{/* We add the Ory themes here */}
<ThemeProvider themeOverrides={{}}>
<IntlProvider>
{/* We dont need to pass any custom translations */}
{/* <IntlProvider> */}
{/* We pass custom translations */}
<IntlProvider<CustomTranslations>
locale="af"
defaultLocale="en"
customTranslations={customTranslations}
>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/login" element={<Login />} />
Expand Down
Loading

0 comments on commit ec3d744

Please sign in to comment.