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

Crowdin Api Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Technical Evaluation

Architecture fit. Unchanged in shape: still a thin, standalone SDK at the boundary of the localization domain, still belongs behind a first-party TranslationProvider interface rather than being imported directly by controllers or jobs. The 2.0.0 change is a dependency substitution, not an architectural one — but it materially improves the fit with modern Laravel. Swapping Guzzle for symfony/http-client means the SDK now programs against HttpClientInterface and can accept an injected PSR-18/PSR-17 client rather than constructing its own handler stack. That is the single most useful thing this release could have done for observability, proxying, and testability, and it is a better fit for a Laravel app than a hard Guzzle coupling was.

Integration feasibility. Still low-friction on the happy path, with one caveat: symfony/http-client is not a default Laravel dependency (Laravel pulls symfony/console, http-foundation, process, etc., but not the HTTP client). It will be added to the tree for this package alone. That is a modest footprint and a well-maintained component, but it is a new transitive family to track. The real work remains workflow design — source extraction, project/file/branch mapping, pull cadence, write-back — and that has not changed.

Technical risk. The lifecycle risk profile has improved but not disappeared. A 2.0.0 after a ~two-year quiet period is evidence that the maintainer is still engaged and willing to make hard, breaking calls; "internal tool published for convenience" no longer reads as "abandoned." It is still one organizational maintainer (Akeneo) with incidental interest, zero dependents, and a small star count — you remain the primary owner of any defect. Two risks are retired by this release: the uncontrolled Guzzle constraint and the Guzzle-vs-Laravel HTTP client collision. Two risks are introduced or shifted:

  • Symfony major-version constraint. If the package pins symfony/http-client ^6, and the host app is on Laravel 11/12 (Symfony 7 components), you get a split-Symfony-major dependency tree. Distinct Symfony component packages can coexist across majors, but it is fragile and composer resolution may force downgrades elsewhere. Verify the constraint allows ^6.4|^7.0.
  • Different exception and retry semantics. symfony/http-client throws Symfony\Contracts\HttpClient\Exception\*, not GuzzleHttp\Exception\RequestException. Any error classification, 429 backoff, or retry logic written against Guzzle exception types is now wrong. Default timeout and redirect behavior also differ from Guzzle and must be set explicitly.

A major version bump for what reads as a single dependency swap strongly implies the public constructor/type-hint surface changed (a HttpClientInterface parameter replacing a Guzzle client). Assume 1.x call sites break at instantiation, not at the call site. MIT license keeps the fork escape hatch open, which still de-risks all of the above.

Key questions for the maintainer/spike.

  • What is the exact symfony/http-client constraint — does it permit ^7.0, or does it pin ^6 and therefore complicate Laravel 11/12 adoption?
  • Does the constructor accept any PSR-18 ClientInterface, or specifically HttpClientInterface? The former is more portable; the latter gives you Symfony's async/streaming.
  • Is retry/backoff now delegated to Symfony's RetryableHttpClient (and is it configurable), or is retry still absent?
  • How are exceptions surfaced — raw Symfony exceptions leaking through, or wrapped in a package-level exception type? Unwrapped is a leaky abstraction you'll need to shield.
  • Which Crowdin API version and auth model does 2.0 target — personal token only, or OAuth2 for Enterprise?
  • What changed in endpoint coverage versus 1.x, and is pagination still manual?
  • Is there now a test suite using MockHttpClient, or is it still untested against a live API?
  • How does this compare to the official crowdin/crowdin-api-client-php today — the build-vs-adopt call is still open and still decides the engagement.

Integration Approach

Stack fit. Laravel 10/11/12 on PHP 8.1+ is the target; Symfony 6 requires PHP 8.1, so the floor is unchanged in practice. The package should still live behind a CrowdinServiceProvider binding a configured client singleton from config/crowdin.php/env, and you should now also bind the underlying HTTP client so you can decorate it — TraceableHttpClient for the profiler, ScopingHttpClient for base-URI and per-host timeouts, RetryableHttpClient for backoff. Because the client is injectable, you can register it in the container once and reuse the same connection pool and configuration across Crowdin calls.

