2025-12-11 19:34:14 +05:30
# 🌍 Translation Guide for BentoPDF
This guide will help you add new languages or improve existing translations for BentoPDF.
## Table of Contents
- [Overview ](#overview )
- [Quick Start ](#quick-start )
- [Adding a New Language ](#adding-a-new-language )
- [Translation File Structure ](#translation-file-structure )
- [Where Translations Are Used ](#where-translations-are-used )
- [Testing Your Translations ](#testing-your-translations )
- [Translation Guidelines ](#translation-guidelines )
- [Common Issues ](#common-issues )
---
## Overview
BentoPDF uses **i18next ** for internationalization (i18n). Currently supported languages:
- **English** (`en` ) - Default
- **German** (`de` )
2025-12-12 08:49:23 +07:00
- **Vietnamese** (`vi` )
2026-01-07 22:46:54 +07:00
- **Indonesian** (`id` )
2026-01-11 03:19:45 +08:00
- **Chinese** (`zh` )
- **Traditional Chinese (Taiwan)** (`zh-TW` )
2025-12-14 00:20:40 +01:00
- **French** (`fr` )
2025-12-11 19:34:14 +05:30
The app automatically detects the language from the URL path:
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
- `/en/` → English
- `/de/` → German
2025-12-12 08:49:23 +07:00
- `/vi/` → Vietnamese
2026-01-07 22:46:54 +07:00
- `/id/` → Indonesian
2026-01-11 03:19:45 +08:00
- `/zh/` → Chinese
- `/zh-TW/` → Traditional Chinese (Taiwan)
2025-12-14 00:20:40 +01:00
- `/fr/` → French
2025-12-11 19:34:14 +05:30
---
## Quick Start
**To improve existing translations:**
1. Navigate to `public/locales/{language}/common.json`
2. Find the key you want to update
3. Change the translation value
4. Save and test
**To add a new language (e.g., Spanish):**
1. Copy `public/locales/en/common.json` to `public/locales/es/common.json`
2. Translate all values in `es/common.json`
3. Add Spanish to `supportedLanguages` in `src/js/i18n/i18n.ts`
4. Add Spanish name to `languageNames` in `src/js/i18n/i18n.ts`
5. Test thoroughly
---
## Adding a New Language
2025-12-14 00:20:40 +01:00
Let's add **Spanish ** as an example:
2025-12-11 19:34:14 +05:30
### Step 1: Create Translation File
```bash
# Create the directory
2025-12-14 00:20:40 +01:00
mkdir -p public/locales/es
2025-12-11 19:34:14 +05:30
# Copy the English template
2025-12-14 00:20:40 +01:00
cp public/locales/en/common.json public/locales/es/common.json
2025-12-11 19:34:14 +05:30
```
### Step 2: Translate the JSON File
2025-12-14 00:20:40 +01:00
Open `public/locales/es/common.json` and translate all the values:
2025-12-11 19:34:14 +05:30
```json
{
"nav": {
2025-12-14 00:20:40 +01:00
"home": "Inicio",
"about": "Acerca de",
"contact": "Contacto",
"allTools": "Todas las herramientas"
2025-12-11 19:34:14 +05:30
},
"hero": {
2025-12-14 00:20:40 +01:00
"title": "Tu conjunto de herramientas PDF gratuito y seguro",
"subtitle": "Combina, divide, comprime y edita archivos PDF directamente en tu navegador."
2025-12-11 19:34:14 +05:30
}
// ... continue translating all keys
}
```
⚠️ **Important ** : Only translate the **values ** , NOT the keys!
✅ **Correct: **
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```json
2025-12-14 00:20:40 +01:00
"home": "Inicio"
2025-12-11 19:34:14 +05:30
```
❌ **Wrong: **
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```json
2025-12-14 00:20:40 +01:00
"inicio": "Inicio"
2025-12-11 19:34:14 +05:30
```
### Step 3: Register the Language
Edit `src/js/i18n/i18n.ts` :
```typescript
2025-12-14 00:20:40 +01:00
// Add 'es' to supported languages
export const supportedLanguages = ['en', 'de', 'fr', 'es'] as const;
2025-12-11 19:34:14 +05:30
export type SupportedLanguage = (typeof supportedLanguages)[number];
// Add French display name
export const languageNames: Record<SupportedLanguage, string> = {
2026-01-07 22:46:54 +07:00
en: 'English',
de: 'Deutsch',
fr: 'Français', // ← Add this
2025-12-11 19:34:14 +05:30
};
```
2026-01-07 23:02:41 +07:00
### Step 4: Update Vite Configuration
In `vite.config.ts` , ensure the new language is included in the build:
```typescript
// Add 'fr' to the language regex
const langMatch = url.match(/^\/(en|de|zh|vi|it|fr)(\/.*)?$/);
```
### Step 5: Test Your Translation
2025-12-11 19:34:14 +05:30
```bash
# Start the dev server
npm run dev
2025-12-14 00:20:40 +01:00
# Visit the Spanish version
# http://localhost:5173/es/
2025-12-11 19:34:14 +05:30
```
---
## Translation File Structure
The `common.json` file is organized into logical sections:
```json
{
"nav": {
// Navigation menu items
},
"hero": {
// Homepage hero section
},
"features": {
// Features section
},
"tools": {
// Tool names and descriptions
},
"upload": {
// File upload UI
},
"settings": {
// Settings modal and keyboard shortcuts
},
"faq": {
// FAQ section
},
"footer": {
// Footer links and text
},
"compliance": {
// Security compliance information
},
"testimonials": {
// User testimonials
},
"support": {
// Support section
},
"alert": {
// Alert and error messages
}
}
```
### Key Naming Convention
- Use **camelCase ** for keys: `"deletePage"` not `"delete_page"`
- Use **nested objects ** for organization: `"nav.home"` is represented as:
```json
{
"nav": {
"home": "Home"
}
}
```
- Be descriptive: `"shortcutsWarning"` is better than `"warning1"`
---
## Where Translations Are Used
### 1. HTML Templates (`data-i18n` attribute)
```html
<!-- Translation key: nav.home -->
<a href="/" data-i18n="nav.home">Home</a>
```
The `data-i18n` attribute tells i18next which translation to use.
### 2. Tool Definitions
Tool names and descriptions are defined in `src/js/config/tools.ts` and use a special namespace:
```typescript
{
name: 'Merge PDF', // Used for shortcuts only
subtitle: 'Combine multiple PDFs into one file.',
}
```
In translations:
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```json
{
"tools": {
"mergePdf": {
"name": "PDF zusammenführen",
"subtitle": "Mehrere PDFs in eine Datei kombinieren."
}
}
}
```
### 3. Dynamic JavaScript (`t()` function)
For translations that need to be applied dynamically:
```typescript
import { t } from './i18n/i18n';
const message = t('alert.error');
console.log(message); // "Error" or "Fehler" depending on language
```
### 4. Placeholders
For input placeholders:
```html
2026-01-07 22:46:54 +07:00
<input
type="text"
placeholder="Search for a tool..."
2025-12-11 19:34:14 +05:30
data-i18n-placeholder="tools.searchPlaceholder"
/>
```
In `common.json` :
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```json
{
"tools": {
"searchPlaceholder": "Nach einem Tool suchen..."
}
}
```
---
## Testing Your Translations
### Manual Testing
1. **Start development server: **
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```bash
npm run dev
```
2. **Visit each language: **
- English: `http://localhost:5173/en/`
- German: `http://localhost:5173/de/`
2025-12-12 08:49:23 +07:00
- Vietnamese: `http://localhost:5173/vi/`
2026-01-07 22:46:54 +07:00
- Indonesian: `http://localhost:5173/id/`
2026-01-12 16:10:38 +08:00
- Chinese: `http://localhost:5173/zh/`
- Traditional Chinese (Taiwan): `http://localhost:5173/zh-TW/`
2025-12-14 00:20:40 +01:00
- French: `http://localhost:5173/fr/`
- Your new language: `http://localhost:5173/es/`
2025-12-11 19:34:14 +05:30
3. **Check these pages: **
- Homepage (`/` )
- About page (`/about.html` )
- Contact page (`/contact.html` )
- FAQ page (`/faq.html` )
- Tool pages (e.g., `/merge-pdf.html` )
4. **Test these interactions: **
- Click the language switcher in the footer
- Navigate between pages
- Open the settings modal (click gear icon next to search)
- Try a tool to see upload messages
### Automated Checks
Check for missing translations:
```bash
# This will show any missing keys
node scripts/check-translations.js
```
2026-01-07 22:46:54 +07:00
_(If this script doesn't exist, you may need to create it or manually compare JSON files)_
2025-12-11 19:34:14 +05:30
### Browser Testing
Test in different browsers:
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
- Chrome/Edge
- Firefox
- Safari
---
## Translation Guidelines
### 1. Keep the Tone Consistent
BentoPDF is **friendly, clear, and professional ** . Match this tone in your translations.
✅ **Good: **
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```json
"hero.title": "Ihr kostenloses und sicheres PDF-Toolkit"
```
❌ **Too formal: **
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```json
"hero.title": "Ihr gebührenfreies und gesichertes Werkzeug für PDF-Dokumente"
```
### 2. Preserve Formatting
Some strings contain HTML or special characters:
```json
{
"faq.analytics.answer": "We care about your privacy. BentoPDF does not track personal information. We use <a href=\"https://simpleanalytics.com\" class=\"text-indigo-400 hover:underline\" target=\"_blank\" rel=\"noopener noreferrer\">Simple Analytics</a> solely to see anonymous visit counts."
}
```
When translating, **keep the HTML tags intact ** :
```json
{
"faq.analytics.answer": "Wir schätzen Ihre Privatsphäre. BentoPDF verfolgt keine persönlichen Informationen. Wir verwenden <a href=\"https://simpleanalytics.com\" class=\"text-indigo-400 hover:underline\" target=\"_blank\" rel=\"noopener noreferrer\">Simple Analytics</a> ausschließlich, um anonyme Besucherzahlen zu sehen."
}
```
### 3. Handle Plurals and Gender
If your language has complex plural rules or gender distinctions, consult the [i18next pluralization guide ](https://www.i18next.com/translation-function/plurals ).
Example:
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```json
{
"pages": "page",
"pages_plural": "pages"
}
```
### 4. Don't Translate Brand Names or Legal Terms
Keep these as-is:
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
- BentoPDF
- PDF
- GitHub
- Discord
- Chrome, Firefox, Safari, etc.
- Terms and Conditions
- Privacy Policy
- Licensing
### 5. Technical Terms
For technical terms, use commonly accepted translations in your language:
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
- "Merge" → "Fusionner" (French), "Zusammenführen" (German)
- "Split" → "Diviser" (French), "Teilen" (German)
- "Compress" → "Compresser" (French), "Komprimieren" (German)
If unsure, check how other PDF tools translate these terms in your language.
### 6. String Length
Some UI elements have limited space. Try to keep translations **similar in length ** to the English version.
If a translation is much longer, test it visually to ensure it doesn't break the layout.
---
## Common Issues
### Issue: Translations Not Showing Up
**Solution:**
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
1. Clear your browser cache
2. Hard refresh (Ctrl+F5 or Cmd+Shift+R)
3. Check browser console for errors
4. Verify the JSON file is valid (no syntax errors)
### Issue: Some Text Still in English
**Possible causes:**
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
1. Missing translation key in your language file
2. Missing `data-i18n` attribute in HTML
3. Hardcoded text in JavaScript
**Solution:**
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
- Compare your language file with `en/common.json` to find missing keys
- Search the codebase for hardcoded strings
### Issue: JSON Syntax Error
**Symptoms:**
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```
SyntaxError: Unexpected token } in JSON at position 1234
```
**Solution:**
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
- Use a JSON validator: https://jsonlint.com/
- Common mistakes:
- Trailing comma after last item
- Missing or extra quotes
- Unescaped quotes inside strings (use `\"` )
### Issue: Language Switcher Not Showing New Language
**Solution:**
Make sure you added the language to both arrays in `i18n.ts` :
2026-01-07 22:46:54 +07:00
2025-12-11 19:34:14 +05:30
```typescript
export const supportedLanguages = ['en', 'de', 'fr']; // ← Add here
export const languageNames = {
2026-01-07 22:46:54 +07:00
en: 'English',
de: 'Deutsch',
fr: 'Français', // ← And here
2025-12-11 19:34:14 +05:30
};
```
---
## File Checklist
When adding a new language, make sure these files are updated:
- [ ] `public/locales/{lang}/common.json` - Main translation file
2026-01-07 22:46:54 +07:00
- [ ] `public/locales/{lang}/tools.json` - Tools translation file
2025-12-11 19:34:14 +05:30
- [ ] `src/js/i18n/i18n.ts` - Add to `supportedLanguages` and `languageNames`
- [ ] Test all pages: homepage, about, contact, FAQ, tool pages
- [ ] Test settings modal and shortcuts
- [ ] Test language switcher in footer
- [ ] Verify URL routing works (`/{lang}/` )
---
## Getting Help
If you have questions or need help:
1. Check existing translations in `public/locales/de/common.json` for reference
2. Open an issue on [GitHub ](https://github.com/alam00000/bentopdf/issues )
3. Join our [Discord server ](https://discord.gg/Bgq3Ay3f2w )
---
## Contributing Your Translation
Once you've completed a translation:
1. **Test thoroughly ** (see [Testing Your Translations ](#testing-your-translations ))
2. **Fork the repository ** on GitHub
3. **Create a new branch ** : `git checkout -b add-french-translation`
4. **Commit your changes ** : `git commit -m "Add French translation"`
5. **Push to your fork ** : `git push origin add-french-translation`
6. **Open a Pull Request ** with:
- Description of the language added
- Screenshots showing the translation in action
- Confirmation that you've tested all pages
Thank you for contributing to BentoPDF! 🎉
---
## Translation Progress
Current translation coverage:
2026-01-07 22:46:54 +07:00
| Language | Code | Status | Maintainer |
| ------------- | ---- | -------------- | ---------- |
| English | `en` | ✅ Complete | Core team |
| German | `de` | 🚧 In Progress | Core team |
| Vietnamese | `vi` | ✅ Complete | Community |
| Your Language | `??` | 🚧 In Progress | You? |
2025-12-11 19:34:14 +05:30
---
**Last Updated**: December 2025