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

Translate Bundle Laravel Package

lch/translate-bundle

lch/translate-bundle is a Laravel/PHP translation package for organizing multilingual content, managing locale files, and streamlining translation workflows. It helps keep strings consistent across languages and simplifies maintaining translations as your application grows.

View on GitHub
Deep Wiki
Context7

Getting Started

This package ships a LangSwitchHelper that builds the per-locale URL map behind a language switcher. As of v0.3.0 the returned paths array is keyed by language code rather than positionally indexed, which is the single most important thing to internalise before you write your first Blade loop.

Install and confirm the shape first. Add the package with Composer, then immediately inspect what the helper actually returns rather than trusting the README:

// routes/web.php or tinker
dd(\App\Support\LangSwitchHelper::paths()); // or the package namespace
// [
//   'en' => '/en/about',
//   'fr' => '/fr/a-propos',
// ]

Do this before touching any view. The keys are the contract; the order is incidental.

Where to look first, in order:

  1. The LangSwitchHelper class itself — especially the method that assembles paths. That method defines which locales appear, what happens for missing translations, and whether paths are absolute or relative.
  2. The package config (publish it if the package offers vendor:publish). Locale lists, default locale, and any URL-prefix behaviour usually live there.
  3. The package's own tests, if published — they are the most reliable documentation of edge-case behaviour (missing locale, current-locale exclusion, trailing slashes).

First use case — a header switcher. The canonical integration is a Blade partial rendered in your layout:

@php($paths = \App\Support\LangSwitchHelper::paths())
<nav aria-label="Language">
    @foreach ($paths as $lang => $path)
        <a href="{{ $path }}"
           hreflang="{{ $lang }}"
           @class(['active' => app()->getLocale() === $lang])>
            {{ strtoupper($lang) }}
        </a>
    @endforeach
</nav>

If that renders the right links on two locales, you have validated the v0.3.0 keying behaviour and can move on to the patterns below.

Implementation Patterns

Key-driven lookups instead of positional access. The new keying lets you ask a direct question rather than scanning:

$paths = LangSwitchHelper::paths();

// Current locale's counterpart URL, safe when the locale isn't offered
$current = $paths[app()->getLocale()] ?? url()->current();

This is the idiom to standardise on. It replaces the pre-0.3.0 pattern of array_values() plus a parallel locale array, which was fragile the moment the locale list changed order.

Pairing with hreflang and canonical tags. The keyed array is a natural fit for SEO head tags, because the key is the hreflang value:

@foreach (LangSwitchHelper::paths() as $lang => $path)
    <link rel="alternate" hreflang="{{ $lang }}" href="{{ url($path) }}">
@endforeach

Note the url() wrapper — confirm whether your configuration yields root-relative or absolute paths and normalise once, centrally, rather than in each view.

Wrap the helper in your own accessor. Even a two-line wrapper pays off:

class LocaleLinks
{
    public static function all(): array
    {
        return collect(LangSwitchHelper::paths())
            ->map(fn ($path) => url($path))
            ->all();
    }
}

Every call site now depends on your method, not the package's return shape. When the next release reshapes the array again — and v0.3.0 proves that is a live risk — you change one file.

Cache where the map is expensive. If path generation resolves routes or slugs per locale, it is a good candidate for Cache::remember() keyed by locale plus the current route name, invalidated on content save. Keep the cache key explicit about the locale set:

$key = 'langswitch:'.app()->getLocale().':'.request()->path();

Test the switcher as behaviour, not as an array. Assert rendered output, so a future re-keying does not silently break tests:

$this->get('/en/about')
    ->assertSee('href="https://example.test/fr/a-propos"', false)
    ->assertSee('hreflang="fr"', false);

Middleware and session interplay. If your app remembers a chosen locale in session, decide explicitly whether the switcher reads from app()->getLocale() (request-scoped, correct for the current URL) or from the session (correct for "preferred language" UI). Mixing them produces a switcher that highlights the wrong entry after navigation.

Gotchas and Tips

v0.3.0 is a breaking change for positional consumers. Any code that did $paths[0], $paths[1], array_shift($paths), or iterated with a separate $locales array and an index counter will now be wrong — silently, in the case of $paths[0], which returns null rather than throwing. Grep your codebase for numeric offsets on the helper result before deploying. foreach ($paths as $path) still works but discards the language code you now need.

array_merge semantics changed underneath you. Merging a keyed array with string keys overwrites, whereas merging a list appended. If you merge defaults with helper output — array_merge($defaults, $paths) — a locale present in both now takes the helper's value instead of producing a duplicate entry. Use $defaults + $paths if you specifically want the left side to win, or array_replace() for clarity.

Keys are preserved, order is not guaranteed. PHP keeps insertion order for string keys, so iteration order reflects however the helper built the array — not alphabetical and not your config order necessarily. If the UI must show languages in a fixed order, sort explicitly with uksort() against a config array, don't rely on the helper.

isset versus array_key_exists. If a locale has no counterpart path, the helper may store null rather than omit the key. isset($paths[$lang]) returns false for a null value and will send you down the fallback branch; array_key_exists() will not. Decide which semantic you want and use it consistently in the switcher and the hreflang block — otherwise the head tags and the visible nav disagree.

Membership checks need updating. in_array($locale, $paths) was already wrong but is now more obviously wrong: the values are paths. Use array_key_exists($locale, $paths) or isset(). This is the most common mechanical bug introduced by the release.

JSON serialisation to Alpine/Livewire. Passing the keyed map to the frontend with @js($paths) gives a JSON object. Numeric-looking language keys would be reordered by JavaScript's integer-key rule, but standard ISO codes (en, fr, pt-BR) are safe. If you ever use numeric locale identifiers, cast the keys to strings client-side or send an array of {code, path} objects.

Debugging checklist. When a link is missing or wrong: dd(LangSwitchHelper::paths()) at the top of the partial (not inside the loop), confirm the current locale via app()->getLocale(), then confirm the helper is seeing the locale list you expect from config. Nine times out of ten the array is correct and the locale has not been set by your middleware yet at render time.

Extension points worth knowing. Before forking, check for: a publishable config (locale list, URL prefixing, whether the current locale is excluded from the output), a container binding or facade you can swap for a subclass, and any events or resolver callbacks invoked during path generation. Overriding the resolver is almost always cheaper than overriding the helper, and it survives package updates.

Pin the version. Given a return-shape change at 0.x, constrain to ^0.3 in composer.json and treat 0.4 as requiring a read of the changelog. Semantic versioning gives you no guarantees below 1.0, and this release demonstrates the package is still settling its public API.

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