---
title: Localization
description: "\"Shows how to use localization packs to support multiple languages with the PingOne Recognize Web SDK.\""
component: recognize
page_id: recognize:web-sdk:web-sdk-reference-localization
canonical_url: https://docs.pingidentity.com/recognize/web-sdk/web-sdk-reference-localization.html
llms_txt: https://docs.pingidentity.com/recognize/llms.txt
docs_for_agents: https://developer.pingidentity.com/build-with-ai/docs-for-agents.md
section_ids:
  component-attributes: Component attributes
  localizationpack-interface: LocalizationPack interface
  default-english-language-pack: Default English language pack
  example-customizing-instruction-heading: "Example: Customizing instruction heading"
---

# Localization

The text in PingOne Recognize Web SDK components can be localized to other languages.

Use the `lang` attribute to set the default language of a Web SDK component.

## Component attributes

The `<kl-auth>`, `<kl-auth-dialog>`, `<kl-enroll>`, and `<kl-enroll-dialog>` components each support two attributes that help manage localization:

|                                                   |                                 |                                                                                                                                                                                             |
| ------------------------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Attribute**                                     | **Type**                        | **Description**                                                                                                                                                                             |
| `localization-packs`, `localizationPacks`         | `LocalizationPack[]`            | Pass an array of localization packs to this attribute. If a localization pack uses a language that already exists, the new values replace values defined in the existing localization pack. |
| `localization-variables`, `localizationVariables` | `Record<number \| string, any>` | Localization variables represent dynamic values to be inserted into existing localization strings by replacing the `{variable}` with the new text.                                          |

Customize component text values using custom localization pack arrays and dynamic localization variables.

### LocalizationPack interface

A localization pack is an array of objects declared using the following types:

```javascript
interface LocalizationPack {
    data: LocalizationPackData;
    language: string;
}

interface LocalizationPackData {
    [key: string]: string | LocalizationPackData;
}
```

### Default English language pack

The following example shows the default PingOne Recognize language pack and serves as a reference for customization:

