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

Loco Importer Bundle Laravel Package

purjus/loco-importer-bundle

A Symfony bundle for importing translations from Loco into your application. It streamlines pulling localization data from the Loco API into your project's translation files. Early-stage package with limited adoption; a useful starting point for Loco-to-Symfony translation sync.

View on GitHub
Deep Wiki
Context7

Getting Started

First, a framing note: despite the brief, purjus/loco-importer-bundle is a Symfony bundle, not a Laravel package. There is no service provider, no config/loco.php, and no facade. A Laravel developer will either (a) use it inside a Symfony service/legacy app, or (b) more likely copy the ~40 lines of logic it wraps into an Artisan command. The underlying mechanism is trivial and documented: Loco's export endpoint is a plain authenticated GET.

Minimal steps (Symfony context):

  1. composer require purjus/loco-importer-bundle — pin the version; the last tag is from Feb 2020, so expect Symfony 4.x/5.0-era constraints and check composer why-not symfony/framework-bundle 6 before committing.
  2. Register it in config/bundles.php: Purjus\LocoImporterBundle\LocoImporterBundle::class => ['all' => true].
  3. Pull your API key from Loco → Project settings → API keys. Put it in .env as LOCO_API_KEY, never in the committed YAML.
  4. Create config/packages/loco_importer.yaml with the key, the target translations directory, the export format, and the locales you want.
  5. Run bin/console list loco (or debug:container --tag=console.command) to discover the actual command name — the bundle's command/service IDs are not documented in the README, so read the source. It will be something like loco:import.

First use case: pull all locales into translations/ once, before you touch anything else, so you have a baseline to diff against. Do it on a clean branch and inspect git diff — that diff is the fastest way to learn what the bundle actually writes and whether it matches the format your translator expects.

If you're in Laravel and just want the behaviour, skip the bundle:

Http::get("https://localise.biz/api/export/locale/{$locale}.json", [
    'key' => config('services.loco.key'),
])->throw()->body();

That is 90% of the package's value. Use the rest of this document for the operational details that the one-liner hides.

Implementation Patterns

Build-time, not request-time. This is a deploy/dev tool. Wire it into your pipeline (composer deploy, a GitHub Action step, a Forge/Envoyer deploy hook) and run it before assets are compiled and before caches are warmed. Never call the Loco API from a web request.

Export per locale, in a loop. Loco exposes both export/all.{format} and export/locale/{locale}.{format}. Prefer per-locale in a loop so a single failed locale doesn't nuke the whole set, and so you can skip/pin locales independently. Add a short retry with backoff — Loco returns 429s on bursty free-tier usage.

Pick format per consumer, not per project. Typical split:

Consumer Format Note
Symfony translator symfony / xliff matches default loader
Laravel lang/ json or php php gives you array files directly
Vue/React frontend json (nested or flat) configure nesting in Loco, not in code
Mobile arb / xliff separate export target

If you have both a backend and a JS frontend, export twice into two directories with two commands. Do not try to make one format serve both.

Use Loco tags to split domains. Tag assets in Loco (messages, admin, emails) and export with the tag query parameter into separate files. This lets you refresh only the domain you're working on without churning the whole translations/ tree — much friendlier to code review.

Keep a hand-maintained overlay. Exports are authoritative for anything managed in Loco, which means anything you add locally gets silently deleted on the next import. Two working patterns:

  • Put locally-authored keys in a separate domain/file that the importer never touches, and let the framework's fallback chain resolve them.
  • Or run the import into a translations/.loco/ directory and merge during a build step, so the raw export is a build artifact and never a source file.

CI pattern. Run the import in CI, then git diff --exit-code translations/ and fail the build if there's drift. This catches "someone edited translations in Loco and forgot to commit" — which is the single most common failure mode with any translation-sync tool. Add --dry-run behaviour yourself if the bundle lacks it (write to a temp dir, diff, then move).

Laravel port sketch. If you're rebuilding it: an Artisan command loco:import {--locale=} {--tag=}, Http::retry(3, 200), write to lang/{locale}/{domain}.php via var_export, then Artisan::call('optimize:clear'). Register it in the deploy script alongside config:cache. That's the whole package.

Cache invalidation is mandatory. Symfony compiles catalogues into var/cache/{env}/translations/. After an import you must bin/console cache:clear (or cache:pool:clear cache.global_clearer) or you will spend twenty minutes debugging "the translation didn't update". In Laravel there's no compiled catalogue, but opcache and optimize:clear still matter if you're on a long-running worker (Octane).

Gotchas and Tips

The package is effectively unmaintained. One star, zero dependents, last release Feb 2020. Treat it as vendored code: pin the exact version, and be prepared to fork it (it's small) the first time a Symfony major bump breaks it. Check whether it ships a DependencyInjection/Configuration.php and Extension — a bundle without those is a thin command wrapper, and forking is an afternoon.

Locale code mismatch is the #1 silent bug. Loco uses pt-BR, zh-Hans; Symfony uses pt_BR, Laravel uses pt_BR for file names but accepts pt-BR in App::setLocale. A str_replace('-', '_', $locale) in your command config usually fixes it — but do the mapping explicitly in the bundle config rather than discovering it from missing translations in production.

Removed keys disappear from exports. If a translator deletes an asset in Loco, the next export won't contain it, and any local file using that key now renders the raw key string. Grep your templates for the key before deleting in Loco, or keep exports additive and reconcile by hand.

Message format mismatch. Loco supports both Symfony-style %name% placeholders and ICU {name}. The export format you choose does not translate placeholders for you. If your translator writes ICU and your Symfony translator uses %name%, you get literal {name} in output. Standardise in Loco's project settings, not in the code.

The API key leaks easily. The bundle likely takes the key via config, and it's tempting to hardcode it in config/packages/loco_importer.yaml because env-var resolution inside a bundle's config tree can be finicky. Use %env(LOCO_API_KEY)% and verify it resolves with bin/console debug:config loco_importer (adjust the alias to whatever the bundle registers — debug:config will error and list valid aliases if you guess wrong).

Debug by bypassing the bundle. When an import "does nothing", curl the endpoint directly:

curl -sS "https://localise.biz/api/export/locale/fr.symfony?key=$LOCO_API_KEY" | head -50

If that returns 401 the key/scope is wrong; 404 means the locale code doesn't exist in the project; a valid body means the problem is your target path or write permissions. This isolates bundle bugs from Loco config in under a minute.

Watch the trailing-slash and target-path config. If the bundle writes to translations/ relative to the project root but your Symfony app expects %kernel.project_dir%/translations, you'll get files in the wrong place with no error. After the first run, find . -name '*.xlf' -newer composer.json to confirm where they landed.

Free-tier quotas and export size. Loco limits API calls on lower plans. Don't put the import in a per-test setUp() or a file watcher; run it on demand and on deploy. Cache the exported files locally for CI re-runs where possible.

Extension points are thin, if they exist. There's unlikely to be an event dispatcher hook or an injectable HTTP client you can swap. The realistic extension strategy is to decorate the bundle's service (find it via debug:container --show-private | grep -i loco) or, simpler, write your own command and drop the bundle. Given the age and size, writing your own is usually less work than fighting its config tree.

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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings