# How to Add New Translations to the Stirling-PDF UI Using Locale Files

> Learn how to add new translations to Stirling-PDF UI. Translate TOML locale files by copying the English reference, updating key-value pairs, and running validation scripts before submitting your PR.

- Repository: [Stirling Tools/Stirling-PDF](https://github.com/Stirling-Tools/Stirling-PDF)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Stirling-PDF uses TOML-based locale files rather than JSON to store UI translations.** To add a new language, create a directory under `frontend/public/locales/`, copy the English reference file from [`en-GB/translation.toml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/en-GB/translation.toml), translate the key-value pairs while preserving placeholders like `{n}` or `{{variable}}`, and run the validation scripts in `scripts/translations/` before submitting your pull request.

Stirling-PDF implements internationalization using **i18next** with a custom **TomlBackend** that loads translation strings from TOML configuration files. While many projects use JSON for localization, the `Stirling-Tools/Stirling-PDF` repository exclusively uses the TOML format for its standard workflow. If you require JSON for a custom backend integration, the repository provides conversion utilities, but the following guide covers the standard TOML-based approach for adding new UI translations.

## Understanding the Translation Architecture

The application stores all UI strings in `frontend/public/locales/<language>/translation.toml`. The i18next configuration in [`frontend/src/core/i18n/config.ts`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/src/core/i18n/config.ts) initializes the **TomlBackend** to parse these files at runtime. The [`LanguageSelector.tsx`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/LanguageSelector.tsx) component automatically detects available languages by reading the subdirectories within `frontend/public/locales/`, meaning you typically do not need to modify React code to add a new language option.

## Step-by-Step Guide to Adding a New Language

### 1. Create the Language Directory

Use a hyphenated language code following the `language-COUNTRY` format (e.g., `pl-PL`, `pt-BR`, `zh-CN`). Create the directory structure:

```bash
mkdir -p frontend/public/locales/pl-PL

```

### 2. Copy the Reference Translation File

Duplicate the English reference file to serve as your translation template. This file contains every translation key used throughout the application:

```bash
cp frontend/public/locales/en-GB/translation.toml frontend/public/locales/pl-PL/translation.toml

```

The [`en-GB/translation.toml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/en-GB/translation.toml) file serves as the master reference maintained by the core team. Always ensure you start with the latest version of this file to avoid missing newly added keys.

### 3. Translate the TOML Content

Edit the copied file using standard TOML syntax with `key = "value"` pairs. Preserve all placeholders exactly as they appear in the source text, including `{n}`, `{total}`, and `{{variable}}` formats.

```toml

# frontend/public/locales/pl-PL/translation.toml

[convert]
selectSourceFormat = "Wybierz format źródłowego pliku"
selectTargetFormat = "Wybierz format docelowego pliku"

[myFeature]
welcome = "Witamy w mojej funkcji"
description = "Ta funkcja wykonuje X, Y i Z."

```

### 4. Register the Language (Automatic Detection)

The [`frontend/src/core/components/shared/LanguageSelector.tsx`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/src/core/components/shared/LanguageSelector.tsx) component automatically detects new language folders and includes them in the dropdown menu. No code changes are required for basic addition. However, if you want to limit which languages appear in the UI, configure the `ui.languages` setting in your backend configuration files.

## Adding New Translation Keys to Existing Languages

When the UI introduces new features requiring additional text, you must add the keys to the English reference file first:

```toml

# frontend/public/locales/en-GB/translation.toml

[newFeature]
welcome = "Welcome to the new feature!"
buttonLabel = "Start Processing"

```

After updating the English reference, add the corresponding translations to every other language file following the same TOML section structure. Keeping the English file current ensures the validation scripts can detect missing translations in other locales.

## Validating Translation Files

Before committing your changes, run the three validation scripts located in `scripts/translations/` to ensure TOML syntax integrity, placeholder consistency, and translation completeness:

```bash
python3 scripts/translations/validate_json_structure.py --language pl-PL
python3 scripts/translations/validate_placeholders.py --language pl-PL
python3 scripts/translations/translation_analyzer.py --language pl-PL

```

The [`validate_placeholders.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/validate_placeholders.py) script is particularly important—it verifies that variables like `{0}` or `{{username}}` remain intact across all language files, preventing runtime errors where the application expects specific interpolation values.

## Converting TOML to JSON (Optional)

If you require JSON format for a custom backend implementation, use the conversion utility provided in the repository:

```bash
python3 scripts/translations/translation_merger.py

```

This utility converts the TOML locale files to JSON format. However, for contributing translations back to the main `Stirling-Tools/Stirling-PDF` repository, you must submit TOML files following the standard workflow described above.

## Key Implementation Files

- **Reference translation (English)**: [`frontend/public/locales/en-GB/translation.toml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/public/locales/en-GB/translation.toml)
- **i18n initialization**: [`frontend/src/core/i18n/config.ts`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/src/core/i18n/config.ts)
- **Language selector component**: [`frontend/src/core/components/shared/LanguageSelector.tsx`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/src/core/components/shared/LanguageSelector.tsx)
- **Structure validation**: [`scripts/translations/validate_json_structure.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/scripts/translations/validate_json_structure.py)
- **Placeholder validation**: [`scripts/translations/validate_placeholders.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/scripts/translations/validate_placeholders.py)
- **Completeness analysis**: [`scripts/translations/translation_analyzer.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/scripts/translations/translation_analyzer.py)
- **Format conversion**: [`scripts/translations/translation_merger.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/scripts/translations/translation_merger.py)
- **Developer documentation**: [`devGuide/HowToAddNewLanguage.md`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/devGuide/HowToAddNewLanguage.md)

## Summary

- Stirling-PDF uses **TOML files** stored in `frontend/public/locales/<language>/translation.toml`, not JSON.
- Always copy the [`en-GB/translation.toml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/en-GB/translation.toml) reference file when creating a new language translation.
- Preserve all placeholders like `{n}` and `{{variable}}` exactly as they appear in the source text.
- The [`LanguageSelector.tsx`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/LanguageSelector.tsx) component automatically detects new language folders without requiring code changes.
- Run the three validation scripts ([`validate_json_structure.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/validate_json_structure.py), [`validate_placeholders.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/validate_placeholders.py), [`translation_analyzer.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/translation_analyzer.py)) to ensure translation quality.
- Add new keys to the English reference file first, then translate them to other languages.

## Frequently Asked Questions

### Does Stirling-PDF use JSON files for translations?

No. The UI uses **i18next with a custom TomlBackend** that expects TOML format files. While the repository includes a [`translation_merger.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/translation_merger.py) script to convert TOML to JSON for custom backend integrations, the standard workflow and contribution process require TOML files placed in `frontend/public/locales/`.

### How do I add a completely new language that doesn't exist in the repository?

Create a new directory under `frontend/public/locales/` using a hyphenated language code (e.g., `es-MX` for Mexican Spanish), copy the contents of [`frontend/public/locales/en-GB/translation.toml`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/public/locales/en-GB/translation.toml) into it, and translate all values while keeping the keys identical. The language will automatically appear in the UI selector.

### Do I need to modify the LanguageSelector component to add my translation?

No. The [`frontend/src/core/components/shared/LanguageSelector.tsx`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/frontend/src/core/components/shared/LanguageSelector.tsx) component dynamically scans the `frontend/public/locales/` directory and populates the dropdown based on available folders. You only need to modify the component if you want to implement custom filtering logic beyond the automatic detection.

### What happens if I forget to include a placeholder in my translation?

The [`validate_placeholders.py`](https://github.com/Stirling-Tools/Stirling-PDF/blob/main/validate_placeholders.py) script will catch missing or modified placeholders during validation. If placeholders like `{0}`, `{n}`, or `{{variable}}` are missing or altered, the application may fail to render dynamic values correctly at runtime, causing broken UI strings or JavaScript errors.