# Localization

Every text in the web components is completely customizable and localizable, multiple languages are supported and the default language of the components can be changed with the `lang` attribute.

There are also two more attributes regarding localization which are:

| **Attribute**                                                                    | **Type**                        | **Explanation**                                                                                                                                             |
| -------------------------------------------------------------------------------- | ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p><code>localization-packs</code><br><code>localizationPacks</code></p>         | `LocalizationPack[]`            | You can pass an array of localization packs to this attribute, if you pass a localization pack that already exists it will be merged with the existing one. |
| <p><code>localization-variables</code><br><code>localizationVariables</code></p> | `Record<number \| string, any>` | The localization variables are usually dynamic values that can be injected inside the localization strings through the `{ variable }` syntax.               |

### LocalizationPack Interface

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

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

As a reference, here’s our english language pack:

```typescript
  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: {
    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',
  
    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: {
    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_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_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 accession 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_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_NOT_NULL: 'Please contact our support.',
    SESSION_MANAGER_NULL: 'Please contact our support.',

    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.',

    SESSION_ID_UNSET: 'Please contact our support.',

    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_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_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.',

    QUEUE_UNSET: 'Please contact our support.',
    SYMBOL_UNSET: 'Please contact our support.',

    NONCANCELABLE: 'Please try again or contact our support if the problem persists.'
  }
}
```

{% hint style="info" %}
Remember that the `language` specified in the pack must match with the `lang` attribute set in the web component for the localization to work.
{% endhint %}

Here’s an example on changing the instructions screen headline:

```html
<!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
      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="./node_modules/@keyless/sdk-web-components/elements/auth/auth-element.iife.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>
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keyless.io/web-sdk/web-sdk-reference/localization.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
