11 KiB
🌍 Translation Guide for BentoPDF
This guide will help you add new languages or improve existing translations for BentoPDF.
Table of Contents
- Overview
- Quick Start
- Adding a New Language
- Translation File Structure
- Where Translations Are Used
- Testing Your Translations
- Translation Guidelines
- Common Issues
Overview
BentoPDF uses i18next for internationalization (i18n). Currently supported languages:
- English (
en) - Default - German (
de) - Vietnamese (
vi)
The app automatically detects the language from the URL path:
/en/→ English/de/→ German/vi/→ Vietnamese
Quick Start
To improve existing translations:
- Navigate to
public/locales/{language}/common.json - Find the key you want to update
- Change the translation value
- Save and test
To add a new language (e.g., Spanish):
- Copy
public/locales/en/common.jsontopublic/locales/es/common.json - Translate all values in
es/common.json - Add Spanish to
supportedLanguagesinsrc/js/i18n/i18n.ts - Add Spanish name to
languageNamesinsrc/js/i18n/i18n.ts - Test thoroughly
Adding a New Language
Let's add French as an example:
Step 1: Create Translation File
# Create the directory
mkdir -p public/locales/fr
# Copy the English template
cp public/locales/en/common.json public/locales/fr/common.json
Step 2: Translate the JSON File
Open public/locales/fr/common.json and translate all the values:
{
"nav": {
"home": "Accueil",
"about": "À propos",
"contact": "Contact",
"allTools": "Tous les outils"
},
"hero": {
"title": "Votre boîte à outils PDF gratuite et sécurisée",
"subtitle": "Fusionnez, divisez, compressez et modifiez des PDF directement dans votre navigateur."
}
// ... continue translating all keys
}
⚠️ Important: Only translate the values, NOT the keys!
✅ Correct:
"home": "Accueil"
❌ Wrong:
"accueil": "Accueil"
Step 3: Register the Language
Edit src/js/i18n/i18n.ts:
// Add 'fr' to supported languages
export const supportedLanguages = ['en', 'de', 'fr'] as const;
export type SupportedLanguage = (typeof supportedLanguages)[number];
// Add French display name
export const languageNames: Record<SupportedLanguage, string> = {
en: 'English',
de: 'Deutsch',
fr: 'Français', // ← Add this
};
Step 4: Test Your Translation
# Start the dev server
npm run dev
# Visit the French version
# http://localhost:5173/fr/
Translation File Structure
The common.json file is organized into logical sections:
{
"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:{ "nav": { "home": "Home" } } - Be descriptive:
"shortcutsWarning"is better than"warning1"
Where Translations Are Used
1. HTML Templates (data-i18n attribute)
<!-- 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:
{
name: 'Merge PDF', // Used for shortcuts only
subtitle: 'Combine multiple PDFs into one file.',
}
In translations:
{
"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:
import { t } from './i18n/i18n';
const message = t('alert.error');
console.log(message); // "Error" or "Fehler" depending on language
4. Placeholders
For input placeholders:
<input
type="text"
placeholder="Search for a tool..."
data-i18n-placeholder="tools.searchPlaceholder"
/>
In common.json:
{
"tools": {
"searchPlaceholder": "Nach einem Tool suchen..."
}
}
Testing Your Translations
Manual Testing
-
Start development server:
npm run dev -
Visit each language:
- English:
http://localhost:5173/en/ - German:
http://localhost:5173/de/ - Vietnamese:
http://localhost:5173/vi/ - Your new language:
http://localhost:5173/fr/
- English:
-
Check these pages:
- Homepage (
/) - About page (
/about.html) - Contact page (
/contact.html) - FAQ page (
/faq.html) - Tool pages (e.g.,
/merge-pdf.html)
- Homepage (
-
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:
# This will show any missing keys
node scripts/check-translations.js
(If this script doesn't exist, you may need to create it or manually compare JSON files)
Browser Testing
Test in different browsers:
- Chrome/Edge
- Firefox
- Safari
Translation Guidelines
1. Keep the Tone Consistent
BentoPDF is friendly, clear, and professional. Match this tone in your translations.
✅ Good:
"hero.title": "Ihr kostenloses und sicheres PDF-Toolkit"
❌ Too formal:
"hero.title": "Ihr gebührenfreies und gesichertes Werkzeug für PDF-Dokumente"
2. Preserve Formatting
Some strings contain HTML or special characters:
{
"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:
{
"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.
Example:
{
"pages": "page",
"pages_plural": "pages"
}
4. Don't Translate Brand Names or Legal Terms
Keep these as-is:
- BentoPDF
- 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:
- "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:
- Clear your browser cache
- Hard refresh (Ctrl+F5 or Cmd+Shift+R)
- Check browser console for errors
- Verify the JSON file is valid (no syntax errors)
Issue: Some Text Still in English
Possible causes:
- Missing translation key in your language file
- Missing
data-i18nattribute in HTML - Hardcoded text in JavaScript
Solution:
- Compare your language file with
en/common.jsonto find missing keys - Search the codebase for hardcoded strings
Issue: JSON Syntax Error
Symptoms:
SyntaxError: Unexpected token } in JSON at position 1234
Solution:
- 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:
export const supportedLanguages = ['en', 'de', 'fr']; // ← Add here
export const languageNames = {
en: 'English',
de: 'Deutsch',
fr: 'Français', // ← And here
};
File Checklist
When adding a new language, make sure these files are updated:
public/locales/{lang}/common.json- Main translation filesrc/js/i18n/i18n.ts- Add tosupportedLanguagesandlanguageNames- 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:
- Check existing translations in
public/locales/de/common.jsonfor reference - Open an issue on GitHub
- Join our Discord server
Contributing Your Translation
Once you've completed a translation:
- Test thoroughly (see Testing Your Translations)
- Fork the repository on GitHub
- Create a new branch:
git checkout -b add-french-translation - Commit your changes:
git commit -m "Add French translation" - Push to your fork:
git push origin add-french-translation - 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:
| Language | Code | Status | Maintainer |
|---|---|---|---|
| English | en |
✅ Complete | Core team |
| German | de |
🚧 In Progress | Core team |
| Vietnamese | vi |
✅ Complete | Community |
| Your Language | ?? |
🚧 In Progress | You? |
Last Updated: December 2025