Product Decisions This Supports
- Localization roadmap and locale expansion. The package stores translations as rows (polymorphic
translatable relation) rather than columns, so adding a new language is a content operation, not a schema migration. This directly supports the decision to launch in N markets on a rolling basis instead of committing to a fixed locale set at design time.
- Build vs. buy on the translation layer. It replaces a custom
translations table + repository + cache-invalidation layer that most teams end up hand-rolling. For a PM, that is scope removed from the current sprint and a smaller surface area to QA.
- Content-model choices for core entities. Products, articles, categories, and CMS pages are the usual candidates for translatable attributes. The decision "do we model translated content as first-class rows or as JSON columns?" gets a defensible answer with a real implementation behind it.
- Admin/CMS feature scoping. Because translations are queryable per model and per field, a translation-editing UI, bulk import/export, and per-locale review queues become straightforward CRUD rather than bespoke plumbing. This informs whether the editorial tooling is a v1 or v2 commitment.
- Read-performance budgeting for localized pages. Built-in caching for translated attributes supports the decision to serve locale-specific pages from the primary datastore without adding a separate read model or CDN-level content sharding in the near term.
- Sequencing against a TMS. It clarifies the boundary: this package handles storage and retrieval in-app; it does not handle translator workflow, review states, or vendor sync. That keeps "integrate a TMS" as a separable, later decision.
- Multi-tenant and per-market content variants. Where the same entity needs different copy per market rather than per language, the relation-based model accommodates that without new columns or forked tables.
When to Consider This Package
Adopt when:
- Translatable content lives in the database on Eloquent models and changes through the product, not only at deploy time.
- The locale set is open-ended, market-driven, or likely to grow — the schema-churn argument is the strongest one here.
- You already run Laravel with morph relations and are comfortable with a relation-per-attribute read pattern.
- Read traffic on localized content dominates writes, so the caching layer earns its place.
- You want the option to swap implementations later; keeping translation access behind your own repository or accessor interface makes this a reversible bet.
Look elsewhere when:
- The need is UI strings and validation messages. Laravel's
lang files and __() are the right tool; this package is not.
- The locale set is small, fixed, and stable — two or three column-per-locale fields are simpler to query, index, and debug, and avoid an extra join on every read.
- Full-text search across translated fields is a core requirement. Cross-table search across a translations relation adds real complexity to search indexing and relevance work; a JSON-column approach often indexes more cleanly.
- Write volume is high or translations are edited concurrently by many editors; verify the cache invalidation behavior under concurrent writes before committing.
- You need translation memory, review workflows, versioning, or vendor handoff — that is a TMS, not this.
- Maturity risk is a real consideration. At roughly 72 stars with a single maintainer, this is an early-stage dependency. Adopt it behind an internal abstraction, pin the version, and read the source before relying on the caching semantics in production.
Alternatives worth a spike: spatie/laravel-translatable (JSON-column approach, larger community, different query tradeoffs) and Laravel's native JSON casting. A half-day evaluation across all three against your actual query patterns is cheaper than reversing the decision later.
How to Pitch It (Stakeholders)
For executives: This is a small, MIT-licensed library that removes a recurring piece of engineering work — storing and serving translated content — from every market launch. It lets us add a language without a database migration or a redesign of the content model, which shortens the lead time on entering a new market and keeps localization off the critical path. The direct cost is negligible and the license carries no commercial obligation. The main caveat is maturity: it is a young, single-maintainer project, so we should treat it as an internal implementation detail behind our own interface, which also keeps the exit cheap if we outgrow it. Recommendation: adopt on a bounded pilot with one content type, measure against the two obvious alternatives, and revisit at the next locale expansion.
For engineering: It is a morph-relation translation store with caching, for Eloquent models, in the same problem space as spatie/laravel-translatable but row-based rather than JSON-column-based. That means cleaner per-locale querying and indexing and no schema change per locale, at the cost of a join on translated reads. Before we commit: verify cache invalidation under concurrent edits, check how it behaves when a translation is missing for a locale (fallback semantics matter for UX), and wrap access behind our own repository so the choice stays reversible. Pin the version; the project is early.