Repository navigation
Closed
Labels
cross-packageRequested by or affecting another next-gen packageRequested by or affecting another next-gen packagenext-genNext-gen Javaabu packagesNext-gen Javaabu packages
Description
javaabu/translatable v3 defines how packages support translations optionally (contract: n4ff4h/translatable docs/advanced-usage/for-package-authors.md on next-gen, summary on n4ff4h/translatable#10). Stencil fields need a hook so forms defined once render per-locale inputs in both drivers when the model is translatable. Translatable stays optional for stencil: suggest + require-dev, feature-detected.
What stencil needs to add
Text::make('name')->label(__('Name'))->required()->translatable();
Textarea::make('description')->translatable(fn (?Model $model) => $model?->is_public);translatable(bool|Closure $translatable = true)on the base field (closure-evaluated like other props).- At render/serialize time a field is translatable when
translatableis true andclass_exists(\Javaabu\Translatable\Translatable::class) && \Javaabu\Translatable\Translatable::supports($model ?? $model_class, $field_name). Otherwise it renders exactly as today (so->translatable()is harmless without the package or on a non-translatable model). - A translatable field expands into one input per locale with
Translatable::inputs($field_name, $model)(aCollection<string, LocaleInput>, the model's primary locale first). EachLocaleInputgives:name:name_en,name_dv(always{field}_{locale}, the default locale included)locale(Locale:code,native_name,direction,isThaana()),is_primarylabel($label): "Name (ދިވެހި)"toArray():{ field, name, locale, direction, thaana, primary, language }
- Validation:
Translatable::rules($model, $rules)turns['name' => ['required', 'string']]intoname_en(primary, rules as written) andname_dv(required→nullable). Stencil's automatic validation should run its generated rules through it for translatable fields. - Binding: values come from
Translatable::values($model, ['name'])(['name_en' => 'Malé', 'name_dv' => 'މާލެ']), or$model->name_dv, which forms' model binding already reads. Old input uses the same names. - Saving:
$model->fill($validated)/create()/update()accept the per-locale names; translations are written on save. No stencil code needed.
Rendering
- Blade driver: render
<x-translatable::field type="text" name="name" :label="…" />(ortext/textarea) from translatable; it draws per-locale tabs of<x-forms::text name="name_dv" dir="rtl" thaana …>and handles errors and old input. Its attributes are the forms v2 attributes pluslayout="tabs|stacked". - React driver: serialize a translatable field as the plain field plus
translatable: { inputs: [LocaleInput::toArray(), …] }. Render one@javaabu/formsfield per input (name,dir,thaana, label fromlanguage.native_name), grouped in tabs. Don't import@javaabu/translatablefrom stencil's React code (it only exists in apps that install translatable); the serialized data is enough. Apps can still map it to translatable'sTranslatableField, which takes the sameinputs.
Asks
->translatable()on fields, evaluated as above.- Both drivers expanding via
Translatable::inputs()and validation viaTranslatable::rules(). - Tests with translatable installed (
Javaabu\Translatable\Testing\InteractsWithLanguages::setUpLanguages(['en', 'dv'])) and with it off (withoutTranslatable()), using Thaana values.
Require it for tests as "javaabu/translatable": "^3.0@dev" with { "type": "vcs", "url": "https://github.com/n4ff4h/translatable" }. If any of this doesn't fit stencil's architecture, comment here and I'll adjust translatable's side.
Metadata
Metadata
Assignees
Labels
cross-packageRequested by or affecting another next-gen packageRequested by or affecting another next-gen packagenext-genNext-gen Javaabu packagesNext-gen Javaabu packages
Activity
n4ff4h commentedon Nov 4, 2026
Thanks, this fits. Here's what stencil will provide. Translatable stays optional:
suggest,require-devvia then4ff4h/translatableVCS repo at^3.0@dev, and guarded withclass_exists(\Javaabu\Translatable\Translatable::class).API.
->translatable(bool|Closure $condition = true)on the baseField. Closures get stencil's usual injection ($record,$model,$get,$operation, …). A field counts as translatable when the condition is true, the class exists, andTranslatable::supports($record ?? $model_class, $name)passes. Otherwise nothing changes.State and binding. A translatable field holds one state entry per input:
name_en,name_dv. These come fromTranslatable::values()and old input with the same names.$get('name_dv')works, and$get('name')returns the primary locale's value.Validation. The field's generated rules (
required,string,max:…, custom rules) go throughTranslatable::rules(). Each input's attribute name isLocaleInput::label($label).validate()returns the per-locale keys, sofillModel()/save()hand them straight tofill().Blade driver. Renders
<x-translatable::field type="{forms component}" name="name" :label …>with the field's other forms props as attributes, pluslayout. I'll add->translatableLayout('tabs'|'stacked')as a pass-through.JSON/React. The node keeps its usual shape (
type,name,component,props) and adds:The React renderer draws one
@javaabu/formscomponent per input (name,dir,thaana, label fromlanguage.native_name), grouped in@javaabu/formsTabs. It doesn't import@javaabu/translatable. Apps can register their own component for translatable fields through the stencil React registry, to use translatable'sTranslatableField.Conditions.
visibleWhen('name', …)on a translatable field watches the primary input.Tests. Covered both ways: with
InteractsWithLanguages::setUpLanguages(['en', 'dv'])and withwithoutTranslatable(), using Thaana values.This comes after the core drivers land. I'll comment here when it's pushed.
n4ff4h commentedon Nov 4, 2026
Done in a21ec03, as agreed above. Docs are in docs/advanced-usage/translatable.md.
One deviation from the proposal: the Blade driver doesn't render
<x-translatable::field>. It renders the same per-locale inputs itself, with javaabu/formstabsand inputs (dir,lang, Thaana, "Name (ދިވެހި)" labels, the tab with an error opens). The reason is that<x-translatable::field>binds to the model, while stencil fields bind to the form's state, which has to carry the user's edits through a live re-render. The React renderer draws the same inputs from the node'stranslatablekey, and apps can register translatable's own component as thetranslatabletype.Translatable is optional:
suggest, plusrequire-devfrom the n4ff4h VCS repository.class_exists().setUpLanguages(['en', 'dv'])andwithoutTranslatable().