10 KiB
10 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | must_haves | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 11-translation-infrastructure | 03 | execute | 2 |
|
|
true |
|
Purpose: Enable efficient bulk translation management by exporting messages to CSV for translation in external tools (Google Sheets, professional translators) and importing completed translations. Output: Two CLI commands in Quotify plugin for translation workflow.
<execution_context>
@/.claude/get-shit-done/workflows/execute-plan.md
@/.claude/get-shit-done/templates/summary.md
</execution_context>
Prior plan
@.planning/phases/11-translation-infrastructure/11-01-SUMMARY.md
Existing export/import models
@plugins/golem15/translate/models/MessageExport.php @plugins/golem15/translate/models/MessageImport.php
Quotify plugin
@plugins/golem15/quotify/Plugin.php
Task 1: Create TranslateExportCommand plugins/golem15/quotify/console/TranslateExportCommand.php Create console command for exporting translations to CSV:```php
<?php
namespace Golem15\Quotify\Console;
use Illuminate\Console\Command;
use Golem15\Translate\Models\Message;
use Golem15\Translate\Models\Locale;
use Golem15\Translate\Models\MessageExport;
use Symfony\Component\Console\Input\InputOption;
class TranslateExportCommand extends Command
{
protected $name = 'quotify:translate-export';
protected $description = 'Export translation messages to CSV for bulk translation.';
public function handle()
{
$outputPath = $this->option('output') ?: storage_path('app/translations-export.csv');
// Get all columns (code, default, + all locales)
$columns = MessageExport::getColumns();
$columnKeys = array_keys($columns);
// Get all messages
$messages = Message::all();
if ($messages->isEmpty()) {
$this->error('No messages found. Run translate:scan first.');
return 1;
}
// Open file for writing
$file = fopen($outputPath, 'w');
// Write header row
fputcsv($file, $columnKeys);
// Write data rows
foreach ($messages as $message) {
$row = [];
$row['code'] = $message->code;
$row['x'] = $message->message_data['x'] ?? ''; // default/original
foreach (Locale::listEnabled() as $code => $name) {
$row[$code] = $message->message_data[$code] ?? '';
}
fputcsv($file, $row);
}
fclose($file);
$count = $messages->count();
$locales = implode(', ', array_keys(Locale::listEnabled()));
$this->info("Exported {$count} messages to: {$outputPath}");
$this->info("Columns: code, default (original), {$locales}");
$this->comment("Edit the file and run quotify:translate-import to import translations.");
return 0;
}
protected function getOptions()
{
return [
['output', 'o', InputOption::VALUE_OPTIONAL, 'Output file path', null],
];
}
}
```
Key features:
- Exports to CSV format (universally compatible)
- Includes code column (MD5 hash identifier)
- Includes default column (original English string)
- Includes column for each enabled locale
- Default output to storage/app/translations-export.csv
- Custom output path via --output option
php-legacy -l plugins/golem15/quotify/console/TranslateExportCommand.php
Export command created with proper structure
Task 2: Create TranslateImportCommand
plugins/golem15/quotify/console/TranslateImportCommand.php
Create console command for importing translations from CSV:
```php
<?php
namespace Golem15\Quotify\Console;
use Illuminate\Console\Command;
use Golem15\Translate\Models\Message;
use Golem15\Translate\Models\Locale;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputOption;
class TranslateImportCommand extends Command
{
protected $name = 'quotify:translate-import';
protected $description = 'Import translations from CSV file.';
public function handle()
{
$inputPath = $this->argument('file') ?: storage_path('app/translations-export.csv');
if (!file_exists($inputPath)) {
$this->error("File not found: {$inputPath}");
return 1;
}
$file = fopen($inputPath, 'r');
$header = fgetcsv($file);
if (!$header || !in_array('code', $header)) {
$this->error('Invalid CSV format. Must have "code" column.');
fclose($file);
return 1;
}
$enabledLocales = array_keys(Locale::listEnabled());
$updated = 0;
$created = 0;
$skipped = 0;
while (($row = fgetcsv($file)) !== false) {
$data = array_combine($header, $row);
$code = $data['code'] ?? null;
if (!$code) {
$skipped++;
continue;
}
$message = Message::firstOrNew(['code' => $code]);
$messageData = $message->message_data ?: [];
// Import default if provided and not already set
if (!empty($data['x']) && empty($messageData['x'])) {
$messageData['x'] = $data['x'];
}
// Import locale translations
foreach ($enabledLocales as $locale) {
if (isset($data[$locale]) && !empty(trim($data[$locale]))) {
$messageData[$locale] = trim($data[$locale]);
}
}
$message->message_data = $messageData;
if ($message->exists) {
$updated++;
} else {
$created++;
}
$message->save();
}
fclose($file);
$this->info("Import complete:");
$this->info(" Updated: {$updated}");
$this->info(" Created: {$created}");
$this->info(" Skipped: {$skipped}");
if ($updated > 0 || $created > 0) {
$this->comment("Run 'php artisan cache:clear' to see changes.");
}
return 0;
}
protected function getArguments()
{
return [
['file', InputArgument::OPTIONAL, 'Path to CSV file to import'],
];
}
protected function getOptions()
{
return [
['overwrite', null, InputOption::VALUE_NONE, 'Overwrite existing translations'],
];
}
}
```
Key features:
- Reads CSV with header row
- Matches messages by code (MD5 hash)
- Only imports non-empty translations
- Does not overwrite existing translations by default
- Reports created, updated, skipped counts
- Reminds to clear cache
php-legacy -l plugins/golem15/quotify/console/TranslateImportCommand.php
Import command created with proper structure
Task 3: Register commands in Quotify plugin
plugins/golem15/quotify/Plugin.php
Add command registration to Quotify Plugin.php.
Find the `register()` method in Plugin.php and add:
```php
public function register()
{
// ... existing code ...
// Register translation commands
$this->registerConsoleCommand('quotify.translate-export', \Golem15\Quotify\Console\TranslateExportCommand::class);
$this->registerConsoleCommand('quotify.translate-import', \Golem15\Quotify\Console\TranslateImportCommand::class);
}
```
If Plugin.php doesn't have a `register()` method, add one:
```php
public function register(): void
{
$this->registerConsoleCommand('quotify.translate-export', \Golem15\Quotify\Console\TranslateExportCommand::class);
$this->registerConsoleCommand('quotify.translate-import', \Golem15\Quotify\Console\TranslateImportCommand::class);
}
```
php-legacy artisan list | grep quotify:translate
Commands registered and appear in artisan list
Before declaring plan complete:
- [ ] TranslateExportCommand.php exists with valid PHP
- [ ] TranslateImportCommand.php exists with valid PHP
- [ ] Commands registered in Plugin.php
- [ ] `php-legacy artisan quotify:translate-export` runs and creates CSV
- [ ] `php-legacy artisan quotify:translate-import` runs and imports CSV
- [ ] Round-trip test: export, verify CSV has data, import succeeds
<success_criteria>
- All tasks completed
- Export command creates valid CSV with all locales
- Import command reads CSV and updates messages
- Commands appear in artisan list
- Round-trip export/import works correctly </success_criteria>