Localization prop (experimental)
Clerk offers the ability to override the strings for all of the elements in each of the Clerk components. This allows you to provide localization for your users or change the wording to suit your brand.
@clerk/localizations
The @clerk/localizations package contains predefined localizations for the Clerk components.
Languages
Clerk currently supports the following languages with English as the default:
Usage
To get started, install the @clerk/localizations package.
npm install @clerk/localizationspnpm add @clerk/localizationsyarn add @clerk/localizationsbun add @clerk/localizationsOnce the @clerk/localizations package is installed, you can import the localizations you need by removing the "-" from the locale. You can then pass the localization to the localization prop, which is available wherever you initialize the Clerk integration. For most SDKs, this is done via the <ClerkProvider> component. For other SDKs, it's configured through the SDK's Clerk integration or plugin.
In the following example, the fr-FR locale is imported as frFR. The imported localization is then passed to the localization prop on the <ClerkProvider>.
// fr-FR locale is imported as frFR
import { frFR } from '@clerk/localizations'
<ClerkProvider localization={frFR}>
  {/* ... */}
</ClerkProvider>In the following example, the fr-FR locale is imported as frFR. The imported localization is then passed to the localization prop to the clerk() integration.
import { defineConfig } from 'astro/config'
import clerk from '@clerk/astro'
// fr-FR locale is imported as frFR
import { frFR } from '@clerk/localizations'
export default defineConfig({
  integrations: [
    clerk({
      localization: frFR,
    }),
  ],
})In the following example, the fr-FR locale is imported as frFR. The imported localization is then passed to the localization prop on the clerk.load() method.
Use the following tabs to view the code necessary for each file.
import { Clerk } from '@clerk/clerk-js'
// fr-FR locale is imported as frFR
import { frFR } from '@clerk/localizations'
const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
const clerk = new Clerk(clerkPubKey)
await clerk.load({
  localization: frFR,
})
if (clerk.isSignedIn) {
  document.getElementById('app').innerHTML = `
      <div id="user-button"></div>
    `
  const userButtonDiv = document.getElementById('user-button')
  clerk.mountUserButton(userButtonDiv)
} else {
  document.getElementById('app').innerHTML = `
      <div id="sign-in"></div>
    `
  const signInDiv = document.getElementById('sign-in')
  clerk.mountSignIn(signInDiv)
}<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Clerk + JavaScript App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="main.js" async crossorigin="anonymous"></script>
  </body>
</html>In the following example, the fr-FR locale is imported as frFR. The imported localization is then passed to the localization prop to the clerkPlugin() integration.
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
// fr-FR locale is imported as frFR
import { frFR } from '@clerk/localizations'
const app = createApp(App)
app.use(clerkPlugin, {
  localization: frFR,
})
app.mount('#app')In the following example, the fr-FR locale is imported as frFR. The imported localization is then passed to the localization prop to the defineNuxtConfig() integration.
// fr-FR locale is imported as frFR
import { frFR } from '@clerk/localizations'
export default defineNuxtConfig({
  modules: ['@clerk/nuxt'],
  clerk: {
    localization: frFR,
  },
})In the following example, the fr-FR locale is imported as frFR. The imported localization is then passed to the localization prop to the clerkPlugin() integration.
import Fastify from 'fastify'
import { clerkPlugin } from '@clerk/fastify'
// fr-FR locale is imported as frFR
import { frFR } from '@clerk/localizations'
const fastify = Fastify({ logger: true })
fastify.register(clerkPlugin, {
  localization: frFR,
})Adding or updating a localization
Clerk's localizations are customer-sourced and we encourage customers to add or update localizations. To do so, follow these steps:
- Fork the https://github.com/clerk/javascript/ repo.
- Clone it locally to edit it.
- Review Clerk's Contributing guide.
- If you are updating an existing localization locate the file in packages/localizations/src
- If you are adding a new language, copy the en-US.tsfile and name it according to your language. The naming is the abbreviated language-region. For example, for French in Canada, it would befr-CA.ts.
- Go through the file and edit the entries.
- If you are adding a new localization, add the language to the packages/localizations/src/index.tsfile.
- Commit your changes to git and push them to your fork. Create a Pull Request from your fork to Clerk's repo against the mainbranch. We will review and either approve or ask for updates.
Custom localizations
You can also provide your own localizations for the Clerk components. This is useful if you want to provide limited or quick localization for a language Clerk doesn't currently support, adjust the wording to match your brand, or customize default error messages.
First, you need to find the key for the element that you want to customize. To find the key for your translation, open up Clerk's English localization file. Search the file for the term that you want to customize.
For example, say you want to change the text of the "Continue" button on the <SignIn /> component to say "LETS GO!". In this case, you'd search for "Continue". The first result that comes up is formButtonPrimary, which is the key for the "Continue" button.
Now that you know the key, you can pass it to the localization prop and set the value to the text you want to display. In this case, you'd set the value to "LETS GO!", as shown in the following example.
For React-based SDKs, pass the localization prop to the <ClerkProvider> component.
// Set your customizations in a `localization` object
const localization = {
  formButtonPrimary: 'LETS GO!',
}
<ClerkProvider localization={localization}>
  {/* ... */}
</ClerkProvider>In Astro, pass the localization prop to the clerk() integration.
import { defineConfig } from 'astro/config'
import clerk from '@clerk/astro'
export default defineConfig({
  integrations: [
    clerk({
      localization: {
        formButtonPrimary: 'LETS GO!',
      },
    }),
  ],
})In JavaScript, pass the localization prop to the clerk.load() method.
Use the following tabs to view the code necessary for each file.
import { Clerk } from '@clerk/clerk-js'
const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
const clerk = new Clerk(clerkPubKey)
await clerk.load({
  localization: {
    formButtonPrimary: 'LETS GO!',
  },
})
if (clerk.isSignedIn) {
  document.getElementById('app').innerHTML = `
      <div id="user-button"></div>
    `
  const userButtonDiv = document.getElementById('user-button')
  clerk.mountUserButton(userButtonDiv)
} else {
  document.getElementById('app').innerHTML = `
      <div id="sign-in"></div>
    `
  const signInDiv = document.getElementById('sign-in')
  clerk.mountSignIn(signInDiv)
}<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Clerk + JavaScript App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="main.js" async crossorigin="anonymous"></script>
  </body>
</html>In Vue, pass the localization prop to the clerkPlugin() integration.
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
const app = createApp(App)
app.use(clerkPlugin, {
  localization: {
    formButtonPrimary: 'LETS GO!',
  },
})
app.mount('#app')In Nuxt, pass the localization prop to the defineNuxtConfig() integration.
export default defineNuxtConfig({
  modules: ['@clerk/nuxt'],
  clerk: {
    localization: {
      formButtonPrimary: 'LETS GO!',
    },
  },
})In Fastify, pass the localization prop to the clerkPlugin() integration.
import Fastify from 'fastify'
import { clerkPlugin } from '@clerk/fastify'
const fastify = Fastify({ logger: true })
fastify.register(clerkPlugin, {
  localization: {
    formButtonPrimary: 'LETS GO!',
  },
})You can also customize multiple entries by passing multiple keys. The following example updates the "to continue to" subtitles on the <SignUp /> component to say "to access" instead.
For React-based SDKs, pass the localization prop to the <ClerkProvider> component.
const localization = {
  signUp: {
    start: {
      subtitle: 'to access {{applicationName}}',
    },
    emailCode: {
      subtitle: 'to access {{applicationName}}',
    },
  },
}
<ClerkProvider localization={localization}>
  {/* ... */}
</ClerkProvider>In Astro, pass the localization prop to the clerk() integration.
import { defineConfig } from 'astro/config'
import clerk from '@clerk/astro'
export default defineConfig({
  integrations: [
    clerk({
      localization: {
        signUp: {
          start: {
            subtitle: 'to access {{applicationName}}',
          },
          emailCode: {
            subtitle: 'to access {{applicationName}}',
          },
        },
      },
    }),
  ],
})In JavaScript, pass the localization prop to the clerk.load() method.
Use the following tabs to view the code necessary for each file.
import { Clerk } from '@clerk/clerk-js'
const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
const clerk = new Clerk(clerkPubKey)
await clerk.load({
  localization: {
    signUp: {
      start: {
        subtitle: 'to access {{applicationName}}',
      },
      emailCode: {
        subtitle: 'to access {{applicationName}}',
      },
    },
  },
})
if (clerk.isSignedIn) {
  document.getElementById('app').innerHTML = `
      <div id="user-button"></div>
    `
  const userButtonDiv = document.getElementById('user-button')
  clerk.mountUserButton(userButtonDiv)
} else {
  document.getElementById('app').innerHTML = `
      <div id="sign-in"></div>
    `
  const signInDiv = document.getElementById('sign-in')
  clerk.mountSignIn(signInDiv)
}<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Clerk + JavaScript App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="main.js" async crossorigin="anonymous"></script>
  </body>
