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

Localization Laravel Package

webx-ui/localization

Webx UI Localization brings localization tools to your Laravel UI. It offers helpers and components for managing translations, switching locales, and keeping multilingual interfaces consistent, so you can ship apps that feel native across languages with less effort.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. This is a conventional Laravel locale vertical — locales table + Locale model, a Locales service facade, a HasTranslations trait that stores all locales as a {"en": "...", "uk": "..."} JSON map in one column, $table->translatable() blueprint macros, two middleware aliases (webx.locale, webx.panel-locale), a OneSpellingPerAddress route guard, and two Artisan commands. That conventionality is the TPM-relevant fact: the work is estimable by any Laravel team without a spike, and no exotic infrastructure (queues, external services, exotic drivers) enters the critical path.

The one item that requires product sign-off before sprint one is the single JSON column per translated attribute in place of a side translation table. Reads and writes stay single-row, but per-language uniqueness and indexed filtering move out of the database and into application scopes (whereTranslation, whereTranslationLike, orderByTranslation). Leaving JSON maps for per-locale tables later is a data migration, not a config change. Assign a named owner, record the decision with content-volume and reporting assumptions, and gate it before the first translated row is written.

Integration feasibility. The package is small; its value is not, and that asymmetry is the main planning hazard. /api/cms/locales and translation endpoints live in webx-ui/module-admin; translated address uniqueness lives in webx-ui/routing; cache invalidation rides on webx-ui/cache (CacheGroups::LOCALES). The planning unit is therefore a three-to-four package cluster — budget, version pinning, and upgrade rehearsals must cover the cluster, not this artifact alone. One genuinely useful bootstrap property: until the locales table exists, the service answers from config('webx-localization.locales'), so install-before-migrate does not fail. That materially de-risks phased rollouts and lets config and middleware land ahead of the schema.

Technical risk, ranked for a steering committee:

  1. Read-only split, 0 stars, 0 dependents, single vendor, bus factor of one. This is a published artifact of webx-ui/webx-ui (php/packages/localization); issues and PRs route upstream with no SLA, and there is no independent adoption to learn from. Every upgrade is "wait for upstream, then re-pin." Frame the decision as adopting webx-ui as a platform, not adopting this package à la carte — the risk read is wrong in both directions otherwise.
  2. Model-enforced invariant, not a schema constraint. "Exactly one default locale" is normalised by the Locale model on save. Concurrent saves or raw SQL can produce two defaults or a denormalised code; recovery requires a cache clear. Acceptable, but it is an operating rule the team must actually follow, and it belongs in the runbook.
  3. No per-language unique index. A JSON column cannot enforce unique translated slugs. Any workflow assuming database-level address uniqueness will be surprised. Slug localization is explicitly webx-ui/routing's scope — scope it as a separate workstream or you will promise something this package cannot deliver.
  4. Cache coherence. lang edits require webx:locales:clear (or WEBX_LOCALIZATION_CACHE=false in dev). Stale translations are the most probable day-one support ticket; plan a deploy hook, not a wiki page.
  5. Vendor-patch temptation. Editing vendor/webx-ui/localization is unsupported; a missing seam is framed as an upstream bug. Good discipline, but it converts every gap into an upstream dependency with no committed turnaround.

Key questions for the maintainers before committing.

  • Supported Laravel/PHP range — undocumented in the source excerpt.
  • Minimum MySQL/Postgres versions and JSON support, plus the exact SQL emitted by whereTranslationLike — index-assisted or full scan?
  • Is the split tagged in lockstep with the monorepo, and where do issues actually route and get triaged?
  • Does panel() dictionary generation have a size ceiling when 'namespaces' is widened across modules?
  • What is the versioning and support policy given zero dependents?

Integration Approach

