akeneo/crowdin-api
A PHP client for the Crowdin API that makes it easy to manage translation projects, files, strings, and localizations from your application. Provides a clean, typed wrapper around Crowdin endpoints for automating localization workflows.
Consider adopting when:
TranslationClient port) so you can swap to a maintained fork or the official Crowdin SDK later without touching business code.HandlerStack — request logging, token refresh, retry/backoff, MockHandler tests — has no drop-in equivalent and must be re-expressed in Symfony's HttpClientInterface decorators, RetryableHttpClient, or MockHttpClient.Look elsewhere when:
Http facade is Guzzle-backed; adopting v2.0.0 means shipping symfony/http-client alongside Guzzle. That's fine architecturally but worth an explicit decision, especially for teams whose observability, mocking, and retry conventions are all Guzzle-shaped.symfony/http-client directly.If you already run v1.x: treat 2.0.0 as a planned migration, not a patch. Budget for (a) dependency and autoload changes, (b) re-implementing any Guzzle middleware as Symfony decorators, (c) rewriting HTTP-level test doubles from MockHandler to MockHttpClient, and (d) re-verifying error semantics — Symfony's client surfaces non-2xx responses without throwing unless you call throw(), which differs from code that assumed Guzzle exceptions. A contract test against a Crowdin sandbox is the cheapest way to prove parity before cutting over.
To executives (1 slide):
We can ship multi-language support ~2 engineer-weeks sooner by integrating Crowdin with a small open-source (MIT, zero-cost) PHP client maintained by Akeneo — a credible PIM vendor with the same localization problem we have. It's a thin connector, not a platform bet. The new 2.0.0 release modernizes its HTTP layer (Symfony 6 instead of Guzzle), which keeps it aligned with current Laravel/Symfony rather than decaying on an old stack — a good sign, though it is a breaking change and confirms this is a vendor side-project, not a supported product. Cost: no license, low lock-in (we can swap TMS or fork the client). Risk: low adoption, ~2-year gap between releases, one-line changelog; we contain that by wrapping it behind our own interface, pinning the version, and requiring PHP 8.1+/Laravel 9+. Decision needed: approve Crowdin as the TMS for the next two locales and confirm our platform baseline is 8.3; the client reduces engineering effort and keeps the exit door open.
To engineering:
It's a hand-written PHP client for the Crowdin REST API — covers projects, directories, files, translations, and branches with a service + client structure that composes fine in Laravel services. 2.0.0 is a breaking release: Guzzle is gone, replaced by
symfony/http-client(PHP 8.1+, Symfony 6). Consequences for us: (1) we lose the Guzzle middleware ecosystem — logging, retry/backoff, and auth handlers need porting toHttpClientInterfacedecorators orRetryableHttpClient; (2)MockHandlertest doubles becomeMockHttpClient; (3) error handling differs — non-2xx doesn't throw by default, so any code relying on Guzzle exceptions must be audited; (4) we now ship two HTTP stacks, since Laravel'sHttpfacade is Guzzle-backed. Upside: native concurrency, which is genuinely useful if bulk sync fans out across files/locales. Plan: pin the major, wrap behind aTranslationGatewayinterface with our own DTOs, add contract tests against a Crowdin sandbox to catch drift, and budget a half-day to fork if a missing endpoint blocks us. If that overhead isn't worth it, the fallback is a 200-line client we own — same surface, one HTTP stack, no third party.
To product/design:
This unblocks "continuous localization": strings flow to translators on merge, translations flow back as PRs, and we can gate locale launches on coverage metrics pulled from Crowdin. It also gives us admin primitives (bulk export/import, per-locale progress) without building a translation console — and the new release makes bulk syncs cheaper to run concurrently. What it does not do: in-context preview, MT/QA orchestration, or design-time string management — those stay in Crowdin's UI or a later phase. Dependency note for planning: the integration now requires PHP 8.1+ / Laravel 9+, so if any tenant or client platform is older, that's a scoping item before we commit to a locale launch date.
How can I help you explore Laravel packages today?