> **Collapse: Details**
>
> ```javascript
> {
>   auth: {
>     step: {
>       bootstrap: {
>         headline: 'Authentication Process',
>         text: 'Take a selfie to authenticate through Keyless on the platform.'
>       },
>       'camera-instructions': {
>         headline: 'Authentication Process',
>         text: 'Take a selfie to authenticate through Keyless on the platform.',
>         button: "All set. I'm ready"
>       },
>       'camera-permission': {
>         prompt: {
>           headline: 'Allow Camera Access',
>           text: 'We need access to your camera to authenticate you. Please allow the browser to access your camera.',
>           button: 'Continue'
>         },
>         granted: {
>           headline: 'Allow Camera Access',
>           text: 'We need access to your camera to authenticate you. Please allow the browser to access your camera.',
>           button: 'Continue'
>         },
>         denied: {
>           headline: 'Camera Access Denied',
>           text: 'Looks like you denied camera access on this website, we need access to your camera to authenticate you.\n\nPlease allow the browser to access your camera.',
>           button: 'Retry'
>         }
>       },
>       'camera-stream-boot': {
>         tip: 'Preparing your camera'
>       },
>       done: {
>         headline: 'Authentication Successful',
>         text: 'You can now proceed to the platform.'
>       },
>       error: {
>         headline: 'Something went wrong',
>         text: 'We were unable to authenticate you. {message} <code style="font-size: 12px">[{code}]</code>',
>         button: 'Retry'
>       },
>       'microphone-permission': {
>         prompt: {
>           headline: 'Allow Microphone Access',
>           text: 'We need access to your microphone to authenticate you. Please allow the browser to access your microphone.',
>           button: 'Continue'
>         },
>         granted: {
>           headline: 'Allow Microphone Access',
>           text: 'We need access to your microphone to authenticate you. Please allow the browser to access your microphone.',
>           button: 'Continue'
>         },
>         denied: {
>           headline: 'Microphone Access Denied',
>           text: 'Looks like you denied microphone access on this website, we need access to your microphone to authenticate you.\n\nPlease allow the browser to access your microphone.',
>           button: 'Retry'
>         }
>       },
>       'server-computation': {
>         headline: 'Authenticating...',
>         text: 'Your selfie was captured correctly, we are processing your photo'
>       },
>       'stm-choice': {
>         headline: 'Authentication Process',
>         text: 'Take a selfie to authenticate through Keyless on the platform.',
>         button: 'Continue on Phone',
>         secondary_button: 'Authenticate on Desktop'
>       },
>       'stm-qrcode': {
>         headline: 'Scan the QR Code',
>         text: 'Scan the QR code with your phone to continue the authentication process.',
>         button: {
>           false: 'Copy Link',
>           true: 'Copied to Clipboard'
>         }
>       }
>     }
>   },
>   camera_instructions: {
>     alignment: 'Center your face in the frame',
>     look: 'Look directly at the screen',
>     lighting: 'Ensure you are in a well-lit area',
>     accessories: 'Remove any eyewear or hats'
>   },
>   camera_select: {
>     headline: 'Select a Camera',
>     text: 'We detected more than one webcam connected to your device. Choose one for the process.'
>   },
>   camera_tip: {
>     /**
>      * Client
>      */
>     FaceAbsent: 'Show your face in the frame',
>     FaceMultiple: 'Show only one face in the frame',
>     FaceOffCenter: 'Center your face in the frame',
>     FacePartial: 'Show your full face in the frame',
>     FaceTooLarge: 'Move your face farther from the device',
>     FaceTooSmall: 'Move your face closer to the device',
>     /**
>      * Server
>      */
>     eyes_closed: 'Open your eyes',
>     face_angle_too_large: 'Look into the camera',
>     face_is_occluded: 'Remove any obstructions from your face',
>     face_missing: 'Show your face in the frame',
>     face_multiple: 'Show only one face in the frame',
>     face_partial: 'Show your full face in the frame',
>     face_too_close: 'Move your face farther from the device',
>     face_too_small: 'Move your face closer to the device',
>     image_black_and_white: 'Move in a well-lit area',
>     image_metadata_low_light: 'Move in a well-lit area',
>     no_movement_from_device: 'Pick up your device',
>     no_movement_from_subject: 'Tilt your face slightly',
>     /**
>      * Shared
>      */
>     none: 'Keep your face still'
>   },
>   enroll: {
>     step: {
>       bootstrap: {
>         headline: 'Enrollment Process',
>         text: 'Take a selfie to create an account on Keyless and easily register on the platform.'
>       },
>       'camera-instructions': {
>         headline: 'Enrollment Process',
>         text: 'Take a selfie to create an account on Keyless and easily register on the platform.',
>         button: 'Continue'
>       },
>       'camera-permission': {
>         prompt: {
>           headline: 'Allow Camera Access',
>           text: 'We need access to your camera to create your account. Please allow the browser to access your camera.',
>           button: 'Continue'
>         },
>         granted: {
>           headline: 'Allow Camera Access',
>           text: 'We need access to your camera to create your account. Please allow the browser to access your camera.',
>           button: 'Continue'
>         },
>         denied: {
>           headline: 'Camera Access Denied',
>           text: 'Looks like you denied camera access on this website, we need access to your camera to create your account.\n\nPlease allow the browser to access your camera.',
>           button: 'Retry'
>         }
>       },
>       'camera-stream-boot': {
>         tip: 'Preparing your camera'
>       },
>       done: {
>         headline: 'Account created',
>         text: 'You can now access and authenticate simply by using your face.'
>       },
>       error: {
>         headline: 'Something went wrong',
>         text: 'We were unable to create your account. {message} <code style="font-size: 12px">[{code}]</code>',
>         button: 'Retry'
>       },
>       'microphone-permission': {
>         prompt: {
>           headline: 'Allow Microphone Access',
>           text: 'We need access to your microphone to create your account. Please allow the browser to access your microphone.',
>           button: 'Continue'
>         },
>         granted: {
>           headline: 'Allow Microphone Access',
>           text: 'We need access to your microphone to create your account. Please allow the browser to access your microphone.',
>           button: 'Continue'
>         },
>         denied: {
>           headline: 'Microphone Access Denied',
>           text: 'Looks like you denied microphone access on this website, we need access to your microphone to create your account.\n\nPlease allow the browser to access your microphone.',
>           button: 'Retry'
>         }
>       },
>       'server-computation': {
>         headline: 'Crafting your private key',
>         text: 'Hold on, it will just take a moment'
>       },
>       'stm-choice': {
>         headline: 'Enrollment Process',
>         text: 'Take a selfie to create an account on Keyless and easily register on the platform.',
>         button: 'Continue on Phone',
>         secondary_button: 'Enroll on Desktop'
>       },
>       'stm-qrcode': {
>         headline: 'Scan the QR Code',
>         text: 'Please scan the QR code with your phone to continue the enrollment process.',
>         button: {
>           false: 'Copy Link',
>           true: 'Copied to Clipboard'
>         }
>       }
>     }
>   },
>   error: {
>     /**
>      * Collector Errors
>      */
>     FRAME_RESULTS_SET_UNSET: 'Please contact our support.',
>     OPTIONS_UNSET: 'Please contact our support.',
>     VIDEO_ELEMENT_UNSET: 'Please contact our support.',
>     VIDEO_ELEMENT_EVENT_LISTENERS_UNSET: 'Please contact our support.',
>     WEB_SOCKET_MESSAGE_SET_UNSET: 'Please contact our support.',
>
>     /**
>      * Media Device Errors
>      */
>     MEDIA_DEVICES_EMPTY_AUDIO_INPUT_LABEL: 'Please allow the browser to access your microphone and try again.',
>     MEDIA_DEVICES_EMPTY_VIDEO_INPUT_LABEL: 'Please allow the browser to access your camera and try again.',
>     MEDIA_DEVICES_NO_VIDEO_INPUTS: 'No camera was found. Please connect a camera and try again.',
>
>     /**
>      * Media Stream Errors
>      */
>     MEDIA_STREAM_ABORT: 'Please make sure your camera is not being used by another application and try again.',
>     MEDIA_STREAM_INVALID_STATE: 'Please make sure your camera is not being used by another application and try again.',
>     MEDIA_STREAM_NOT_ALLOWED: 'Please make sure you granted camera access permission and that no other application is using your camera, then try again.',
>     MEDIA_STREAM_NOT_FOUND: 'No camera was found. Please connect a camera and try again.',
>     MEDIA_STREAM_NOT_READABLE: 'Please make sure your camera is not being used by another application and try again.',
>     MEDIA_STREAM_OVERCONSTRAINED: 'The camera does not meet our minimum requirements. Please use a different camera and try again.',
>     MEDIA_STREAM_SECURITY: 'Please contact our support.',
>     MEDIA_STREAM_TYPE: 'Please contact our support.',
>     MEDIA_STREAM_UNSET: 'Please contact our support.',
>
>     /**
>      * Server Errors
>      */
>     SERVER_CUSTOMER_NOT_FOUND: 'Please contact our support.',
>     SERVER_FACE_DOES_NOT_MATCH: 'Make sure you are in a well-lit environment, possibly without any eyewear or hats.',
>     SERVER_FORBIDDEN: 'Please try again or contact our support if the problem persists.',
>     SERVER_IMAGE_ENCRYPT_FAILED: 'Please contact our support.',
>     SERVER_INTERNAL_ERROR: 'Please try again or contact our support if the problem persists.',
>     SERVER_NO_ATTEMPTS_LEFT: 'Please contact our support.',
>     SERVER_RECOGNITION_FAILED: {
>       eyes_closed: 'Make sure your eyes are open, possibly without any eyewear.',
>       face_angle_too_large: 'Make sure you are looking into the camera.',
>       face_is_occluded: 'Make sure to remove any obstructions from your face, possibly any eyewear or hats.',
>       face_missing: 'Make sure to show your face in the frame, possibly without any eyewear or hats.',
>       face_multiple: 'Make sure to show only one face in the frame, possibly with a plain background.',
>       face_partial: 'Make sure to show your full face in the frame.',
>       face_too_close: 'Make sure to move your face farther from the device.',
>       face_too_small: 'Make sure to move your face closer to the device.',
>       image_black_and_white: 'Make sure you are in a well-lit environment.',
>       image_metadata_low_light: 'Make sure you are in a well-lit environment.',
>       no_movement_from_device: 'Make sure to pick up your device.',
>       no_movement_from_subject: 'Make sure to tilt your face slightly every now and then.',
>       none: 'Make sure you are in a well-lit environment, possibly without any eyewear or hats.'
>     },
>     SERVER_TIMEOUT: 'Please try again or contact our support if the problem persists.',
>     SERVER_UNAVAILABLE_SERVICE: 'Please try again or contact our support if the problem persists.',
>     SERVER_UNPROCESSABLE_EVENT: 'Please contact our support.',
>     SERVER_USER_ALREADY_ENROLLED: 'The account {username} already exists.',
>     SERVER_USER_LOCKED_OUT: 'Too many attempts. You can try again in {lockout_expiration}.',
>     SERVER_USER_NOT_FOUND: 'The account {username} does not exist.',
>     SERVER_VALIDATION_FAILED: 'Please contact our support.',
>
>     /**
>      * Session Manager Errors
>      */
>     SESSION_MANAGER_NOT_NULL: 'Please contact our support.',
>     SESSION_MANAGER_NULL: 'Please contact our support.',
>
>     /**
>      * Special Errors
>      */
>     CREATE_MEDIA_STREAM_ARGS_UNSET: 'Please contact our support.',
>     EXCEPTION: 'Please contact our support.',
>     RUNTIME_VIOLATION: 'Please contact our support.',
>     SYMBOL_DESCRIPTION_UNSET: 'Please contact our support.',
>
>     /**
>      * Storage Errors
>      */
>     SESSION_ID_UNSET: 'Please contact our support.',
>
>     /**
>      * Verify Connect Options Errors
>      */
>     CUSTOMER_UNSET: 'Please contact our support.',
>     KEY_DECODE_FAILED: 'Please contact our support.',
>     KEY_UNSET: 'Please contact our support.',
>     KEY_ID_UNSET: 'Please contact our support.',
>     USERNAME_UNSET: 'Please contact our support.',
>     WEB_SOCKET_URL_PARSE_FAILED: 'Please contact our support.',
>     WEB_SOCKET_URL_UNSET: 'Please contact our support.',
>
>     /**
>      * Web Assembly Errors
>      */
>     WEB_ASSEMBLY_ABORTED: 'Please try again or contact our support if the problem persists.',
>     WEB_ASSEMBLY_FACTORY_FAILED: 'Please contact our support.',
>     WEB_ASSEMBLY_IMPORT_FAILED: 'Please contact our support.',
>     WEB_ASSEMBLY_NOT_READY: 'Please contact our support.',
>     WEB_ASSEMBLY_MODULE_NOT_FOUND: 'Please contact our support.',
>
>     /**
>      * Web Socket Errors
>      */
>     WEB_SOCKET_ERROR: 'Please try again or contact our support if the problem persists.',
>     WEB_SOCKET_OPEN: 'Please try again or contact our support if the problem persists.',
>     WEB_SOCKET_TIMEOUT: 'Please try again or contact our support if the problem persists.',
>     WEB_SOCKET_UNEXPECTED_CLOSE: 'Please try again or contact our support if the problem persists.',
>
>     /**
>      * Flow Errors
>      */
>     QUEUE_UNSET: 'Please contact our support.',
>     SYMBOL_UNSET: 'Please contact our support.',
>
>     /**
>      * Cancel or Close Errors
>      */
>     NONCANCELABLE: 'Please try again or contact our support if the problem persists.'
>   }
> }
> ```

