codezero/laravel-unique-translation
Laravel validation rule for ensuring translated attribute values are unique per locale. Works with translatable models and JSON columns to prevent duplicate translations in forms, imports, and admin panels.
What it is. codezero/laravel-unique-translation is a single-purpose Laravel validation package. It exposes a custom validation rule (UniqueTranslationRule, plus a string-form unique_translation) that asserts a value is unique within a specific locale key of a JSON column — e.g. title->en — rather than within a flat column. That is the gap it fills: Laravel's built-in unique rule cannot express "unique inside a JSON document." It targets schemas produced by translation packages like spatie/laravel-translatable.
Architecture fit. Excellent shape fit, narrow scope. It is a leaf dependency: one rule class, one service provider, zero runtime services, no middleware, no schema changes. It composes into the existing FormRequest / Validator pipeline, which is exactly where a TPM wants validation logic to live (declarative, testable, no controller coupling). It assumes — correctly — that translation storage is already JSON-in-a-column and does not attempt to own that concern. There is no architectural lock-in: removing it later is a one-line rule swap.
Integration feasibility. Low effort. Composer install, package auto-discovery, add the rule to the relevant FormRequests. No migrations, no config publishing required for basic use, no queue/worker implications. A competent Laravel engineer can wire it into an existing resource in under a day, including tests. The real cost is not integration — it is the surrounding correctness and performance work described below.
Technical risk.
where, so behavior varies across MySQL 5.7/8, PostgreSQL (json vs jsonb), SQLite, and SQL Server. Any driver that does not support the path syntax fails at query time, not at boot time — a latent production-only failure.Key questions for the maintainer / spike.
where clauses, ignore-by-ID, withTrashed) — and if not, is there a supported extension point?null, empty string, and case/collation differences treated for uniqueness?Stack fit. Clean, provided we are on Laravel 9+ and PHP 8.1+, and provided the translation columns are genuine JSON (or jsonb). It pairs naturally with spatie/laravel-translatable; it does not require it. If we are on a driver with weak JSON-path support (older SQLite, some SQL Server configurations), stop here — the package is the wrong tool and a normalized translations table would be better.
Migration path. No data migration. This is a validation-layer addition only; existing rows are untouched and duplicates already in the database will not be flagged retroactively. If the business requires that existing data be clean, that is a separate data-audit and backfill workstream — scope it explicitly or it will surface as an unplanned ticket after launch.
Compatibility and isolation. Pin the version explicitly in composer.json rather than floating. Given the low adoption and single-maintainer profile, wrap the rule in our own thin App\Rules\UniqueTranslation (or a small TranslationsUnique helper) that composes the package rule and adds our tenant/soft-delete scoping. That gives us one seam to patch, replace, or fork without touching every FormRequest. Budget roughly one engineering day for the wrapper, plus CI coverage on each database engine we support.
Sequencing.
Maintenance. Very low surface area — a few hundred lines. The realistic maintenance event is a Laravel major upgrade breaking the rule's internals or a DB engine upgrade changing JSON semantics. Mitigate with the wrapper seam and a pinned version. Total ongoing cost is close to zero until it isn't, which is the classic small-package risk profile.
Support. Community-only, no SLA, effectively a bus factor of one. For a low-blast-radius validation rule this is acceptable; for anything customer-facing and revenue-critical it should be treated as "unsupported code we own," with a named internal owner. Do not adopt it if our policy requires vendor-backed dependencies.
Scaling. The dominant operational risk. Validation runs synchronously on the write path, so latency added per request is index lookup (fast) or table scan (catastrophic). At scale this becomes a p95 write-latency problem that is invisible until traffic grows. Enforce the functional index as a launch prerequisite, monitor write latency on affected endpoints, and set a clear threshold (e.g. table row count) beyond which the rule must be re-evaluated. Also note this adds a query per locale per record on bulk imports — batch import paths should be exempted or reworked.
Failure modes.
Ramp-up. Trivial for the team — an engineer familiar with Laravel validation understands the package from the README in under an hour. The onboarding cost is not the package, it is the tribal knowledge about which tables need functional indexes and what the uniqueness domain is per resource. Document both alongside the adoption.
Recommendation. Adopt with guardrails: pin the version, wrap the rule, confirm driver support in a short spike, and treat the functional index as a hard prerequisite rather than an optimization. The package earns its place because it solves a real validation gap with almost no architectural weight; the risks are all operational (indexing, scoping, concurrency) rather than structural, and each is cheap to mitigate if handled before launch rather than after.
How can I help you explore Laravel packages today?