Stack fit. Native Laravel, no impedance mismatch. Config publish tag webx-localization-config, per-module lang publish tags (webx-admin-lang plus each module's own -lang), middleware aliases registered by the provider, blueprint macros global after boot. The package's ten validation languages are appended behind the application's own lang/ strings, so app overrides win. Confirm that ordering in a half-day spike rather than assuming it — it determines whether our product copy or vendor copy ships, and it is the cheapest possible test of a claim the whole content plan rests on.

Migration path. Greenfield: publish config → define 'locales' → php artisan webx:locales:seed → register middleware → adopt HasTranslations on new models. Brownfield: add $table->translatable('title', 'body') as nullable columns, backfill existing single-language values into {"<default>": "<value>"} maps, then switch reads to forLocale() / getTranslations(). Run a dual-read window — read through the trait while the old column is still authoritative — before dropping legacy fields. Budget the backfill as its own ticket with a rollback script; it is the one irreversible step in the sequence and it touches production content.

Compatibility. Two boundaries need explicit product acknowledgement, not engineering footnotes. First, translated slugs are out of scope and belong to webx-ui/routing — if the roadmap promises localized URLs, that is a second workstream with its own estimate. Second, the 'strategy' => 'prefix' | 'header' | 'none' switch lets you defer the SEO/URL-structure debate, but it is a launch-time decision with permanent redirect implications, not a toggle you flip post-launch. OneSpellingPerAddress hard-codes the consequence: unknown prefix → 404, default prefix → 301 unless prefix_default is on. Changing strategy after launch means a redirect-map project.

Sequencing. Five gates, roughly in order:

  1. Platform decision — adopt webx-ui or not. Everything downstream is contingent; do not let the team start on this package first.
  2. Storage-model sign-off — JSON map vs per-locale tables, with content volume and reporting needs in hand. One-way door; named owner; recorded.
  3. Locale-set and fallback policy — how many public languages, how many admin languages (separate config lists), and whether missing strings fall back (ship faster, mixed-language pages) or surface (ship slower, cleaner). The default becomes your policy unless you intervene.
  4. SEO/URL decision — strategy plus prefix_default, locked before launch.
  5. Panel translation as its own budget line — webx.panel-locale is configured independently of webx.locale, which lets you plan "public site in N languages, admin in 2." But panel translation costs scale with modules × languages in vendor content, not with our code — that is a recurring line item, not a one-time engineering task.

Operational Impact

Maintenance. Low code surface, high coupling. The package itself will rarely need attention; keeping it in lockstep with the monorepo siblings (module-admin, routing, cache) is the ongoing cost. Set a re-pin cadence tied to upstream tags and rehearse one upgrade on a branch before the first production release so the second one isn't a discovery. Add a standing rule to the engineering handbook: never edit vendor/webx-ui/localization; report the gap upstream and track it. Without that rule, the first missed seam becomes a silent fork.

Support. Two recurring ticket classes are predictable enough to pre-write runbooks for. (1) Stale translations — content edited, cache not cleared; fix is webx:locales:clear, prevention is a deploy hook. (2) Content team deletes a language row to "hide" it — the docs are explicit that the correct action is is_active = false, because translated text persists in every JSON map and a row deletion orphans the corpus. Underwrite a product policy from that: we can retire a language from the UI without losing the content. It matters for re-launch decisions, archival obligations, and content-team trust. Encode it as a permission restriction, not a training slide.

Scaling. The scaling ceiling here is query shape, not traffic. Reads and writes are single-row, which is excellent; but whereTranslation/orderByTranslation will not match native-column performance under heavy filtering, sorting, or aggregation on translated fields, and whereTranslationLike may be a full scan. The package suits read-heavy public pages with caching in front and thousands — not millions — of rows across a handful of languages. Set an explicit tripwire: if analytics or per-language reporting on translated content becomes a roadmap item, that is the trigger to revisit the storage model, and the earlier JSON-map decision record should name it as the revisit condition. Also ask for the emitted SQL before launch so the first slow query isn't the discovery.

Failure modes, with the ones worth pre-planning:

  • Two defaults or a denormalised code from a raw-SQL or concurrent-save bypass. Detection: a health check asserting exactly one default. Recovery: normalise via the model, then clear the locale cache. The schema will not catch it for you.
  • Stale translation cache after a content deploy. Highest-probability day-one incident; mitigate with a post-deploy cache clear in the pipeline.
  • Missing per-language slug uniqueness. Manifests as duplicate or colliding addresses discovered by SEO or by a customer, not by the database. If the product requires per-language unique slugs, the storage model is wrong for us — that is a pre-launch determination, not a post-launch fix.
  • Unknown-prefix 404s and default-prefix 301s misconfigured at launch. OneSpellingPerAddress is a tested invariant — don't reimplement it — but the prefix_default choice must be exercised in staging with real URLs, because the redirect implications are permanent.
  • Upstream stall. A needed fix sits in an unresponsive monorepo. Mitigation is scope discipline: keep the package's surface narrow, prefer config and published lang files over code changes, and flag any needed vendor change as a schedule risk rather than absorbing it silently.

Ramp-up. Steepest curve is not the package — it is the surrounding model. Allocate roughly: half a day to verify the lang/ append-behind ordering; one day to stand up config, migration, seed, and middleware in a scratch environment; two to three days for the brownfield backfill with dual-read on a real dataset; then a dedicated slice for the panel dictionary (panel(), 'namespaces', webx.panel-locale) that scales with module count. Engineers need three things up front that the docs make easy to miss: the storage model is JSON-in-one-column and the trait is the only supported read/write path; the locales table wins over config after migration and config is seed-only; and the extension surface is exactly the published config, published lang tags, and model traits — a missing seam is a bug to report, not a workaround to build.

Bottom line for the steering deck. Low, predictable cost profile — MIT, no vendor contract, no per-seat fees — against a real platform-coupling risk from a zero-adoption, single-vendor, read-only split. Adopt as part of a webx-ui platform decision, not as an isolated bet. Lock the storage model and the URL strategy before the first translated row or the first indexed page. Treat translated-slug handling and panel translation as separately scoped workstreams with their own estimates and owners.

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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager