Skip to main content
Docs

Localization prop (experimental)

Warning

This feature is currently experimental and may not behave as expected. If you encounter any issues, contact support with as much detail as possible.

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:

English nameLanguage tag (BCP 47)Key
Arabic (Saudi)ar-SAarSA
Belarusbe-BYbeBY
Bengalibn-INbnIN
Bulgarianbg-BGbgBG
Catalanca-EScaES
Chinese (Simplified)zh-CNzhCN
Chinese (Traditional)zh-TWzhTW
Croatianhr-HRhrHR
Czechcs-CZcsCZ
Danishda-DKdaDK
Dutchnl-BEnlBE
Dutchnl-NLnlNL
English (GB)en-GBenGB
English (US)en-USenUS
Farsifa-IRfaIR
Finnishfi-FIfiFI
Frenchfr-FRfrFR
Germande-DEdeDE
Greekel-GRelGR
Hebrewhe-ILheIL
Hindihi-INhiIN
Hungarianhu-HUhuHU
Icelandicis-ISisIS
Italianit-ITitIT
Indonesianid-IDidID
Japaneseja-JPjaJP
Kazakhkk-KZkkKZ
Koreanko-KRkoKR
Malayms-MYmsMY
Mongolianmn-MNmnMN
Norwegiannb-NOnbNO
Polishpl-PLplPL
Portuguese (BR)pt-BRptBR
Portuguese (PT)pt-PTptPT
Romanianro-ROroRO
Russianru-RUruRU
Serbiansr-RSsrRS
Slovaksk-SKskSK
Spanishes-ESesES
Spanish (Costa Rica)es-CResCR
Spanish (Mexico)es-MXesMX
Spanish (Uruguay)es-UYesUY
Swedishsv-SEsvSE
Tamilta-INtaIN
Telugute-INteIN
Thaith-THthTH
Turkishtr-TRtrTR
Ukrainianuk-UAukUA
Vietnamesevi-VNviVN

Usage

Caution

The localizations will only update the text in the Clerk components used in your application. The hosted Clerk Account Portal will remain in English.

To get started, install the @clerk/localizations package.

terminal
npm install @clerk/localizations
terminal
pnpm add @clerk/localizations
terminal
yarn add @clerk/localizations
terminal
bun add @clerk/localizations

Once 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()Astro Icon integration.

astro.config.mjs
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()JavaScript Icon method.

Use the following tabs to view the code necessary for each file.

main.js
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)
}
index.html
<!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()Vue.js Icon integration.

src/main.ts
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()Nuxt.js Icon integration.

nuxt.config.ts
// 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()Fastify Icon integration.

server.ts
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:

  1. Fork the https://github.com/clerk/javascript/ repo.
  2. Clone it locally to edit it.
  3. Review Clerk's Contributing guide.
  4. If you are updating an existing localization locate the file in packages/localizations/src
  5. If you are adding a new language, copy the en-US.ts file and name it according to your language. The naming is the abbreviated language-region. For example, for French in Canada, it would be fr-CA.ts.
  6. Go through the file and edit the entries.
  7. If you are adding a new localization, add the language to the packages/localizations/src/index.ts file.
  8. Commit your changes to git and push them to your fork. Create a Pull Request from your fork to Clerk's repo against the main branch. 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()Astro Icon integration.

astro.config.mjs
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()JavaScript Icon method.

Use the following tabs to view the code necessary for each file.

main.js
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)
}
index.html
<!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()Vue.js Icon integration.

src/main.ts
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()Nuxt.js Icon integration.

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@clerk/nuxt'],
  clerk: {
    localization: {
      formButtonPrimary: 'LETS GO!',
    },
  },
})

In Fastify, pass the localization prop to the clerkPlugin()Fastify Icon integration.

server.ts
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()Astro Icon integration.

astro.config.mjs
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()JavaScript Icon method.

Use the following tabs to view the code necessary for each file.

main.js
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)
}
index.html
<!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()Vue.js Icon integration.

src/main.ts
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()Nuxt.js Icon integration.

nuxt.config.ts
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()Fastify Icon integration.

server.ts
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()Astro Icon integration.

astro.config.mjs
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()JavaScript Icon method.

Use the following tabs to view the code necessary for each file.

main.js
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)
}
index.html
<!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()Vue.js Icon integration.

src/main.ts
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()Nuxt.js Icon integration.

nuxt.config.ts
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()Fastify Icon integration.

server.ts
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

What did you think of this content?

Last updated on