Skip to content

Translation Manager — Improvement & Growth Plan

Package: capell-app/translation-manager · Kind: package · Tier: premium · Product group: Capell Admin · Bundle: admin · Status: Draft

Translation Manager is an admin-only Filament package (single surface: admin) that turns Laravel language files into an editable source-vs-target comparison grid at /admin/translation-manager. All domain behaviour lives in 17 thin Actions (src/Actions) that delegate to two pluggable contracts — TranslationSourceResolver (default ConfigTranslationSourceResolver, discovers app + Composer-package + vendor resources/lang dirs) and TranslationFileStore (default FileTranslationFileStore, reads/writes PHP and JSON lang files with override-path safety) — plus an optional TranslationAITranslator (default NullTranslationAITranslator). It owns no migrations, settings, or DB tables (database.migrations: false), and produces no frontend output. Third-party deps are minimal: lorisleiva/laravel-actions, spatie/laravel-data, spatie/laravel-package-tools. Nine Data classes (src/Data) carry every boundary payload — no anonymous arrays leak between layers.

The supports / soft-dependency pattern is implemented correctly and is worth highlighting. composer.json lists capell-app/ai-orchestrator under suggest (not require); capell.json lists it under dependencies.supports. TranslationManagerServiceProvider::registerOptionalAIOrchestratorModule() guards with interface_exists(AIOrchestratorModule::class) and class_exists(AIOrchestratorModuleRegistry::class) and only registers inside an afterResolving(AIOrchestratorModuleRegistry::class, …) callback, so the AIOrchestrator-typed classes in src/Integrations/AI/ are never autoloaded when the orchestrator is absent. This is the clean inversion of a hard dependency: the package runs standalone with a Null translator and lights up AI drafting only when the orchestrator is installed and binds a real TranslationAITranslator.

Current marketplace summary: “Manage Capell language files from one Filament page with side-by-side locale editing, missing and stale key checks, safe override writes, and optional reviewed AI drafting.” Screenshot coverage now matches the package contract: the marketplace card plus all five docs/screenshots.json captures are committed and declared in capell.json (empty state, comparison grid, create locale, duplicate locale, and optional AI translate selected).

  • CSV/XLIFF/PO import-export and publish-readiness are surfaced in the UITranslationManagerPage::getHeaderActions() now exposes CSV, XLIFF, and PO export actions, an import action with format selection, a publish-readiness notification action, a missing-key scan action, and Save. Coverage exercises those header actions through the page state and verifies streamed export/import/readiness behavior. — src/Filament/Pages/TranslationManagerPage.php, tests/Feature/Filament/TranslationManagerPageTest.php — Shipped

  • Needs-attention filtering is available — the page filter supports needs_attention and filteredEntries() returns missing, stale, and changed entries as the translator work queue. The filter selection is persisted between visits with the rest of the browser state. — src/Filament/Pages/TranslationManagerPage.php, resources/views/filament/pages/translation-manager.blade.php, tests/Feature/Filament/TranslationManagerPageTest.php — Shipped

  • Done/Shipped: raw grid controls were replaced with Filament-native controls. The page now wraps source/file/filter selectors in x-filament::input.wrapper + x-filament::input.select, uses x-filament::input.checkbox for selectable entries, wraps editable target textareas in Filament input wrappers, and receives stable entry indexes from TranslationManagerPage::loadEntries() instead of doing per-row array_search work in Blade. — resources/views/filament/pages/translation-manager.blade.php, src/Filament/Pages/TranslationManagerPage.php.

  • Source/locale/file/filter selection persists between visitsTranslationManagerPage stores the selected source, source locale, target locale, file, and filter in session, restores valid selections on mount(), and refreshes the readiness matrix without resetting the translator’s working context. — src/Filament/Pages/TranslationManagerPage.php, tests/Feature/Filament/TranslationManagerPageTest.php — Shipped

  • Done/Shipped: AIOrchestrator module registration is typed. registerOptionalAIOrchestratorModule() checks the optional AI Orchestrator classes exist, then registers inside an afterResolving(AIOrchestratorModuleRegistry::class, ...) callback against the typed registry and calls $registry->register(...) directly. — src/Providers/TranslationManagerServiceProvider.php — S

  • Accepted residual risk: large XLIFF exports are in-memory. exportCsv() uses php://temp; ExportTranslationEntriesToXliffAction builds a full DOMDocument and returns a string. This is acceptable for current admin language-file sizes and documented as an assumption; chunked XLIFF output should be a future scale task only if real translation sets exceed practical memory. — src/Actions/ExportTranslationEntriesToXliffAction.php — S

