Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Translatable Laravel Package

dimsav/laravel-translatable

Add multi-language support to any Eloquent model without touching your schema. laravel-translatable stores translations in a dedicated table and lets you read, write, and fall back between locales using familiar Eloquent syntax, making it ideal for multilingual apps and APIs.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Release review — v10.0.0

The first release after a long dormancy. Three changes, one of which is materially risky and none of which address the finding that drove the original assessment.

  • Locales helper class (#574) — consolidates locale list, fallback, and default-locale resolution into a single first-class object instead of config reads scattered through the trait. Additive and low risk; a useful seam for us if we ever fork (fewer places to patch locale logic). Watch for two sources of truth: the helper and the trait must both read config/translatable.php identically, or locale behavior diverges depending on code path.
  • getRelationKey() fix (#575) — correctness fix. Behavior change for any model that overrides the translation relation name or $translationModel; audit those before upgrading.
  • Drop custom save() in favor of a saved event listener (#567) — the material change, and the reason this must be treated as breaking. Translation persistence moves from an overridden save path into Eloquent's saved event. Translation writes now depend on events actually being dispatched: saveQuietly(), Model::withoutEvents(), insert()/upsert() bulk paths, seeders, and any event-suppressing wrapper will persist the parent row and silently drop the translations. Observer ordering relative to translation writes also changes.
  • No compatibility work in the release. No PHP constraint bump, no Laravel support statement, no CI or security-policy change. The "not installable on a modern baseline" finding is unresolved, not overturned. The 10.0.0 number is a semver major — do not read it as "Laravel 10 support."

Architecture fit

  • Pattern unchanged: per-model translation tables (posts + post_translations) accessed through a Translatable trait and a $translatedAttributes array. Normalized side-table design, not JSON-column.
  • Good fit where translations must be indexed and queried per locale (unique slugs per language, whereTranslation('slug', ...), locale-scoped listings). Weaker fit for cross-locale full-text search or teams standardizing on JSON columns (spatie/laravel-translatable).
  • The new Locales helper slightly improves the fit for multi-locale apps: locale configuration becomes an addressable object rather than implicit config reads, which helps when locale lists are runtime-driven. It also adds one more coupling point between our code and the package.
  • Coupling is still moderate: opt-in per model, but it leaks into controllers, form requests, and per-locale validation rules. Adoption remains a schema and application-layer decision.

Integration feasibility

  • Previously: effectively not installable on Laravel 8+ / PHP 8.1+ without a fork or alias. This is now the single decision-gating unknown. Read the require block of v10.0.0 before anything else. Three outcomes: (a) it supports our baseline — dimsav is viable again and the substitution argument weakens to a preference; (b) it does not — the successor swap stands as the recommended path; (c) partial support — successor wins on maintenance cadence and docs.
  • Even under (a), astrotomic/laravel-translatable remains the safer default: same schema, same trait semantics, current docs, and active compatibility work. Revived upstream does not erase several years of missing maintenance; it only makes the fork contingency less urgent.
  • Mechanically, upgrade from a pinned 9.x to 10.0.0 is a major bump requiring: dependency resolution check, relation-key audit, event-suppression audit, and a re-run of the translation test suite. No data migration — the table layout is unchanged.

Technical risk

  • Write-path regression (new, highest severity). The saved-event refactor means translation persistence is now conditional on event dispatch. Any code path that suppresses events — saveQuietly(), withoutEvents(), raw bulk inserts, some seeder and import patterns — will write the parent and lose the translations with no error. This is a silent-data-loss class risk and it is new in this release.
  • Upstream status: unverified (downgraded from "archived", not cleared). One release after extended dormancy is a signal, not a commitment. There is no stated support policy, no security process, and no evidence of sustained cadence. Keep the fork-ownership question open; re-evaluate after two or more releases across two quarters with a documented maintenance posture.
  • Major-version churn. If we pinned 9.x, v10.0.0 is a breaking upgrade we must absorb and test. If we adopt v10, we are on a version with one release of history and a behavioral change that has not seen broad production exposure.
  • Relation-key behavior change. Low severity, bounded to models with custom translation relations, but it is a silent correctness issue if missed.
  • Silent locale fallback remains a design property, not a bug: content renders in the default language rather than erroring. Must be an explicit product decision, per content type.
  • Schema risk unchanged: each translated model adds a table and a join; retrofitting unique constraints (locale-scoped slugs) after data exists is a migration with data-repair work.
  • Mitigating constant: the API surface is small and the pattern is widely mirrored, so knowledge is transferable and an exit remains cheap.

Key questions

  1. What does v10.0.0's composer.json actually allow — PHP and Laravel constraints? This single fact decides whether the archived-dependency disqualifier still stands.
  2. Is there any evidence of sustained maintenance — commit cadence, issue triage, a security policy — or is v10.0.0 a one-off?
  3. Does our codebase or its seeders/importers use saveQuietly(), withoutEvents(), or bulk insert paths on translatable models? Any "yes" turns the saved-event refactor into a data-loss risk.
  4. Do any models override the translation relation key or $translationModel, and therefore depend on the pre-fix getRelationKey() behavior?
  5. Who owns the fork if we adopt it? Named engineer, not a team.
  6. Do we need per-locale indexable columns (slugs, SEO metadata, searchable titles), or is JSON-column storage sufficient?
  7. Is silent fallback acceptable for our content types, or do we need explicit "translation missing" states in the API/UI contract?
  8. Why did this score 9.475 technically while opportunity scored 4.9? Confirm the "well-built but strategically marginal" reading rather than treating a version bump as strategic revival.

Integration Approach

Stack fit

  • Best fit: an existing Laravel application with Eloquent-centric models, MySQL/Postgres, and a modest number of translatable entities (3–10 models).
  • Poor fit: greenfield projects, API-first services on current Laravel, or teams without capacity to own a fork.
  • Recommended posture is now conditional rather than absolute:
    • If v10.0.0 supports our baseline and upstream shows sustained cadence: dimsav becomes usable, but astrotomic/laravel-translatable still wins on documentation and compatibility work. Prefer the successor unless we have a specific reason to stay.
    • If v10.0.0 does not support our baseline: substitution, as originally recommended. Same schema pattern, same trait API, no data migration.
  • If already running the successor: no action. Track whether the two projects converge or diverge, since that affects future migration cost in either direction.

Migration path — dimsav 9.x → 10.0.0 (only if the compatibility gate passes)

  1. Diff the require block against our PHP/Laravel baseline. If it fails, stop and route to the successor swap instead.
  2. Inventory translatable models; snapshot config/translatable.php (locales, fallback, use_property_fallback). Verify the new Locales helper resolves the same values the trait previously read directly — test both paths explicitly.
  3. Event-suppression audit before upgrading: grep for saveQuietly, withoutEvents, withoutObservers, raw insert/upsert, and seeder/import patterns touching translatable models. Each hit is a candidate for silent translation loss under the new saved-listener design.
  4. Audit models that override the translation relation key or $translationModel; add explicit tests for relation resolution.
  5. Run the suite plus targeted tests: translate(), translateOrNew(), getTranslation(), whereTranslation(), toArray() shape, and — new — a saveQuietly() test that asserts the documented behavior, whatever we decide it should be.
  6. No data migration required; table layout is unchanged. Deploy behind a flag, validate against production-shaped data on staging, then roll forward.

Migration path — dimsav → successor (unchanged, still the default)

  1. Inventory models, count translation rows, snapshot config.
  2. Swap the dependency; replace Dimsav\Translatable\Translatable imports; add the translatable contract where required.
  3. Re-publish and diff config; verify locale list and fallback semantics are byte-identical.
  4. Run the suite plus the same targeted tests listed above, including serialization shape.
  5. No data migration required — the single biggest argument for the successor over switching storage strategies.
  6. Feature-flag, verify on staging, roll forward.

Compatibility

  • Database: MySQL 5.7+/8, Postgres 11+ fine. Watch composite index length on MySQL for (parent_id, locale, slug) under utf8mb4.
  • Events: with the saved-listener design, translation writes are now ordered relative to observers, created/saved hooks, and transaction boundaries. Any observer that reads translations in a saved handler may now see stale or missing data depending on listener registration order.
  • Serialization: confirm the translations array shape is unchanged before and after, regardless of path.
  • Eager loading: preserve with('translations') everywhere; the lazy per-accessor load remains an N+1 hazard.

Sequencing

  1. Gate (0.5 day): read v10.0.0 composer.json; check upstream cadence. Output: dimsav-upgrade vs. successor-swap.
  2. Spike: one model, one locale pair, end-to-end read/write through the API layer (2–3 days).
  3. Event-suppression audit and relation-key audit (1 day) — new, and blocking.
  4. Schema review: unique constraints, index plan, cascade-delete on translation rows.
  5. Rollout to remaining models, lowest read-traffic first.
  6. Admin/authoring tooling last — depends on stable write semantics.

Operational Impact

Maintenance

  • Budget shifts rather than disappears. Previously 1–2 engineer-days per quarter for internal ownership. If upstream is genuinely alive, that drops — but only after cadence is proven over two quarters, not on the strength of one release. Keep the fork contingency written down with a named owner and a sunset date either way.
  • Tracking a moving upstream has its own cost: major-version upgrades (like this one) require audit and test cycles. A frozen dependency is cheaper to run and more expensive to escape; an active one is the reverse. Choose deliberately.
  • Documentation cost is unchanged: internal runbooks (locale config via the new Locales helper, adding a translated model, adding a locale) are still ours to author.

Support

  • Marginal improvement: an active repository raises the odds that issues get triaged. Unproven — there is no stated support commitment and no security disclosure process. Treat community Stack Overflow coverage as the primary support channel, as before.
  • Escalation remains "the one engineer who has touched it." Mitigate with a one-page design doc and pairing on the initial integration.

Scaling

  • Read scaling: each translated attribute access may trigger a translation load. Enforce with('translations') as a code-review rule; measure query counts per endpoint before and after the change.
  • Data scaling: rows multiply by locale count. Eight locales × 1M records = 8M translation rows — fine with proper composite indexes, but locale-scoped queries must hit (locale, ...) indexes or listings degrade.
  • Join depth: filtering/sorting on translated columns requires joins; if search-by-translated-field is near-term, evaluate a dedicated search index rather than SQL joins.
  • Schema scaling: N translated models = N extra tables plus admin complexity. Past ~15 translated models, revisit the JSON-column approach.
  • Write scaling: the saved-listener path changes the cost and timing profile of writes and interacts with bulk operations — re-measure import throughput, not just read paths.

Failure modes

  • Silent translation loss via suppressed events (new, highest severity). saveQuietly(), withoutEvents(), bulk inserts, and some seeder/import patterns persist the parent and drop translations with no error. Mitigation: static-analysis or grep-based lint rule, integration tests on quiet-save paths, and a row-count reconciliation check in import jobs.
  • Observer ordering drift (new). Code reading translations inside saved handlers may see stale data depending on listener registration order. Mitigation: contract tests on any observer that touches translations.
  • Locale config split-brain (new). The Locales helper and the trait must resolve the same config; divergence produces locale-dependent behavior differences. Mitigation: a single test asserting both paths return identical locale sets and fallbacks.
  • Relation-key regression. Models with custom relation keys may resolve the wrong translation. Mitigation: explicit tests for those models.
  • Silent locale fallback: content renders in the wrong language with no error. Mitigation: translation-completeness reporting per locale as a content-ops metric.
  • Missing translation → null: unguarded accessors throw in views/serializers. Mitigation: default-value conventions and request-level tests.
  • Unique constraint collisions: slug uniqueness not scoped by locale, or scoped incorrectly, failing during bulk import.
  • Serialization drift: toArray() shape changes break mobile clients silently. Mitigation: contract tests on API responses.
  • Composer/PHP upgrade breakage: softened to "unverified" — the upgrade may still block framework upgrades and delay security patches app-wide. Verify before assuming this is resolved.
  • Orphaned rows: deleting a parent without cascade leaves stale translations that pollute search and admin listings.

Ramp-up

  • Low for Eloquent-fluent engineers: trait + side table + locale key is learnable in under a day.
  • Non-obvious learning stays concentrated in three places: fallback semantics, eager-loading discipline, and per-locale validation in the authoring workflow. Add a fourth for v10.0.0: never use event-suppressing saves on translatable models unless the behavior is explicitly verified.
  • New-hire risk remains asymmetric: abundant community material for the pattern, thin current material for the package. Point people at the successor's docs — the API is close enough to serve as a learning resource, though the saved-event write semantics now differ and must be flagged.
  • Onboarding artifact: a one-page "adding a translated model" checklist — trait, $translatedAttributes, migration with composite unique index, factory states per locale, API contract test, and the event-suppression rule.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource