46 lines
1.9 KiB
PHP
46 lines
1.9 KiB
PHP
<?php
|
|
|
|
use Illuminate\Support\Facades\File;
|
|
|
|
/**
|
|
* `:attr="__('…')"` ist nur an Blade-Komponenten (`<x-…>`, `<flux:…>`)
|
|
* ein PHP-Ausdruck. An einem normalen HTML-Element reicht Blade das
|
|
* Attribut unverändert an Alpine durch, und der Browser wirft
|
|
* „ReferenceError: __ is not defined“ — so geschehen auf /register
|
|
* (GlitchTip browser-pressekonto, Issue 15, 06.10.2026). Für HTML-Elemente
|
|
* gilt: `attr="{{ __('…') }}"`.
|
|
*/
|
|
function alpineTranslationBindingPattern(): string
|
|
{
|
|
// HTML-Tag (keine Komponente), beliebige Attribute auch über mehrere
|
|
// Zeilen, dann ein Alpine-Binding, dessen Ausdruck mit __( beginnt.
|
|
return '/<(?!x-|flux:|livewire:|\/)([a-z][a-z0-9-]*)\b((?:[^>"]|"[^"]*")*?)\s(:[a-zA-Z.-]+|x-bind:[a-zA-Z.-]+)="\s*__\(/s';
|
|
}
|
|
|
|
test('no html element binds an alpine attribute to the php translation helper', function () {
|
|
$pattern = alpineTranslationBindingPattern();
|
|
$offenders = [];
|
|
|
|
foreach (File::allFiles(resource_path('views')) as $view) {
|
|
if (! str_ends_with($view->getFilename(), '.blade.php')) {
|
|
continue;
|
|
}
|
|
|
|
$contents = File::get($view->getRealPath());
|
|
|
|
preg_match_all($pattern, $contents, $matches, PREG_OFFSET_CAPTURE);
|
|
|
|
foreach ($matches[3] as [$attribute, $offset]) {
|
|
$offenders[] = sprintf('%s:%d %s', $view->getRelativePathname(), substr_count($contents, "\n", 0, $offset) + 1, $attribute);
|
|
}
|
|
}
|
|
|
|
expect($offenders)->toBe([], "Alpine-Binding mit __() an einem HTML-Element — auf attr=\"{{ __('…') }}\" umstellen:\n".implode("\n", $offenders));
|
|
});
|
|
|
|
test('the guard catches the pattern that broke the registration', function () {
|
|
$pattern = alpineTranslationBindingPattern();
|
|
|
|
expect(preg_match($pattern, "<input\n wire:model=\"name\"\n :placeholder=\"__('Vor- und Nachname')\"\n/>"))->toBe(1)
|
|
->and(preg_match($pattern, "<x-web.page-header\n :title=\"__('static.faq.title')\"\n/>"))->toBe(0);
|
|
});
|