> For the complete documentation index, see [llms.txt](https://docs.apryse.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.apryse.com/web/get-started/samples/showcase-demo-rtl-language-support.md).

# Right-to-Left Language Support Showcase Demo Code Sample

Load right-to-left language PDFs and Office documents and interact with them directly in your browser, without server-side dependencies

{% hint style="info" %}
**Requirements**

*These packages are required to use these features in production. Trial keys have unlimited access to all features*

<a href="/web/get-started/readme.md" class="button primary">Web SDK</a><a href="https://showcase.apryse.com/rtl-language-support" class="button primary">Live demo</a>
{% endhint %}

Easily load right-to-left (RTL) language PDFs and Office documents and interact with them directly in your browser, without server-side dependencies.

This demo allows you to:

* Upload your own PDF file.
* Set UI in left-to-right mode.
* Edit in left-to-right mode.
* Test sample documents in Arabic, Hebrew, Persian, and Urdu.
* Download the document.

### **Implementation steps**

To add Left-to-Right Language capability in WebViewer: Step 1: Choose your [preferred web stack](/web/get-started/readme.md). Step 2: Add the ES6 JavaScript sample code provided in this guide.

Once you generate your license key, it will automatically be included in your sample code below.

{% @apryse-license-key/apryse-license-key platform="WEB\_VIEWER" variant="compact" %}

{% tabs %}
{% tab title="index.js" %}

<pre class="language-js" data-line-numbers><code class="lang-js">// ES6 Compliant Syntax
// Copilot name: GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-10-21
// File: showcase-demos/rtl-language-support/index.js

import WebViewer from '@pdftron/webviewer';

const licenseKey = '<code class="expression">visitor.claims.wvKey || "YOUR_WEBVIEWER_LICENSE_KEY"</code>';

function initializeWebViewer() {
  WebViewer(
    {
      path: '/lib',
      enableFilePicker: true, // Enable file picker to open files. In WebViewer -> menu icon -> Open File
      licenseKey: licenseKey, // Replace with your license key
    },
    document.getElementById('viewer')
  ).then((instance) => {

    // Customize the webviewer left panel
    UIElements.customizeUI(instance);

    // Listen for language change events
    instance.UI.addEventListener('languageChanged', (previous, next) => {
      // Log the previous and new language codes to the console
      console.log(`Previous language: ${previous} -> New language: ${next}`);
    });

    console.log('WebViewer loaded successfully.');
  }).catch((error) => {
    console.error('Failed to initialize WebViewer:', error);
  });
};

// Function to handle RTL language selection
window.SelectRTLLanguage = (instance, rtlLanguage, matchingButton) => {
  UIElements.supportedRtlLanguages.forEach((lang) => {
    lang.button.className = 'rtl-button';
  });

  if (rtlLanguage !== null) {
    // Set the selected rtl language and load the corresponding document
    matchingButton.className = 'rtl-button-selected';
    UIElements.selectedRtlLanguage = rtlLanguage;
    instance.UI.setLanguage(UIElements.selectedRtlLanguage.id);
    instance.UI.loadDocument(UIElements.selectedRtlLanguage.file);
  } else {
    // Reset language to English
    UIElements.selectedRtlLanguage = null;
    instance.UI.setLanguage('en');
  }
};

//helper function to load the ui-elements.js script
function loadUIElementsScript() {
  return new Promise((resolve, reject) => {
    if (window.UIElements) {
      console.log('UIElements already loaded');
      resolve();
      return;
    }
    const script = document.createElement('script');
    script.src = '/showcase-demos/rtl-language-support/ui-elements.js';
    script.onload = function () {
      console.log('✅ UIElements script loaded successfully');
      resolve();
    };
    script.onerror = function () {
      console.error('Failed to load UIElements script');
      reject(new Error('Failed to load ui-elements.js'));
    };
    document.head.appendChild(script);
  });
}

// Load UIElements script first, then initialize WebViewer
loadUIElementsScript().then(() => {
  initializeWebViewer();
}).catch((error) => {
  console.error('Failed to load UIElements:', error);
});
</code></pre>

{% endtab %}

{% tab title="ui-elements.js" %}
{% code title="ui-elements.js" lineNumbers="true" %}

```js
// ES6 Compliant Syntax
// Copilot name: GitHub Copilot, version: 1.0.0, model: GPT-4, version: 2024-06, date: 2025-10-21
// File: showcase-demos/rtl-language-support/ui-elements.js

// Class with static UI elements and related functions for the rtl language support demo

class UIElements {

    // The list of registered panels in the webviewer
    static viewerPanels = null;

    // The tab panel, representing the webviewer left panel
    static tabPanel = {
        handle: null,
        dataElement: 'tabPanel'
    };

    // The rtl language support sub-panel to be registered
    static rtlLanguagePanel = {
        handle: null,
        dataElement: 'rtlLanguagePanel',
        render: null,
    };

    static apryseFilesUrl = 'https://apryse.s3.us-west-1.amazonaws.com/public/files/samples/';

    // The list of supported rtl languages along with their sample files
    static supportedRtlLanguages = [
        {
            id: 'ar',
            name: 'العربية',
            englishName: 'Arabic',
            file: `${UIElements.apryseFilesUrl}UDHR-arabic.pdf`,
        },
        {
            id: 'he',
            name: 'עברית',
            englishName: 'Hebrew',
            file: `${UIElements.apryseFilesUrl}UDHR-hebrew.pdf`,
        },
        {
            id: 'fa',
            name: 'فارسی',
            englishName: 'Persian',
            file: `${UIElements.apryseFilesUrl}UDHR-persian.pdf`,
        },
        {
            id: 'ur',
            name: 'اردو',
            englishName: 'Urdu',
            file: `${UIElements.apryseFilesUrl}UDHR-urdu.pdf`,
        },
    ];

    // The currently selected rtl language. Default to the first language in the supportedRtlLanguages list
    static selectedRtlLanguage = UIElements.supportedRtlLanguages[0];

    // Customize the webviewer left panel
    static customizeUI = (instance) => {
        const { UI } = instance;

        // Set the toolbar group to the Annotations tools
        UI.setToolbarGroup('toolbarGroup-Annotate');

        // Close the tab panel (if it's open) for refreshment.
        UI.closeElements([UIElements.tabPanel.dataElement]);

        // Get the list of registered panels in the webviewer
        UIElements.viewerPanels = UI.getPanels();

        // Find the Tab Panel to modify. The rtl language sub-panel will be added to this Tab panel.
        UIElements.tabPanel.handle = UIElements.viewerPanels.find((panel) => panel.dataElement === UIElements.tabPanel.dataElement);

        // Register the rtl language sub-panel
        UIElements.RegisterRtlLanguagePanel(instance);

        // Add the new rtl language sub-panel to list of sub-panels under the Tab Panel
        UIElements.rtlLanguagePanel.handle = { render: UIElements.rtlLanguagePanel.dataElement };
        UIElements.tabPanel.handle.panelsList = [UIElements.rtlLanguagePanel.handle, ...UIElements.tabPanel.handle.panelsList];

        UI.openElements([UIElements.tabPanel.dataElement]);
    };

    // Register the rtl language sub-panel
    static RegisterRtlLanguagePanel = (instance) => {
        UIElements.rtlLanguagePanel.render = UIElements.createRtlLanguagePanelElements(instance);
        instance.UI.addPanel({
            dataElement: UIElements.rtlLanguagePanel.dataElement,
            location: 'left',
            icon: '<svg fill="#000000" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24px" height="24px" viewBox="796 796 200 200" enable-background="new 796 796 200 200" xml:space="preserve"><g><path d="M973.166,818.5H818.833c-12.591,0-22.833,10.243-22.833,22.833v109.333c0,12.59,10.243,22.833,22.833,22.833h154.333		c12.59,0,22.834-10.243,22.834-22.833V841.333C996,828.743,985.756,818.5,973.166,818.5z M896,961.5h-77.167		c-5.973,0-10.833-4.859-10.833-10.833V841.333c0-5.974,4.86-10.833,10.833-10.833H896V961.5z M978.58,872.129		c-0.547,9.145-5.668,27.261-20.869,39.845c4.615,1.022,9.629,1.573,14.92,1.573v12c-10.551,0-20.238-1.919-28.469-5.325		c-7.689,3.301-16.969,5.325-28.125,5.325v-12c5.132,0,9.924-0.501,14.366-1.498c-8.412-7.016-13.382-16.311-13.382-26.78h11.999		c0,8.857,5.66,16.517,14.884,21.623c4.641-2.66,8.702-6.112,12.164-10.351c5.628-6.886,8.502-14.521,9.754-20.042h-49.785v-12		h22.297v-11.986h12V864.5h21.055c1.986,0,3.902,0.831,5.258,2.28C977.986,868.199,978.697,870.155,978.58,872.129z"/><g><g><path d="M839.035,914.262l-4.45,11.258h-15.971l26.355-61.09h15.971l25.746,61.09h-16.583l-4.363-11.258H839.035zM852.475,879.876l-8.902,22.604h17.629L852.475,879.876z"/></g></g></g></svg>',
            title: 'RTL Languages',
            render: () => UIElements.rtlLanguagePanel.render,
        });
    };

    // Create the rtl language panel elements.
    static createRtlLanguagePanelElements = (instance) => {
        let panelDiv = document.createElement('div');
        panelDiv.id = 'rtlLanguagePanel';

        let paragraph = document.createTextNode('Load right to left language PDFs and Office documents and interact with them directly in your browser, without server-side dependencies, thanks to the Apryse Web SDK\'s RTL capabilities.');
        panelDiv.appendChild(paragraph);

        let dividerDiv = document.createElement('div');
        dividerDiv.style.borderTop = '1px solid #ccc';
        dividerDiv.style.margin = '10px 0';
        panelDiv.appendChild(dividerDiv);

        // Languages division title
        let languagesTitle = document.createElement("h3");
        languagesTitle.textContent = "Languages";
        panelDiv.appendChild(languagesTitle);

        // Create a button for each supported rtl language
        UIElements.supportedRtlLanguages.forEach((rtlLanguage) => {
            let button = UIElements.createButton(instance, rtlLanguage);
            rtlLanguage.button = button;
            panelDiv.appendChild(document.createElement("p"));
            panelDiv.appendChild(button);
        });

        panelDiv.appendChild(dividerDiv.cloneNode());

        // Create the reset language button
        let resetButton = UIElements.createButton(instance);
        panelDiv.appendChild(document.createElement("p"));
        panelDiv.appendChild(resetButton);

        // Select the first rtl language by default
        UIElements.selectedRtlLanguage.button.click();

        return panelDiv;
    };

    // Create a button for the given rtl language.
    // If rtlLanguage is null, create the reset language button.
    static createButton = (instance, rtlLanguage = null) => {
        let button = document.createElement("button");
        button.id = (rtlLanguage === null) ? `resetBtn` : `${rtlLanguage.id}Btn`;
        button.textContent = (rtlLanguage === null) ? 'Reset Language' : `${rtlLanguage.name} (${rtlLanguage.englishName})`;
        button.style.width = '100%';
        button.style.backgroundColor = 'blue';
        button.style.color = 'white';
        button.style.border = 'none';
        button.style.padding = '10px 15px';
        button.style.borderRadius = '12px';
        button.onmouseover = () => button.style.opacity = '0.8';
        button.onmouseout = () => button.style.opacity = '1.0';
        button.style.cursor = 'pointer';
        button.onclick = () => window.SelectRTLLanguage(instance, rtlLanguage, button);

        return button;
    };
}
```

{% endcode %}
{% endtab %}

{% tab title="index.css" %}
{% code title="index.css" lineNumbers="true" %}

```css
/* RTL Language Support Demo Styles */

.rtl-button {
  background-color: blue;
}

.rtl-button-selected {
  background-color: darkblue;
}
```

{% endcode %}
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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, and the optional `goal` query parameter:

```
GET https://docs.apryse.com/web/get-started/samples/showcase-demo-rtl-language-support.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
