14 KiB
Translation Update Guide
This guide explains how to update all translation files when new content with translation strings is added to views.
Overview
The application uses Laravel's translation system with TWO types of translation files:
- JSON Translation Files (for simple strings) - managed by
kargnas/laravel-ai-translatorpackage - PHP Translation Files (for dynamic strings with parameters) - managed manually
JSON Translation Files Location: resources/lang/
en.json- English (source language)nl.json- Dutchde.json- Germanes.json- Spanishfr.json- French
PHP Translation Files Location: resources/lang/[locale]/
messages.php- Dynamic messages with placeholders (e.g.,:name,:count)routes.php- Route-related translationsvalidation.php- Validation messages (Laravel default)passwords.php- Password reset messages (Laravel default)
IMPORTANT: PHP translation files should NEVER be converted to JSON format. Laravel automatically uses PHP files when the key is not found in JSON files. Keep them separate to avoid conflicts.
When to Update Translations
Update translations whenever you:
- Add new
__('Translation string')calls in Blade views - Add new
__('Translation string')calls in PHP code - Add new
trans('Translation string')calls - Modify existing translation strings (creates new keys)
Step-by-Step Update Process
Step 1: Add English Translation Strings
First, add your new translation strings to resources/lang/en.json:
# Open the English translation file
nano resources/lang/en.json
Add your new keys in alphabetical order:
{
"existing.key": "Existing value",
"new.key.one": "New translation string one",
"new.key.two": "New translation string two",
"another.key": "Another value"
}
Important Rules for Translation Keys:
- Use descriptive, meaningful key names
- Use dot notation for organization (e.g.,
messages.welcome,buttons.submit) - Keep keys lowercase
- Use underscores for spaces in multi-word keys
- Avoid special characters except dots and underscores
Step 2: Sync Translation Files
Sync all language files to ensure they have the same keys as en.json:
php artisan ai-translator:sync-json
This command:
- Adds missing keys from
en.jsonto all other language files - Removes keys that don't exist in
en.jsonfrom other files - Keeps existing translations intact
- Adds English values as placeholders for new keys
Expected Output:
Syncing translation files...
✓ nl.json: Added 15 keys, removed 0 keys
✓ de.json: Added 15 keys, removed 0 keys
✓ es.json: Added 15 keys, removed 0 keys
✓ fr.json: Added 15 keys, removed 0 keys
Step 3: Translate New Keys with AI
Translate the new keys to all languages using the AI translator:
Option A: Translate All Languages Sequentially
Use the provided script to translate all languages in sequence:
./translate-new-keys.sh
Option B: Translate Each Language Individually
Translate Dutch:
php artisan ai-translator:translate-json --source=en --locale=nl --non-interactive --chunk=100
Translate German:
php artisan ai-translator:translate-json --source=en --locale=de --non-interactive --chunk=100
Translate Spanish:
php artisan ai-translator:translate-json --source=en --locale=es --non-interactive --chunk=100
Translate French:
php artisan ai-translator:translate-json --source=en --locale=fr --non-interactive --chunk=100
Translation Parameters:
--source=en- Source language (English)--locale=XX- Target language code--non-interactive- Don't ask for confirmation--chunk=100- Process 100 keys at a time (reduces API load)
Step 4: Verify Translation Results
Check that all files now have the same number of keys:
php -r "
\$en = json_decode(file_get_contents('resources/lang/en.json'), true);
\$nl = json_decode(file_get_contents('resources/lang/nl.json'), true);
\$de = json_decode(file_get_contents('resources/lang/de.json'), true);
\$es = json_decode(file_get_contents('resources/lang/es.json'), true);
\$fr = json_decode(file_get_contents('resources/lang/fr.json'), true);
echo \"Translation key counts:\n\";
echo \" en: \" . count(\$en) . \" keys\n\";
echo \" nl: \" . count(\$nl) . \" keys\n\";
echo \" de: \" . count(\$de) . \" keys\n\";
echo \" es: \" . count(\$es) . \" keys\n\";
echo \" fr: \" . count(\$fr) . \" keys\n\";
"
Expected Result: All files should have the same number of keys.
Step 5: Test Translations in Application
- Clear Laravel cache:
php artisan config:clear
php artisan cache:clear
- Test the new translations in your browser by switching languages
- Verify that all new strings appear correctly translated
Quick Reference Scripts
translate-new-keys.sh
Create this script in your project root for easy sequential translation:
#!/bin/bash
echo "=== TRANSLATING NEW KEYS TO ALL LANGUAGES ==="
echo ""
# Sync first to ensure all files have the same keys
echo "Step 1: Syncing translation files..."
php artisan ai-translator:sync-json
echo ""
# Translate each language
echo "Step 2: Translating to Dutch (nl)..."
php artisan ai-translator:translate-json --source=en --locale=nl --non-interactive --chunk=100
sleep 5
echo ""
echo "Step 3: Translating to German (de)..."
php artisan ai-translator:translate-json --source=en --locale=de --non-interactive --chunk=100
sleep 5
echo ""
echo "Step 4: Translating to Spanish (es)..."
php artisan ai-translator:translate-json --source=en --locale=es --non-interactive --chunk=100
sleep 5
echo ""
echo "Step 5: Translating to French (fr)..."
php artisan ai-translator:translate-json --source=en --locale=fr --non-interactive --chunk=100
echo ""
echo "=== TRANSLATION COMPLETE ==="
echo ""
# Show final counts
echo "Final key counts:"
php -r "
\$en = json_decode(file_get_contents('resources/lang/en.json'), true);
\$nl = json_decode(file_get_contents('resources/lang/nl.json'), true);
\$de = json_decode(file_get_contents('resources/lang/de.json'), true);
\$es = json_decode(file_get_contents('resources/lang/es.json'), true);
\$fr = json_decode(file_get_contents('resources/lang/fr.json'), true);
echo \" en: \" . count(\$en) . \" keys\n\";
echo \" nl: \" . count(\$nl) . \" keys\n\";
echo \" de: \" . count(\$de) . \" keys\n\";
echo \" es: \" . count(\$es) . \" keys\n\";
echo \" fr: \" . count(\$fr) . \" keys\n\";
"
Make it executable:
chmod +x translate-new-keys.sh
Translation Configuration
The AI translator is configured in config/ai-translator.php:
Key Settings:
- Provider: Anthropic (Claude)
- Model: claude-3-haiku-20240307
- API Key: Set in
.envasANTHROPIC_API_KEY - Source Locale: en (English)
- Tone: Friendly, intuitive, informal
- Addressing Style: Informal (je/du/tú/tu, not u/Sie/usted/vous)
Additional Rules Applied:
'additional_rules' => [
'default' => [
"Use a friendly, intuitive, and informal tone of voice. Simple vocabulary is preferred over advanced vocabulary.",
"Use informal addressing: 'je' in Dutch, 'tu' in French, 'du' in German, 'tú' in Spanish (not formal 'u', 'vous', 'Sie', 'usted').",
],
],
Troubleshooting
Issue: AI Translator Skips All Keys
Symptom: Message says "All strings are already translated. Skipping."
Cause: The translator considers key === value as "already translated"
Solution: Remove untranslated keys before running the translator:
php -r "
\$file = 'resources/lang/nl.json';
\$data = json_decode(file_get_contents(\$file), true);
\$filtered = array_filter(\$data, function(\$value, \$key) {
return \$value !== \$key; // Remove where key equals value
}, ARRAY_FILTER_USE_BOTH);
file_put_contents(\$file, json_encode(\$filtered, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL);
"
Issue: Translation Files Out of Sync
Symptom: Different number of keys in different language files
Solution: Run the sync command:
php artisan ai-translator:sync-json
Issue: API Rate Limiting
Symptom: Translation fails with rate limit errors
Solution:
- Reduce chunk size:
--chunk=50 - Add delays between translations (see translate-new-keys.sh script)
- Translate one language at a time with longer delays
Issue: Some Keys Not Translating
Symptom: Some keys remain in English in other language files
Solution:
- Check that the key exists in
en.json - Verify the key format (valid JSON)
- Check for special characters that might break translation
- Manually review and re-run translation for specific locale
Issue: Translations Show Literal Keys Instead of Values
Symptom: Translations display literal key names like "messages.login_success" instead of the actual translated text
Cause: This occurs when PHP file-based translations (e.g., resources/lang/en/messages.php) conflict with JSON translations. The AI translator may have incorrectly added keys from PHP translation files to JSON files with literal key names as values.
Example of the problem:
{
"messages.login_success": "messages.login_success"
}
This prevents Laravel from falling back to the PHP translation file.
Solution: Remove all conflicting keys that start with messages. from all JSON translation files:
php -r "
\$messagesPhp = require('resources/lang/en/messages.php');
\$languages = ['en', 'nl', 'de', 'es', 'fr'];
// Get list of conflicting keys
\$conflictingKeys = [];
foreach (\$messagesPhp as \$key => \$value) {
\$conflictingKeys[] = 'messages.' . \$key;
}
echo 'Removing ' . count(\$conflictingKeys) . ' conflicting keys from JSON files...' . PHP_EOL;
foreach (\$languages as \$lang) {
\$file = 'resources/lang/' . \$lang . '.json';
\$data = json_decode(file_get_contents(\$file), true);
\$originalCount = count(\$data);
foreach (\$conflictingKeys as \$key) {
if (isset(\$data[\$key])) {
unset(\$data[\$key]);
}
}
file_put_contents(\$file, json_encode(\$data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) . PHP_EOL);
echo \$lang . '.json: ' . \$originalCount . ' -> ' . count(\$data) . ' keys' . PHP_EOL;
}
echo 'Done! Clear cache with: php artisan config:clear && php artisan cache:clear' . PHP_EOL;
"
After removing the conflicting keys, clear Laravel's cache:
php artisan config:clear && php artisan cache:clear
Important Note: This project uses BOTH JSON translation files (for simple strings) AND PHP translation files (for dynamic strings with parameters). The resources/lang/en/messages.php file (and its counterparts in other languages) should NEVER be duplicated into JSON files. Laravel will automatically use PHP files when the key is not found in JSON files.
Best Practices
1. Always Start with English
- Add all new translation strings to
en.jsonfirst - Use clear, concise English that translates well
- Avoid idioms or culturally-specific phrases
2. Use Consistent Key Naming
Good:
messages.welcome_message
buttons.submit_form
errors.validation_failed
Bad:
welcomeMsg
btnSubmit
error_1
3. Organize Keys Logically
{
"auth.login": "Log in",
"auth.logout": "Log out",
"auth.register": "Register",
"profile.edit": "Edit profile",
"profile.delete": "Delete profile",
"profile.settings": "Profile settings",
"messages.welcome": "Welcome",
"messages.goodbye": "Goodbye"
}
4. Test Before Committing
- Always test translations in the application
- Check all 5 languages
- Verify formatting (capitalization, punctuation)
- Ensure placeholders (
:name,:count) work correctly
5. Regular Cleanup
Periodically check for unused translation keys:
php artisan ai-translator:find-unused --format=table
Review and remove unused keys to keep files maintainable.
Common Translation Patterns
Simple Strings
__('Welcome to our platform')
With Placeholders
__('Hello, :name!', ['name' => $user->name])
Pluralization
trans_choice('{0} No items|{1} One item|[2,*] :count items', $count)
Conditional Translation
__('messages.' . ($type === 'success' ? 'success_message' : 'error_message'))
Git Workflow
When committing translation updates:
# Stage all translation files
git add resources/lang/*.json
# Commit with descriptive message
git commit -m "Add translations for new mailing features
- Added 25 new translation keys for mailing management
- Translated to nl, de, es, fr using AI translator
- All files now have 1,414 keys"
# Push changes
git push origin main
Related Files
- Config:
config/ai-translator.php - Translation Files:
resources/lang/*.json - Helper Scripts:
retranslate-informal.sh- Re-translate all languages with informal styletranslate-new-keys.sh- Translate only new keys (create this)sync-translation-files.php- Manual sync script (backup method)
Quick Command Reference
# Sync all translation files
php artisan ai-translator:sync-json
# Translate to specific language
php artisan ai-translator:translate-json --source=en --locale=nl --non-interactive --chunk=100
# Find unused translation keys
php artisan ai-translator:find-unused
# Count keys in all files
php -r "\$en = json_decode(file_get_contents('resources/lang/en.json'), true); echo count(\$en);"
# Clear Laravel cache
php artisan config:clear && php artisan cache:clear
Environment Requirements
- PHP: 8.1+
- Laravel: 9+
- Package: kargnas/laravel-ai-translator
- API Key: Anthropic Claude API (set in
.envasANTHROPIC_API_KEY) - Internet: Required for AI translation API calls
Support
For issues with:
- Laravel AI Translator Package: https://github.com/kargnas/laravel-ai-translator
- Translation Process: Review this guide or check logs in
/tmp/ - API Issues: Check Anthropic API status and your API key validity