docs(14.2.1): lock Go tables to golem15_translate_*
Execute-phase Task 2 chose golem15-prefix over the researched winter_translate_* names so the plugin ships vendor tables; PHP winter names stay a later import mapping. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -27,7 +27,7 @@ requirements: [D-05, D-08, D-09, D-10, D-11, D-12, D-17]
|
||||
must_haves:
|
||||
truths:
|
||||
- "D-09/D-12: a host model declares `Translatable() []string`, `TranslatableIndexes() []string`, and `MorphName() string`; callers use exported get/set and `WithLocale` APIs."
|
||||
- "D-10: default-locale values remain in host columns; each non-default locale is one JSON object row in `winter_translate_attributes`, and indexed values are mirrored to `winter_translate_indexes`."
|
||||
- "D-10: default-locale values remain in host columns; each non-default locale is one JSON object row in `golem15_translate_attributes`, and indexed values are mirrored to `golem15_translate_indexes`."
|
||||
- "D-11: a missing non-default value reads the host model's default-locale field."
|
||||
- "D-05: Locales is ordinary cabana CRUD, permission-gated by exactly `golem15.translate.manage_locales`; no Messages controller, permission, or navigation exists."
|
||||
- "Locale form writes only code/name/is_enabled; is_default and sort_order cannot be mass-assigned, while a permissioned make-default action preserves disabled/default lifecycle guards."
|
||||
@@ -47,11 +47,11 @@ must_haves:
|
||||
contains: "locale:"
|
||||
key_links:
|
||||
- from: "../sm-translate-plugin/classes/translatable.go"
|
||||
to: "winter_translate_attributes"
|
||||
to: "golem15_translate_attributes"
|
||||
via: "non-default SetTranslated upserts one locale/model row"
|
||||
pattern: "attribute_data"
|
||||
- from: "../sm-translate-plugin/classes/translatable.go"
|
||||
to: "winter_translate_indexes"
|
||||
to: "golem15_translate_indexes"
|
||||
via: "indexed fields upsert locale/model/item/value"
|
||||
pattern: "TranslatableIndexes"
|
||||
- from: "../sm-translate-plugin/controllers/locales.go"
|
||||
@@ -99,10 +99,10 @@ No REQUIREMENTS.md IDs are mapped to this phase. Probe predicates are intentiona
|
||||
<task type="tracer">
|
||||
<name>Task 1: Save one fixture title in en and pl, then read pl through the exported API</name>
|
||||
<files>../sm-translate-plugin/classes/translatable.go, ../sm-translate-plugin/classes/translatable_smoke_test.go, ../sm-translate-plugin/models/attribute.go, ../sm-translate-plugin/models/index.go, ../sm-translate-plugin/models/registry.go</files>
|
||||
<read_first>/media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/behaviors/TranslatableModel.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/classes/TranslatableBehavior.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/tests/unit/behaviors/TranslatableModelTest.php, ../sm-translate-plugin/models/locale.go, ../sm-translate-plugin/updates/202610060002_create_winter_translate_attributes.go, ../sm-translate-plugin/updates/202610060003_create_winter_translate_indexes.go, ../fonoteka.go/plugins/golem15/user/models/user.go (MorphName), .planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md (Translatable assignment)</read_first>
|
||||
<action>Implement the minimum stable D-09/D-12 API without Eloquent-style magic. Define a host-model contract with `Translatable() []string` and `MorphName() string`, plus an explicit indexed-field contract `TranslatableIndexes() []string`. Reject fields not declared by the model and locale codes not enabled in `winter_translate_locales`.
|
||||
<read_first>/media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/behaviors/TranslatableModel.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/classes/TranslatableBehavior.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/tests/unit/behaviors/TranslatableModelTest.php, ../sm-translate-plugin/models/locale.go, ../sm-translate-plugin/updates/202610060002_create_golem15_translate_attributes.go, ../sm-translate-plugin/updates/202610060003_create_golem15_translate_indexes.go, ../fonoteka.go/plugins/golem15/user/models/user.go (MorphName), .planning/phases/14.2.1-translate-plugin/14.2.1-PATTERNS.md (Translatable assignment)</read_first>
|
||||
<action>Implement the minimum stable D-09/D-12 API without Eloquent-style magic. Define a host-model contract with `Translatable() []string` and `MorphName() string`, plus an explicit indexed-field contract `TranslatableIndexes() []string`. Reject fields not declared by the model and locale codes not enabled in `golem15_translate_locales`.
|
||||
|
||||
`SetTranslated` writes the default locale directly to the host model field/column and writes non-default values to one `(locale, model_id, model_type)` `winter_translate_attributes` row as a JSON object keyed by field. Use explicit model primary-key extraction and explicit exported-field/GORM-column mapping; do not use `reflect.Type.String()` as morph identity. Attribute rows have no public controller.
|
||||
`SetTranslated` writes the default locale directly to the host model field/column and writes non-default values to one `(locale, model_id, model_type)` `golem15_translate_attributes` row as a JSON object keyed by field. Use explicit model primary-key extraction and explicit exported-field/GORM-column mapping; do not use `reflect.Type.String()` as morph identity. Attribute rows have no public controller.
|
||||
|
||||
`Translated` returns the host field for default locale; for another enabled locale it reads the JSON key and, when absent, returns the default host field per D-11. Keep an explicit locale argument even when context has a UI locale.
|
||||
|
||||
@@ -113,7 +113,7 @@ Create a neutral fixture model only in the smoke test, migrate its host table ex
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- Exported interfaces and functions compile from an external test package.
|
||||
- The default English value is in the fixture host row, not duplicated into `winter_translate_attributes`.
|
||||
- The default English value is in the fixture host row, not duplicated into `golem15_translate_attributes`.
|
||||
- The Polish value is present under `attribute_data.title` in exactly one pl/model row.
|
||||
- Undeclared fields and unenabled locale codes return errors without database writes.
|
||||
- Test fixture is test-only and no production fixture plugin is globally registered.
|
||||
@@ -125,7 +125,7 @@ Create a neutral fixture model only in the smoke test, migrate its host table ex
|
||||
<name>Task 2: Add indexed locale lookup, WithLocale query scope, and default fallback</name>
|
||||
<files>../sm-translate-plugin/classes/translatable.go, ../sm-translate-plugin/classes/translatable_smoke_test.go, ../sm-translate-plugin/README.md</files>
|
||||
<read_first>../sm-translate-plugin/classes/translatable.go, /media/nvme/dev/golem15/fonoteka/plugins/golem15/translate/behaviors/TranslatableModel.php (scopeTransWhere and index writes), /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/models/Post.php, /media/nvme/dev/golem15/fonoteka/plugins/golem15/journal/models/Category.php, .planning/phases/14.2.1-translate-plugin/14.2.1-RESEARCH.md (Minimum exported Go API)</read_first>
|
||||
<action>Expand from the proven save/read path. `WithLocale(ctx, db, locale)` validates the explicit locale and carries it on the GORM statement context; it must not mutate global state. Add an indexed equality helper/scope that joins `winter_translate_indexes` by locale, morph name, model id, and item, while default-locale lookup uses the host column and non-default lookup falls back to that host column only when no translated index match exists, matching the frozen PHP behavior.
|
||||
<action>Expand from the proven save/read path. `WithLocale(ctx, db, locale)` validates the explicit locale and carries it on the GORM statement context; it must not mutate global state. Add an indexed equality helper/scope that joins `golem15_translate_indexes` by locale, morph name, model id, and item, while default-locale lookup uses the host column and non-default lookup falls back to that host column only when no translated index match exists, matching the frozen PHP behavior.
|
||||
|
||||
When SetTranslated writes a declared indexed field, upsert the corresponding index row atomically with the attribute JSON update. Rewriting one locale/field must preserve other translated fields in the same JSON object. Empty translated values stay explicit empty values rather than silently borrowing fallback during admin editing; ordinary `Translated` still applies D-11 fallback.
|
||||
|
||||
@@ -136,7 +136,7 @@ Document only the exported identifiers that exist, MorphName's import-stability
|
||||
</verify>
|
||||
<acceptance_criteria>
|
||||
- `WithLocale` returns a GORM handle carrying an explicit validated locale on context and has no singleton mutation.
|
||||
- Setting an indexed Polish slug writes one matching `winter_translate_indexes` row.
|
||||
- Setting an indexed Polish slug writes one matching `golem15_translate_indexes` row.
|
||||
- Polish indexed lookup finds the fixture; default-locale lookup uses the host slug.
|
||||
- Missing Polish title returns English under normal reads per D-11.
|
||||
- README names every exported API identifier accurately and remains application-neutral.
|
||||
@@ -166,7 +166,7 @@ Port the plugin.* and locale.* UI phrases to `lang/en/lang.yaml` and `lang/pl/la
|
||||
- Unknown/unprivileged admin gets 403; privileged admin gets the Locales schema/list.
|
||||
- A crafted body cannot persist is_default or sort_order.
|
||||
- The permissioned make-default action rejects disabled locales and atomically leaves exactly one enabled default locale.
|
||||
- English/Polish phrasebook files are independent from `winter_translate_attributes`.
|
||||
- English/Polish phrasebook files are independent from `golem15_translate_attributes`.
|
||||
</acceptance_criteria>
|
||||
<done>Authorized administrators can manage the lean Locale surface while default-state and phrasebook/model-translation boundaries remain enforced.</done>
|
||||
</task>
|
||||
|
||||
Reference in New Issue
Block a user