Migration path. If you piloted or shipped 1.x, this is a contained-but-real upgrade:

  1. Update the constructor call site — inject HttpClientInterface (or a PSR-18 adapter) instead of a Guzzle client.
  2. Delete any Guzzle HandlerStack middleware (logging, retry, proxy) and re-express it as Symfony decorators.
  3. Rewrite every catch (RequestException ...) into Symfony's exception contract, or wrap it once in a package-level exception and catch that everywhere.
  4. Replace MockHandler-based tests with MockHttpClient; this is a net gain — MockHttpClient takes a callable and is easier to assert against than a handler queue.
  5. Set timeout and max_duration explicitly; do not inherit defaults across the swap.

If you have not adopted either version yet, start directly on 2.0 — there is no reason to onboard onto a Guzzle-coupled 1.x.

Compatibility. Pin the exact 2.0.x version. Audit composer why symfony/http-client and confirm the resolved Symfony majors are coherent with the rest of the app; run composer update --dry-run against the full tree before merging. Check whether existing Guzzle-dependent packages (Socialite, Flysystem S3, mail transports) are unaffected — they will be, since Guzzle is no longer shared — and confirm nothing depended on the SDK transitively providing Guzzle.

Sequencing.

  1. Spike: install 2.0, authenticate, run one read (list projects) and one write (upload source file) with an injected HttpClientInterface — confirms the new wiring works.
  2. Build the adapter interface plus a fake implementation backed by MockHttpClient so feature work isn't blocked on Crowdin credentials.
  3. Ship the pull path first (approved translations into lang/ or DB) — lowest blast radius.
  4. Add the push path behind a queued job with idempotency keys.
  5. Add webhook ingestion for translation-complete events to replace polling.
  6. Reassess coverage gaps versus the official client before committing to a fork.

Operational Impact

Maintenance. Still treat this as a vendored dependency. The 2.0.0 release is a genuine positive signal — someone is home — but the bus factor is one and the release cadence is unknown. Mitigations unchanged: fork into a private VCS or use a Composer patch plugin, keep the adapter interface thin, and calendar a quarterly check against both Crowdin's API changelog and the Symfony HTTP client's release notes. Add one new watch item: when Symfony 8 lands, this package's constraint becomes your upgrade blocker.

Support. Still community-only, best-effort, no SLA, no security disclosure process to rely on. One improvement worth noting: because the HTTP client is now injectable, you can fix transport-layer problems (timeouts, proxies, TLS, retries) yourself without forking the SDK. That shrinks the surface you'd need a maintainer for to the endpoint wrappers and DTOs.

Scaling. The SDK is stateless and not the bottleneck; Crowdin rate limits are. The new client does unlock something real: symfony/http-client supports concurrent requests via stream()/AsyncResponse, so a full-project translation pull no longer has to be strictly sequential. Use it behind a per-project rate limiter with jittered exponential backoff, and keep every Crowdin interaction inside a queued job — never in a request cycle.

Failure modes to instrument.

  • Token expiry/revocation → 401s that surface as generic transport exceptions unless explicitly classified.
  • Rate limiting → 429 storms during bulk sync; the retry predicate must be rewritten for Symfony's exception types or backoff silently never fires.
  • Silent loss of retry after the upgrade → Guzzle middleware was doing more than anyone remembered; verify with a fault-injection test, not by reading code.
  • Unset timeouts → Symfony's defaults differ from Guzzle's; a hung Crowdin call can now block a worker longer or shorter than before. Set both timeout and max_duration.
  • Non-idempotent writes → duplicate strings or orphaned files on retry.
  • Silent schema drift → Crowdin renames a field, the thin wrapper passes a malformed payload, failure surfaces deep in the pipeline.
  • Pagination truncation on large projects → missing translations no one notices until release.
  • Dependency resolution failure at deploy → Symfony major mismatch or a re-introduced transitive conflict fatal on boot, not at request time. Gate it in CI with composer validate --strict and a dry-run against the production lock.

Ramp-up. Still low for a mid-level PHP engineer — the package is small enough to read in an afternoon. Add half a day for the Symfony HTTP client idiom: exception contracts, RetryableHttpClient, MockHttpClient, and async streams. Engineers fluent in Guzzle will find their instincts wrong in exactly the places that matter (error handling and retry), so budget that explicitly. The dominant learning curve remains Crowdin domain fluency — project/file/branch/namespace hierarchy, translation vs. approval state, TM behavior — and that still drives the integration timeline far more than the SDK does.

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
cgv/localized-resource