Initial commit
This commit is contained in:
484
references/translations/TRANSLATION_UPDATE_GUIDE.md
Normal file
484
references/translations/TRANSLATION_UPDATE_GUIDE.md
Normal file
@@ -0,0 +1,484 @@
|
||||
# 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:
|
||||
|
||||
1. **JSON Translation Files** (for simple strings) - managed by `kargnas/laravel-ai-translator` package
|
||||
2. **PHP Translation Files** (for dynamic strings with parameters) - managed manually
|
||||
|
||||
**JSON Translation Files Location:** `resources/lang/`
|
||||
- `en.json` - English (source language)
|
||||
- `nl.json` - Dutch
|
||||
- `de.json` - German
|
||||
- `es.json` - Spanish
|
||||
- `fr.json` - French
|
||||
|
||||
**PHP Translation Files Location:** `resources/lang/[locale]/`
|
||||
- `messages.php` - Dynamic messages with placeholders (e.g., `:name`, `:count`)
|
||||
- `routes.php` - Route-related translations
|
||||
- `validation.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`:
|
||||
|
||||
```bash
|
||||
# Open the English translation file
|
||||
nano resources/lang/en.json
|
||||
```
|
||||
|
||||
Add your new keys in alphabetical order:
|
||||
|
||||
```json
|
||||
{
|
||||
"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`:
|
||||
|
||||
```bash
|
||||
php artisan ai-translator:sync-json
|
||||
```
|
||||
|
||||
This command:
|
||||
- Adds missing keys from `en.json` to all other language files
|
||||
- Removes keys that don't exist in `en.json` from 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:
|
||||
|
||||
```bash
|
||||
./translate-new-keys.sh
|
||||
```
|
||||
|
||||
#### Option B: Translate Each Language Individually
|
||||
|
||||
Translate Dutch:
|
||||
```bash
|
||||
php artisan ai-translator:translate-json --source=en --locale=nl --non-interactive --chunk=100
|
||||
```
|
||||
|
||||
Translate German:
|
||||
```bash
|
||||
php artisan ai-translator:translate-json --source=en --locale=de --non-interactive --chunk=100
|
||||
```
|
||||
|
||||
Translate Spanish:
|
||||
```bash
|
||||
php artisan ai-translator:translate-json --source=en --locale=es --non-interactive --chunk=100
|
||||
```
|
||||
|
||||
Translate French:
|
||||
```bash
|
||||
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:
|
||||
|
||||
```bash
|
||||
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
|
||||
|
||||
1. Clear Laravel cache:
|
||||
```bash
|
||||
php artisan config:clear
|
||||
php artisan cache:clear
|
||||
```
|
||||
|
||||
2. Test the new translations in your browser by switching languages
|
||||
3. 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:
|
||||
|
||||
```bash
|
||||
#!/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:
|
||||
```bash
|
||||
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 `.env` as `ANTHROPIC_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:**
|
||||
```php
|
||||
'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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
```bash
|
||||
php artisan ai-translator:sync-json
|
||||
```
|
||||
|
||||
### Issue: API Rate Limiting
|
||||
|
||||
**Symptom:** Translation fails with rate limit errors
|
||||
|
||||
**Solution:**
|
||||
1. Reduce chunk size: `--chunk=50`
|
||||
2. Add delays between translations (see translate-new-keys.sh script)
|
||||
3. 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:**
|
||||
1. Check that the key exists in `en.json`
|
||||
2. Verify the key format (valid JSON)
|
||||
3. Check for special characters that might break translation
|
||||
4. 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:**
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```bash
|
||||
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:
|
||||
```bash
|
||||
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.json` first
|
||||
- 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
|
||||
```json
|
||||
{
|
||||
"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:
|
||||
|
||||
```bash
|
||||
php artisan ai-translator:find-unused --format=table
|
||||
```
|
||||
|
||||
Review and remove unused keys to keep files maintainable.
|
||||
|
||||
## Common Translation Patterns
|
||||
|
||||
### Simple Strings
|
||||
```php
|
||||
__('Welcome to our platform')
|
||||
```
|
||||
|
||||
### With Placeholders
|
||||
```php
|
||||
__('Hello, :name!', ['name' => $user->name])
|
||||
```
|
||||
|
||||
### Pluralization
|
||||
```php
|
||||
trans_choice('{0} No items|{1} One item|[2,*] :count items', $count)
|
||||
```
|
||||
|
||||
### Conditional Translation
|
||||
```php
|
||||
__('messages.' . ($type === 'success' ? 'success_message' : 'error_message'))
|
||||
```
|
||||
|
||||
## Git Workflow
|
||||
|
||||
When committing translation updates:
|
||||
|
||||
```bash
|
||||
# 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 style
|
||||
- `translate-new-keys.sh` - Translate only new keys (create this)
|
||||
- `sync-translation-files.php` - Manual sync script (backup method)
|
||||
|
||||
## Quick Command Reference
|
||||
|
||||
```bash
|
||||
# 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 `.env` as `ANTHROPIC_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
|
||||
Reference in New Issue
Block a user