Englische Fassung der Markenseiten: Merkmale, Leistungen, Abschnitte, Showroom, Bildunterschriften
Diese Markenfelder waren nur einsprachig gespeichert und erschienen auf der englischen Seite deutsch. Neue Spalte cms_brands.field_translations (additiv) trägt die Übersetzungen je Sprache, die bisherigen Spalten bleiben die deutsche Fassung; ohne Übersetzung gilt weiter Deutsch. Marken-Editor bearbeitet die Felder über den DE/EN-Umschalter (Bilder und Rubriken bleiben sprachübergreifend). BrandTranslationsSeeder spielt die englischen Texte der vier Kernmarken ein, ohne gepflegte Übersetzungen zu überschreiben. php artisan cms:untranslated listet Inhalte, die in einer Sprache noch fehlen oder deutsch sind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
dc31cdb401
commit
8ddc85422e
8 changed files with 982 additions and 34 deletions
105
app/Console/Commands/CmsUntranslated.php
Normal file
105
app/Console/Commands/CmsUntranslated.php
Normal file
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use App\Models\CmsArticle;
|
||||
use App\Models\CmsBrand;
|
||||
use FluxCms\Core\Models\CmsContent;
|
||||
use Illuminate\Console\Command;
|
||||
|
||||
/**
|
||||
* Findet Inhalte, die auf der englischen Seite deutsch erscheinen (09.10.2026): CMS-Sektionen,
|
||||
* Marken (auch Merkmale, Leistungen, Abschnitte, Showroom, Bildunterschriften) und Magazin.
|
||||
* Erkennung über typische deutsche Wörter – Eigennamen wie „Möbelservice“ allein schlagen nicht an.
|
||||
*/
|
||||
class CmsUntranslated extends Command
|
||||
{
|
||||
protected $signature = 'cms:untranslated {--locale=en : Zielsprache}';
|
||||
|
||||
protected $description = 'Listet CMS-Inhalte, die in der Zielsprache fehlen oder noch deutsch sind';
|
||||
|
||||
private const GermanWords = '/\b(und|der|die|das|für|mit|nicht|wir|Sie|Ihr|Ihre|Ihnen|ist|auf|ein|eine|vom|zum|zur|bei|aus|oder|auch|sich|werden|wird|unser|unsere|dem|den|des|im|sind|alle|mehr|über|wie|nach|nur|noch)\b/u';
|
||||
|
||||
public function handle(): int
|
||||
{
|
||||
$locale = (string) $this->option('locale');
|
||||
$findings = [];
|
||||
|
||||
foreach (CmsContent::query()->orderBy('group')->orderBy('key')->get() as $row) {
|
||||
$translations = $row->getTranslations('value');
|
||||
$label = "CMS {$row->group}.{$row->key}";
|
||||
|
||||
if (! array_key_exists($locale, $translations)) {
|
||||
$findings[] = [$label, 'keine Übersetzung'];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->collect($translations[$locale], $label, $findings);
|
||||
}
|
||||
|
||||
foreach (CmsBrand::query()->ordered()->get() as $brand) {
|
||||
foreach ($brand->translatable as $attribute) {
|
||||
$translations = $brand->getTranslations($attribute);
|
||||
|
||||
if (filled($translations[CmsBrand::BASE_LOCALE] ?? null) && blank($translations[$locale] ?? null)) {
|
||||
$findings[] = ["Marke {$brand->slug}.{$attribute}", 'keine Übersetzung'];
|
||||
} else {
|
||||
$this->collect($translations[$locale] ?? null, "Marke {$brand->slug}.{$attribute}", $findings);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CmsBrand::LOCALIZED_FIELDS as $field) {
|
||||
$this->collect($brand->localized($field, $locale), "Marke {$brand->slug}.{$field}", $findings);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (CmsArticle::query()->get() as $article) {
|
||||
foreach ($article->translatable as $attribute) {
|
||||
$translations = $article->getTranslations($attribute);
|
||||
$label = "Magazin {$article->slug}.{$attribute}";
|
||||
|
||||
if (filled($translations[CmsBrand::BASE_LOCALE] ?? null) && blank($translations[$locale] ?? null)) {
|
||||
$findings[] = [$label, 'keine Übersetzung'];
|
||||
} else {
|
||||
$this->collect($translations[$locale] ?? null, $label, $findings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($findings === []) {
|
||||
$this->info("Keine deutschen oder fehlenden Texte für „{$locale}“ gefunden.");
|
||||
|
||||
return self::SUCCESS;
|
||||
}
|
||||
|
||||
$this->table(['Stelle', 'Text'], $findings);
|
||||
$this->warn(count($findings).' Stellen.');
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array{0: string, 1: string}> $findings
|
||||
*/
|
||||
private function collect(mixed $value, string $path, array &$findings): void
|
||||
{
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $key => $item) {
|
||||
$this->collect($item, "{$path}.{$key}", $findings);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (! is_string($value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$text = trim(html_entity_decode(strip_tags($value)));
|
||||
|
||||
if ($text !== '' && preg_match_all(self::GermanWords, $text) >= 2) {
|
||||
$findings[] = [$path, mb_strimwidth($text, 0, 90, '…')];
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue