Installation:
composer require elasticms/xliff
Ensure your project uses PHP 8.x and Laravel 10+.
First Use Case: Export a Laravel model to XLIFF for translation:
use Elasticms\Xliff\Xliff;
$posts = Post::all()->toArray();
$xliff = Xliff::create('en', 'fr', $posts);
$xliff->save('path/to/translations.xlf');
Where to Look First:
src/Xliff.php for core methods (create(), load(), save()).Export Workflow:
$data = Post::with('translations')->get()->toArray();
$xliff = Xliff::create('source_locale', 'target_locale', $data, [
'file_format' => 'xliff2', // or 'xliff1'
'segment_html' => true, // preserve HTML structure
]);
$xliff->save(storage_path('app/translations.xlf'));
Post::observe(PostObserver::class);
// app/Observers/PostObserver.php
class PostObserver {
public function saved(Post $post) {
if ($post->isDirty('content')) {
$this->exportTranslations($post);
}
}
protected function exportTranslations(Post $post) {
$xliff = Xliff::create('en', 'es', [$post->toArray()]);
$xliff->save("storage/translations/{$post->id}.xlf");
}
}
Import Workflow:
$xliff = Xliff::load(storage_path('app/translations.xlf'));
foreach ($xliff->getTranslations() as $translation) {
$post = Post::find($translation['id']);
$post->update([
'content' => $translation['target']['content'],
]);
}
HTML Segmentation:
$xliff = Xliff::create('en', 'fr', $posts, [
'segment_html' => true,
'html_tags' => ['p', 'strong', 'em'], // customize allowed tags
]);
Artisan Commands:
php artisan xliff:export posts en fr
php artisan xliff:import storage/translations.xlf
app/Console/Kernel.php:
protected $commands = [
\Elasticms\Xliff\Console\ExportCommand::class,
\Elasticms\Xliff\Console\ImportCommand::class,
];
Laravel Service Provider: Bind the XLIFF service for dependency injection:
// app/Providers/XliffServiceProvider.php
public function register() {
$this->app->singleton('xliff', function () {
return new \Elasticms\Xliff\Xliff();
});
}
Blade Directives: Create a custom Blade directive to fetch translations:
// app/Providers/BladeServiceProvider.php
Blade::directive('translate', function ($locale) {
return "<?php echo app('xliff')->getTranslation($locale); ?>";
});
Usage:
<h1>@translate('es')</h1>
Queue Jobs: Offload large exports/imports:
// app/Jobs/ExportTranslationsJob.php
public function handle() {
$xliff = Xliff::create('en', 'fr', $this->posts);
$xliff->save($this->path);
}
Dispatch:
ExportTranslationsJob::dispatch($posts, 'storage/translations.xlf')->onQueue('xliff');
Translation Fallback: Combine with Laravel’s localization:
$fallback = trans('messages.welcome');
$xliffTranslation = app('xliff')->getTranslation('es', 'messages.welcome');
echo $xliffTranslation ?? $fallback;
XML Memory Limits:
memory_limit. Mitigate by:
XMLWriter for streaming:
$writer = new XMLWriter();
$writer->openMemory();
$writer->startDocument('1.0', 'UTF-8');
// Stream segments incrementally
HTML Parsing Quirks:
$dom = new DOMDocument();
$dom->loadHTML($html);
$cleanHtml = $dom->saveHTML();
$xliff = Xliff::create('en', 'fr', $data, [
'html_tags' => ['p', 'span', 'div'], // exclude 'script', 'style'
]);
Locale Handling:
en-US). Sanitize with:
use Symfony\Component\Intl\Locales;
$locale = Locales::getName($inputLocale);
$translation = app('xliff')->getTranslation('es', 'key') ?: app('xliff')->getTranslation('en', 'key');
Namespace Conflicts:
elasticms elsewhere, alias the package:
use Elasticms\Xliff as XliffPackage;
XLIFF Version Mismatches:
$xliff = Xliff::create('en', 'fr', $data, ['file_format' => 'xliff2']);
Validate XLIFF Output: Use online validators like XML Validation or CLI:
xmllint --noout translations.xlf
Log Errors: Wrap XLIFF operations in try-catch:
try {
$xliff->save($path);
} catch (\Elasticms\Xliff\Exception $e) {
Log::error('XLIFF export failed: ' . $e->getMessage());
throw $e;
}
Check for Empty Segments:
XLIFF may skip empty <source> or <target> tags. Add validation:
if (empty($segment['source'])) {
throw new \InvalidArgumentException('Source text cannot be empty.');
}
Custom Metadata: Add project-specific notes to XLIFF files:
$xliff = Xliff::create('en', 'fr', $data, [
'metadata' => [
'project' => 'MyApp',
'due_date' => '2024-12-31',
],
]);
Context-Specific Translations:
Use XLIFF’s <context> or <group> for disambiguation:
$data = [
'title' => [
'context' => 'homepage',
'value' => 'Welcome',
],
];
Performance Optimization:
if (!$post->isDirty('content') && cache()->has("xliff_{$post->id}")) {
return cache()->get("xliff_{$post->id}");
}
SimpleXML for faster parsing (if supported):
$xliff = simplexml_load_file($path);
Testing:
$mockXliff = <<<'XML'
<?xml version="1.0"?>
<xliff version="2.2" xmlns="urn:oasis:names:tc:xliff:document:2.2
How can I help you explore Laravel packages today?