coffreo/jms-translation-js-extractor-bundle
Install the Bundle
composer require coffreo/jms-translation-js-extractor-bundle
For Symfony Flex projects, this auto-enables the bundle. For non-Flex projects, add it to AppKernel.php:
new Coffreo\JmsTranslationJsExtractorBundle\CoffreoJmsTranslationJsExtractorBundle(),
Configure Extractor
Add this to config/packages/coffreo_jms_translation_js_extractor.yaml:
coffreo_jms_translation_js_extractor:
directories: ['%kernel.project_dir%/assets/js'] # Paths to JS files
output_dir: '%kernel.project_dir%/translations' # Output directory for extracted translations
format: 'json' # Output format (json, xlf, etc.)
ignore_patterns: ['node_modules', 'vendor'] # Ignore directories
First Use Case Run the extractor via CLI:
php bin/console coffreo:jms-translation-js-extractor:extract
This scans your JS files (e.g., assets/js/) for translation keys (e.g., __('key')) and generates a translation file (e.g., translations/messages.en.xlf).
Development Loop
php bin/console coffreo:jms-translation-js-extractor:extract
__('welcome.message') instead of hardcoded strings).CI/CD Pipeline Add the extractor to your build process (e.g., GitHub Actions, GitLab CI):
# Example GitLab CI snippet
script:
- php bin/console coffreo:jms-translation-js-extractor:extract
- git add translations/
- git diff --quiet || git commit -m "Update translations"
Symfony Translation Workflow
jms/translation-bundle:
# config/packages/jms_translation.yaml
jms_translation:
configs:
app:
dirs: ['%kernel.project_dir%/translations']
output_dir: '%kernel.project_dir%/var/cache/translations'
// assets/js/app.js
import translations from '../../var/cache/translations/messages.en.json';
console.log(translations['welcome.message']);
Dynamic Key Handling
t('key') or i18n.t('key')):
coffreo_jms_translation_js_extractor:
patterns:
- '__\([\'\"](.*?)[\'\"\)]'
- 't\([\'\"](.*?)[\'\"\)]'
__('user.profile.name')) and map them to Symfony’s translation domains.False Positives
__('some.function()')). Use ignore_patterns to exclude problematic files/directories:
ignore_patterns: ['tests', 'node_modules', '*.spec.js']
Caching Issues
php bin/console cache:clear
File Permissions
output_dir is writable by the web server:
chmod -R 775 %kernel.project_dir%/translations
Symfony Flex Conflicts
JMS\TranslationBundle in bundles.php to avoid autowiring conflicts.Dry Run Mode
Use the --dry-run flag to preview changes without writing files:
php bin/console coffreo:jms-translation-js-extractor:extract --dry-run
Verbose Output Enable debug mode for detailed logs:
php bin/console coffreo:jms-translation-js-extractor:extract --env=dev -v
Custom Logger Extend the extractor’s logger to track skipped files or errors:
// src/Command/ExtractCommand.php (override)
protected function configure(): void
{
$this->setHelp('Extract translations with custom logging.');
parent::configure();
}
Custom Extractors
Implement your own extractor logic by extending Coffreo\JmsTranslationJsExtractorBundle\Extractor\ExtractorInterface:
namespace App\Extractor;
use Coffreo\JmsTranslationJsExtractorBundle\Extractor\ExtractorInterface;
class CustomExtractor implements ExtractorInterface
{
public function extract(string $filePath): array
{
// Custom logic to parse JS files
return ['key' => 'value'];
}
}
Register it in services.yaml:
services:
App\Extractor\CustomExtractor:
tags: [coffreo.jms_translation_js_extractor.extractor]
Post-Processing
Use Symfony’s event system to modify extracted translations. Subscribe to coffreo.jms_translation_js_extractor.post_extract:
// src/EventListener/TranslationListener.php
namespace App\EventListener;
use Coffreo\JmsTranslationJsExtractorBundle\Event\PostExtractEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class TranslationListener implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
'coffreo.jms_translation_js_extractor.post_extract' => 'onPostExtract',
];
}
public function onPostExtract(PostExtractEvent $event): void
{
$translations = $event->getTranslations();
// Modify $translations as needed
$event->setTranslations($translations);
}
}
Integration with Webpack Encore If using Encore, configure it to ignore generated translation files:
// webpack.config.js
Encore
// ...
.configureBabel((config) => {
config.ignore = [
/translations\/.*/,
];
});
How can I help you explore Laravel packages today?