</html>In Vue, pass the localization prop to the clerkPlugin() integration.
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
const app = createApp(App)
app.use(clerkPlugin, {
  localization: {
    signUp: {
      start: {
        subtitle: 'to access {{applicationName}}',
      },
      emailCode: {
        subtitle: 'to access {{applicationName}}',
      },
    },
  },
})
app.mount('#app')In Nuxt, pass the localization prop to the defineNuxtConfig() integration.
export default defineNuxtConfig({
  modules: ['@clerk/nuxt'],
  clerk: {
    localization: {
      signUp: {
        start: {
          subtitle: 'to access {{applicationName}}',
        },
        emailCode: {
          subtitle: 'to access {{applicationName}}',
        },
      },
    },
  },
})In Fastify, pass the localization prop to the clerkPlugin() integration.
import Fastify from 'fastify'
import { clerkPlugin } from '@clerk/fastify'
const fastify = Fastify({ logger: true })
fastify.register(clerkPlugin, {
  localization: {
    signUp: {
      start: {
        subtitle: 'to access {{applicationName}}',
      },
      emailCode: {
        subtitle: 'to access {{applicationName}}',
      },
    },
  },
})Example: Customize error messages
You can customize Clerk's default error messages by targeting the unstable__errors key. This key lets you define specific error keys for different error types and assign them custom message strings. You can find the full list of error keys in the English localization file. Search for the unstable__errors object to find the keys you can customize.
The following example updates the not_allowed_access error message. This message appears when a user tries to sign in with an email domain that isn't allowed to access your application.
For React-based SDKs, pass the localization prop to the <ClerkProvider> component.
const localization = {
  unstable__errors: {
  not_allowed_access:
    'Send us an email if you want your corporate email domain allowlisted for access',
  },
}
<ClerkProvider localization={localization}>
  {/* ... */}
</ClerkProvider>In Astro, pass the localization prop to the clerk() integration.
import { defineConfig } from 'astro/config'
import clerk from '@clerk/astro'
export default defineConfig({
  integrations: [
    clerk({
      localization: {
        unstable__errors: {
          not_allowed_access:
            'Send us an email if you want your corporate email domain allowlisted for access',
        },
      },
    }),
  ],
})In JavaScript, pass the localization prop to the clerk.load() method.
Use the following tabs to view the code necessary for each file.
import { Clerk } from '@clerk/clerk-js'
const clerkPubKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY
const clerk = new Clerk(clerkPubKey)
await clerk.load({
  localization: {
    unstable__errors: {
      not_allowed_access:
        'Send us an email if you want your corporate email domain allowlisted for access',
    },
  },
})
if (clerk.isSignedIn) {
  document.getElementById('app').innerHTML = `
      <div id="user-button"></div>
    `
  const userButtonDiv = document.getElementById('user-button')
  clerk.mountUserButton(userButtonDiv)
} else {
  document.getElementById('app').innerHTML = `
      <div id="sign-in"></div>
    `
  const signInDiv = document.getElementById('sign-in')
  clerk.mountSignIn(signInDiv)
}<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Clerk + JavaScript App</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="main.js" async crossorigin="anonymous"></script>
  </body>
</html>In Vue, pass the localization prop to the clerkPlugin() integration.
import { createApp } from 'vue'
import App from './App.vue'
import { clerkPlugin } from '@clerk/vue'
const app = createApp(App)
app.use(clerkPlugin, {
  localization: {
    unstable__errors: {
      not_allowed_access:
        'Send us an email if you want your corporate email domain allowlisted for access',
    },
  },
})
app.mount('#app')In Nuxt, pass the localization prop to the defineNuxtConfig() integration.
export default defineNuxtConfig({
  modules: ['@clerk/nuxt'],
  clerk: {
    localization: {
      unstable__errors: {
        not_allowed_access:
          'Send us an email if you want your corporate email domain allowlisted for access',
      },
    },
  },
})In Fastify, pass the localization prop to the clerkPlugin() integration.
import Fastify from 'fastify'
import { clerkPlugin } from '@clerk/fastify'
const fastify = Fastify({ logger: true })
fastify.register(clerkPlugin, {
  localization: {
    unstable__errors: {
      not_allowed_access:
        'Send us an email if you want your corporate email domain allowlisted for access',
    },
  },
})Feedback
Last updated on