ibexa/jms-translation-bundle
Symfony bundle for extracting, managing, and updating translation messages. Scans PHP, Twig, and other resources, supports multiple translation formats, and provides tools for maintaining locale files and translation catalogs in your application.
## Getting Started
### Minimal Setup
1. **Installation**:
```bash
composer require ibexa/jms-translation-bundle
Add to config/bundles.php (Symfony 4+):
return [
// ...
Ibexa\JMS\TranslationBundle\JMSTranslationBundle::class => ['all' => true],
];
Basic Configuration:
Update config/packages/jms_translation.yaml (or create it):
jms_translation:
configs:
app:
dirs: ['%kernel.project_dir%/translations']
output_dir: '%kernel.project_dir%/translations'
excluded_dirs: ['%kernel.project_dir%/vendor']
excluded_files: ['*.excluded']
languages: ['en', 'fr']
ignored_domains: []
extractors: ['twig', 'php', 'xlf', 'yaml', 'xml']
First Use Case: Extract translations from your project:
php bin/console translation:extract
This scans your codebase (Twig, PHP, YAML, etc.) and generates .xlf files in your translations/ directory.
Twig Templates:
Use trans and transchoice filters in Twig:
{{ 'welcome.message'|trans({'%name%': user.name}) }}
{{ 'item.count'|transchoice(item.count, 0, 1, '%count% item|%count% items') }}
Extract with:
php bin/console translation:extract twig
PHP Classes:
Annotate translatable strings with @Translation:
use JMS\TranslationBundle\Annotation\Translation;
class UserController
{
/**
* @Translation("messages", domain="user")
*/
public function welcomeAction()
{
return $this->render('user/welcome.html.twig', [
'message' => 'welcome.message',
]);
}
}
Extract with:
php bin/console translation:extract php
Forms: Define translation domains for forms:
# config/packages/validation.yaml
services:
App\Form\Type\UserType:
tags: ['form.type']
arguments: ['App\Form\UserType']
calls:
- [setTranslationDomain, ['user']]
Extract form translations:
php bin/console translation:extract form
Custom Domains:
Configure domains in config/packages/jms_translation.yaml:
jms_translation:
configs:
app:
domains: ['messages', 'user', 'validation']
Reference domains in Twig/PHP:
{{ 'user.profile'|trans({}, 'user') }}
Validation Messages:
Extract validation messages from validation.yaml:
php bin/console translation:extract validation
Update from XLIFF:
php bin/console translation:update
This merges translated .xlf files back into your project’s translation files (e.g., .yml).
ICU Format Support: Export to ICU format (for pluralization/gender support):
php bin/console translation:export --format=icu
Ignore Files/Directories:
jms_translation:
configs:
app:
excluded_dirs: ['%kernel.project_dir%/vendor', '%kernel.project_dir%/tests']
excluded_files: ['*.test.php', '*.spec.php']
Ignore Specific Strings:
Use @Ignore annotation in PHP:
/**
* @Ignore()
*/
public function getHardcodedString()
{
return 'This will not be extracted.';
}
Or in Twig:
{% trans_default 'This will not be extracted.' ignore %}
php bin/console make:translation-config
(Extend the default config to match your needs.)# .github/workflows/translations.yml
jobs:
extract-translations:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: composer install
- run: php bin/console translation:extract
- uses: actions/upload-artifact@v2
with:
name: translations
path: translations/
Developers: Run extraction before committing:
git pre-commit
Add to .git/hooks/pre-commit:
#!/bin/sh
php bin/console translation:extract --dry-run || exit 1
Translators:
Provide .xlf files to translators, then update:
php bin/console translation:update
$translator = $this->createMock(TranslatorInterface::class);
$translator->method('trans')->willReturn('Mocked translation');
$container->set(TranslatorInterface::class, $translator);
Symlink Problems:
If translations are stored in a symlinked directory (e.g., vendor/), extraction may fail. Use absolute paths in excluded_dirs:
excluded_dirs: ['/absolute/path/to/vendor']
Permission Errors:
Ensure the output_dir is writable:
chmod -R 775 translations/
PHP Parser Conflicts:
If you encounter php-parser errors, pin its version in composer.json:
"require": {
"nikic/php-parser": "^4.10"
}
Annotation Caching: Clear cache after adding new annotations:
php bin/console cache:clear
Invalid XLIFF Files:
If translators report malformed .xlf files, use the --clean flag:
php bin/console translation:extract --clean
This regenerates all files from scratch.
Merge Conflicts: Use SHA1-based IDs in XLIFF to avoid conflicts:
jms_translation:
configs:
app:
xliff:
use_sha1_ids: true
Repeated Fields:
Labels for repeated fields (e.g., collectionType) may not extract. Use:
# config/packages/jms_translation.yaml
jms_translation:
configs:
app:
extractors:
form:
extract_repeated_fields: true
Validation Messages: Ensure validation domains are set correctly:
# config/packages/validation.yaml
services:
App\Validator\Constraints\CustomConstraint:
tags: ['validator.constraint']
arguments:
- { message: 'This is a custom message.' }
Extract with:
php bin/console translation:extract validation
Desc Filter:
The desc filter may not work with transchoice. Use:
{{ 'item.count'|transchoice(item.count, 0, 1, '%count% item|%count% items')|desc }}
Dynamic Domains:
Avoid dynamic domains in Twig (e.g., {{ domain|trans }}). Use static domains:
{% trans from 'messages' with {'%name%': name} %}
php bin/console translation:extract --dry-run
php bin/console translation:extract -vvv
config/packages/monolog.yaml:
handlers:
translation:
type: stream
path: "%kernel.logs_dir%/translation.log"
level: debug
channels: ["translation"]
How can I help you explore Laravel packages today?