When creating custom language packs, remember that the `language` specified in the pack must match the value specified in the `lang` attribute of the web component. Otherwise, the component ignores the custom language pack.

### Example: Customizing instruction heading

This example customizes the title of the camera instructions for an authorization component:

> **Collapse: Details**
>
> ```javascript
> <!doctype html>
> <html lang="en">
>   <head>
>     <meta charset="UTF-8" />
>     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
>     <title>Auth</title>
>     <style>
>       * {
>         box-sizing: border-box;
>       }
>
>       body {
>         align-items: center;
>         display: flex;
>         justify-content: center;
>         margin: 0;
>         min-height: 100vh;
>         padding: 8px;
>       }
>
>       kl-auth {
>         border: 1px solid lightgray;
>       }
>     </style>
>   </head>
>   <body>
>     <kl-auth
>       authorization-token="USER_AUTHORIZATION_FROM_CUSTOMER"
>       customer="CUSTOMER_NAME"
>       enable-camera-instructions
>       key="IMAGE_ENCRYPTION_PUBLIC_KEY"
>       key-id="IMAGE_ENCRYPTION_KEY_ID"
>       lang="en"
>       size="375"
>       theme="light"
>       transaction-data='DATA_FROM_CUSTOMER_SERVER_TO_BE_SIGNED'
>       username="USERNAME"
>       ws-url="KEYLESS_AUTHENTICATION_SERVICE_URL"
>     ></kl-auth>
>     <script src="@keyless/sdk-web-components/index.js"></script>
>     <script>
>       const auth = document.querySelector('kl-auth')
>
>       auth.localizationPacks = [
>         {
>           data: {
>             auth: {
>               step: {
>                 'camera-instructions': {
>                   headline: 'Custom Camera Instructions Title',
>                 }
>               }
>             }
>           },
>           language: 'en'
>         }
>       ]
>     </script>
>   </body>
> </html>
> ```
