fix: multilingual i18n issues - #172
Conversation
…cale + drop cols)
…NOT NULL tightening
Companion-table migration generator (enable/disable), nextly_i18n_archive system table, snapshot-less .sql emission on the verbatim runner. Proven end-to-end on real sqlite. +22 tests, 0 new failures.
…tContext locale fields
…o base localization config block (validated + normalized), per-field/collection/single/ component localized flags, locale-resolution + field-classification helpers, and locale delivery to the admin (admin-meta + dashboard tile). +21 tests, 0 new failures.
Companion _locales runtime Drizzle generator, field->M1-spec bridge (deriveCompanionSpec), main-table diff+runtime omit localized fields, and the isCompanionTable pipeline-exclusion helper. Migration-owned companion (Option B). Pure/unit-tested; no boot/HMR wiring (that's M3b). +17 tests, 0 new failures.
…e + drop-guard noise
Persist collection/single localized flag in dynamic_collections/dynamic_singles (mirrors status; write path fully threaded), and exclude companion _locales tables from the migrate drift scope + drop-guard noise. Inert foundation (no consumer yet), no race. +4 tests, 0 new failures.
…d cols from main snapshot Thread the collection-level localized flag and defaultLocale through migrate:create so localized collections omit their translatable columns from the main-table snapshot and get a snapshot-less companion _locales migration. - planCompanionMigrations derives the transition (fresh create-only vs enable seed+drop vs none) purely from the previous snapshot's main table. - stripRelocatedDrops removes the main-table drop_column ops a companion enable migration already performs, avoiding a double-drop. - writeCompanionMigrationFile writes the planned up/down SQL verbatim (no paired snapshot); companions get a strictly-later timestamp so a fresh companion's FK to the main table resolves. - Mirror the localized threading into migrate:check so drift parity holds.
…-findings # Conflicts: # packages/nextly/src/domains/collections/services/collection-mutation-service.ts # packages/nextly/src/domains/dynamic-collections/services/dynamic-collection-registry-service.ts # packages/nextly/src/domains/singles/services/single-mutation-service.ts # packages/nextly/src/init/reload-config.ts
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
- strip internal review-finding identifiers from branch-added comments - add rationale comments to generated component localized flag and sqlite archive timestamp default - SingleForm: drop the exhaustive-deps suppression; keep latest defaults in a ref and guard the reset by a last-applied key so refetches don't reset edits - i18n:restore: resolve UI-built (ui-schema.json) entities so Builder-created collections/singles/components can be restored, not just code-config ones - i18n:restore --purge: bound the delete to the max archive id read so a concurrent archive write is not purged unrestored (+ race test) - align load-dynamic-tables SELECT-shape test with the localized column
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
- add fallbackLocale to the component populate params and thread it through every single/batch populate helper into overlayLocalizedComponent, so a no-fallback read (?fallback-locale=none) leaves untranslated embedded component fields blank instead of showing default-language text - forward fallbackLocale from the collection list/detail and single read paths into component population - overlay localized component fields for ?locale=all as language-keyed maps (mirroring the parent read) instead of skipping them, and decode JSON-backed values per locale
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
A localized single's main table omits translatable columns (they live in the companion `single_<slug>_locales`), so createDefaultDocument must not insert required/defaulted translatable values into the main row. Inserting them targeted a column that only exists on the companion and failed the first GET/PATCH auto-create of a localized single.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
A Schema-Builder localization toggle has no `nextly migrate` step, so the data move must run live. Previously the runtime reconcile only created an empty companion (enable) or no-oped (disable), stranding content. - add buildCompanionTransitionStatements: enable seeds the companion default locale from the existing main columns then drops them; disable restores the default onto main, archives other languages into nextly_i18n_archive, then drops the companion; a field change ADDs/DROPs localized columns - reconcile the companion `_status` column when Draft/Published is toggled on an already-localized entity (companionHasStatus introspection) - extract statement-array builders (up/down) so the runtime path runs them individually; add companionHasStatusColumn probe - single dispatcher: pass wasLocalized, ensure the archive table exists before a disable, and run the transition on a flag-only toggle (not just field edits) - skip localized fields when auto-creating a localized single's main row - cover enable seed+drop and disable restore+archive+drop with a sqlite test
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Apply the shared companion-transition planner to the component reconcile so a Schema-Builder localization toggle preserves data: - reconcileComponentCompanion routes enable → seed + drop, disable → restore + archive + drop, field change → ADD/DROP, using wasLocalized to detect the transition; ensures nextly_i18n_archive exists before a disable - updateComponent runs the reconcile on a flag-only Internationalization toggle (not only when fields change), so a settings-only enable/disable actually moves the data instead of stranding it - forward wasLocalized from the create and apply paths
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…ions Apply the shared companion-transition planner to the collection update + apply paths so a Schema-Builder localization toggle preserves data (previously enable created an empty companion and dropped nothing, losing default-language values, and disable did nothing, leaving content stranded). - generateCollectionUpdate: on an enable/disable transition, build the main ALTER from shared fields only (excluding columns localized in either state) and emit the transition SQL (seed+drop on enable, restore+archive+drop on disable, ADD/DROP on a field change); runs on a flag-only toggle too - inject the app default locale into DynamicCollectionService for the seed - collection-metadata-service: re-register the runtime schema on a flag-only localization toggle, not only on field edits - collection-dispatcher apply path: forward the request's localized flag (not the stale persisted one) and run the data-preserving transition + archive - ensure nextly_i18n_archive exists before a disable archives
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…ints, preview - companion `toColumn` now reuses the canonical descriptor snake_case, so a field with an uppercase acronym (URLTitle) resolves to the same column the DDL creates instead of misrouting reads/writes - add the `localized` column to the raw dynamic_components DDL (all dialects) so a fresh DB via the SystemTableService fallback accepts component creation - separate the collection companion migration statements with `--> statement-breakpoint` so the file runs as single statements (drivers with multi-statements disabled, e.g. MySQL, reject a multi-statement chunk) - forward `localized` into the single and component schema previews so the diff no longer reports phantom main-table changes for translatable fields
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Forward the active `locale` and `onLocaleChange` to EntrySystemHeader from SingleForm, so a localized single has a primary header language switcher — previously editors could not switch locales when the rail was collapsed or on narrow layouts, even though the page fetches and saves by locale.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
… DDL A disable companion migration re-adds the formerly-localized columns to the main table, so it must run BEFORE any main-migration DDL that references a restored column (e.g. an index on a now-shared field). Emit disable companion files with a timestamp before the main file, and enable/create-only ones after (their FK references the main table).
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
…-findings # Conflicts: # packages/nextly/src/domains/collections/services/collection-mutation-service.ts # packages/nextly/src/domains/components/services/component-query-service.ts # packages/nextly/src/domains/singles/services/single-query-service.ts
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Summary
Type of change
Related issues
Changeset
This repo uses Changesets. If your PR changes any publishable package under
packages/*, you must include a changeset:Then commit the generated
.changeset/*.mdfile.apps/*)Test plan
pnpm lintpnpm check-typespnpm buildChecklist
mainbranchScreenshots / recordings
Notes for reviewers
Summary by CodeRabbit
i18n:restoreto recover archived translations, plus safe localization enable/disable transitions.