Tie-back to capabilities[] (16 declared) and standard translation-workflow norms:

  • Done/Shipped: inline missing-key detection / app scanning. ScanMissingTranslationKeysAction scans configured code paths for __() / @lang() references missing from language files, the page exposes a “Scan missing keys” header action, and the manifest declares the translation.files.code-missing-key-scan capability. — src/Actions/ScanMissingTranslationKeysAction.php, src/Filament/Pages/TranslationManagerPage.php, tests/Feature/TranslationManagerActionsTest.php.

  • Done/Shipped: translation memory / glossary. BuildTranslationMemorySuggestionsAction reuses exact source-value translations across files, TranslateSelectedEntriesAction returns memory suggestions before AI calls, and save-time glossary validation enforces configured terms per locale. — src/Actions/BuildTranslationMemorySuggestionsAction.php, src/Actions/TranslateSelectedEntriesAction.php, src/Support/FileTranslationFileStore.php, tests/Feature/TranslationManagerActionsTest.php.

  • Done/Shipped: machine-translation review/approval workflow. AI/memory suggestions land in pendingAiSuggestions instead of immediately overwriting target values; translators must accept or reject each suggestion before Save writes it. Coverage verifies rejected suggestions do not change target values. — src/Filament/Pages/TranslationManagerPage.php, tests/Feature/Filament/TranslationManagerPageTest.php.

  • Done/Shipped: PO / gettext import-export. The package ships ExportTranslationEntriesToPoAction and ImportTranslationEntriesFromPoAction, declares them in capell.json, exposes PO import/export in the page header action set, and covers round-trip import/export behavior. — src/Actions/*PoAction.php, src/Filament/Pages/TranslationManagerPage.php, tests/Feature/TranslationManagerActionsTest.php.

  • Done/Shipped: per-locale completeness dashboard. TranslationManagerPage builds readinessMatrix across target locales and the Blade page renders locale-level file, entry, missing, stale, changed, extra, fallback, and ready/needs-work state. — src/Filament/Pages/TranslationManagerPage.php, resources/views/filament/pages/translation-manager.blade.php, tests/Feature/Filament/TranslationManagerPageTest.php.

  • Done/Shipped: fallback-chain awareness. Comparison reads the configured Laravel fallback locale, marks empty target keys as fallback when fallback content exists, exposes a fallback filter/status label, and includes fallback counts in publish readiness. — src/Support/FileTranslationFileStore.php, resources/views/filament/pages/translation-manager.blade.php, tests/Feature/TranslationManagerActionsTest.php.

  • Done/Shipped: pluralization / parameter validation. Save validates that translated strings preserve source placeholders and pipe-delimited plural-form structure before writing. — src/Support/FileTranslationFileStore.php, tests/Feature/TranslationManagerActionsTest.php.

  • Done/Shipped: partial-override merge. Read-side comparison merges source and Laravel override files so per-key overrides match runtime behavior instead of fully shadowing the source file. — src/Support/FileTranslationFileStore.php, tests/Feature/TranslationManagerActionsTest.php.

Table-stakes already shipped: source/target grid, key-level stale detection when source-hash metadata exists, CSV/XLIFF/PO import-export, locale create/duplicate, safe override-path writes, fallback awareness, publish readiness, and optional reviewed AI drafting.

  • Done/Shipped: partial override files merge with source files. FileTranslationFileStore::readMerged() now combines package source values with Laravel override values for read/comparison paths, while write paths still target the safe override location unless package source writes are explicitly enabled. Coverage proves a partial lang/vendor/<ns>/<locale>/<file>.php override no longer hides un-overridden source keys. — src/Support/FileTranslationFileStore.php, tests/Feature/TranslationManagerActionsTest.php.

  • Done/Shipped: stale detection is key-level when metadata exists. Writes store per-key source hashes in sidecar metadata, and comparison prefers those hashes to decide changed versus stale, falling back to file mtime only when legacy metadata is unavailable. — src/Support/FileTranslationFileStore.php, tests/Feature/TranslationManagerActionsTest.php.

  • Done/Shipped: health label and admin query budget match reality. TranslationManagerHealthCheck now runs real diagnostics for the admin surface, service bindings, and required configuration, so the manifest health label names those exact checks instead of a generic install-health promise. The package remains file-backed and database-free, so performance.adminQueryBudget correctly stays at 0. — src/Health/TranslationManagerHealthCheck.php, capell.json, tests/Unit/ManifestRequirementsTest.php.

  • Accepted residual risk: file writes share the admin page permission. canAccess() gates on ExtensionsPage::canManageExtensions(), package_source_writes defaults to false, and package/vendor writes go through safe Laravel override paths. Finer-grained per-source write permissions would harden larger teams, but the current package scope treats translation editing as an extension-management permission. — src/Filament/Pages/TranslationManagerPage.php, capell.json permissions — security.

  • Done/Shipped: filesystem scans are request-local cached and invalidated after writes. FileTranslationFileStore now memoizes locale discovery, file listings, and comparison data per source/locale/file during the request, then flushes that source cache whenever translations are written. Source discovery was already memoized separately. Evidence: TranslationManagerActionsTest uses CountingFilesystem to prove repeat file/comparison reads do not rescan until SaveTranslationEntriesAction writes and invalidates the cache. — src/Support/FileTranslationFileStore.php, tests/Feature/TranslationManagerActionsTest.php, tests/Fixtures/CountingFilesystem.php — performance budget.

  • Done/Shipped: source discovery is request-local memoized. ConfigTranslationSourceResolver::sources() caches its resolved source list in resolvedSources, and the service provider binds the resolver as a singleton, so Composer package discovery and provider reflection run once per request. — src/Support/ConfigTranslationSourceResolver.php, src/Providers/TranslationManagerServiceProvider.php — performance.

  • Public-output safety: N/A but worth a guard test — the package has surfaces: ["admin"] and emits no frontend HTML, so the Capell public-output rules do not apply. No risk found; no action needed beyond noting it in the manifest (already frontend: [], cacheable: false).

  • Accepted residual risk: package UI strings ship in English only. The package is itself translatable through Laravel language files, but this repository only ships resources/lang/en/*. Additional bundled locales are a product/content task rather than an implementation blocker for the current package plan. — resources/lang/en — i18n.

  • Accepted residual risk: scale/concurrency tests remain future hardening. Coverage is genuinely strong across Actions, file store, page Livewire state, AI module, manifest, and Data boundaries, including path-traversal rejection, override-write defaults, partial-override merge, placeholder/plural/glossary validation, fallback status, translation memory, PO import/export, and page header actions. Remaining gaps are concurrent-write / last-write-wins on write() and very large file export memory. — tests/ — test debt.

Critique. The current summary and composer description diverge. capell.json summary is a 40-word feature dump (editor, workflow actions, stale detection, CSV+XLIFF, publish readiness, AI drafting, override writes) — comprehensive but unreadable as a one-liner, and it advertises CSV/XLIFF/publish-readiness that have no UI entry point (see §2), risking a “where is it?” support load. The composer description (“File-based Laravel translation management for Capell and Filament admin panels.”) is accurate but generic and undersells the differentiators (override safety, AI drafting, no-DB footprint).

Improved one-sentence summary: Edit, translate, and ship your Capell language files from one Filament screen — with side-by-side source/target comparison, stale-key detection, and AI drafting that never touches a database.

Improved 3–4 sentence description: Translation Manager gives admins a file-based editor for every Laravel language file in your Capell app and its packages, without migrations or new tables. Compare source and target locales side by side, spot missing and stale keys at a glance, and create or duplicate locales in one click. Edits to package and vendor strings are written safely to Laravel’s override paths, so upgrades never clobber your translations. Install AI Orchestrator to add one-click AI drafting for selected keys, with review before anything is saved.

Screenshot/media coverage. The marketplace card plus all five docs/screenshots.json captures are now committed and declared in capell.json: empty state, comparison grid, create-locale modal, duplicate-locale modal, and AI translate-selected. A short GIF of the create→translate→save loop would still improve the listing, but the static Marketplace screenshot contract is reconciled.

Pricing / tier / bundle. tier: premium, bundle: admin, proposedLicense: paid, requestedCertification: first-party, supportPolicy: priority — appropriate for a developer/agency tool. Position inside the admin bundle as the localisation utility. The no-DB, override-safe footprint is a genuine premium justification (low risk to install).

Cross-sell. Hard requires capell-app/admin + capell-app/core. Soft supports capell-app/ai-orchestrator — make this the headline upsell: “Add AI Orchestrator for AI translation drafting.” Bundle into an Extension Suite alongside seo-suite (translated SEO metadata per locale) and ai-orchestrator (MT). Cross-link the README’s “Best Used With” (currently Welcome Tour / Diagnostics / Foundation Theme) to add ai-orchestrator and seo-suite, which are far more relevant to the localisation buyer.

Differentiators / value props / target buyer. Differentiators: upgrade-safe override writes; zero database footprint; clean optional-AI integration via supports; XLIFF interop. Target buyer: agencies and developers running multi-locale Capell sites who need to localise package/vendor strings without forking vendor files. Value prop: “localise your whole app — including third-party packages — without migrations and without losing edits on upgrade.”

Keywords/tags (8–12): translation, localization, i18n, l10n, language-files, xliff, csv-import, filament, multilingual, ai-translation, vendor-overrides, capell-admin.

ItemBucketEffortImpactSection ref
Wire CSV/XLIFF import-export + publish-readiness into page header actionsDoneMHigh§2, §3
Ship the 4 required + 1 optional screenshots (fix screenshots.json mismatch)DoneSHigh§1, §5
Fix partial-override merge so editor view matches Laravel runtimeDoneMHigh§4
Done/Shipped: Correct manifest healthChecks label / adminQueryBudget to match realityDoneSMed§4
Done/Shipped: Memoize source discovery + locale/comparison filesystem scans. Evidence: file-listing and comparison caches are request-local and flush after translation writes, with focused filesystem-count coverage.DoneSMed§4
Done/Shipped: Rewrite summary + composer description; add ai-orchestrator/seo-suite cross-sell. Evidence: capell.json and package composer.json now use conservative editor-focused copy, declare/suggest AI Orchestrator and SEO Suite as optional pairings, README/docs copy matches shipped behavior, and ManifestRequirementsTest locks the manifest/composer wording.DoneSMed§5
Add placeholder/plural preservation validation on saveDoneMHigh§3
Add MT review gate (accept/reject AI drafts before write)DoneMHigh§3
Per-locale completeness/coverage matrix view (uses existing readiness data)DoneMMed§3
Key-level stale detection (replace file-mtime heuristic)DoneMMed§4
Persist last source/locale/file selection per userDoneSMed§2
Fallback-chain awareness (“covered by fallback” status)DoneMMed§3
Missing-key detection via code scanning of __()/@lang()DoneLHigh§3
Translation memory / glossary for consistent reuseDoneLMed§3
PO/gettext import-export for Crowdin/Weblate/Poedit interopDoneMMed§3
Done/Shipped: Replace raw blade grid controls with Filament-native selector, checkbox, and input-wrapper components, with stable page-provided row indexes instead of per-row Blade lookupDoneLMed§2