taxionus/laravel-translatable
A Laravel package for adding multilingual attributes to Eloquent models, letting you store and retrieve translations per locale so your app can serve content in multiple languages.
This is the package's first tagged release (1.0.0), so there is no upgrade path to consider — treat it as a greenfield integration and pin it explicitly in composer.json rather than relying on a floating constraint while the public API settles.
Start here, in this order:
composer require the package at ^1.0.0 and confirm the service provider is picked up by Laravel's package auto-discovery (php artisan about will show it, or php artisan package:discover on older skeletons). If the package ships a facade or a Manager-style class, resolve it from the container once in tinker before touching application code — that single check tells you whether config, credentials and bindings are wired.php artisan vendor:publish --provider="...ServiceProvider" --tag=config). On a 1.0.0 release the config is the de facto contract: defaults tell you what the package assumes about your app (driver, queue connection, table names, cache TTL). Diff the published file against the package's own copy in vendor/ — drift here is the most common first-day confusion.php artisan migrate on a fresh database, not your dev DB. A first release frequently has index/foreign-key assumptions that only surface on a clean schema.First use case: wire up the smallest end-to-end path the package offers — one create, one read — inside a throwaway route or an artisan command, not inside a controller. You want to verify container resolution, config loading, and the storage/transport layer in isolation before that code is entangled with your HTTP concerns. Once that green path works, immediately exercise the failure path (missing credential, unreachable service, invalid payload) because first releases tend to have thin error handling.
Resolve through the container, never new. Bind the package's client/manager in a dedicated service provider of your own and inject it, so you have one place to swap config, add retries, or fake it in tests:
$this->app->singleton(PackageClient::class, fn ($app) => new PackageClient(
config('package.api_key'),
$app->make(GuzzleHttp\Client::class),
));
Wrap it in your own thin adapter. Do not let package classes leak into controllers, models or Blade. A single App\Services\... class that exposes the three or four operations you actually use means the package's inevitable 1.x API churn costs you one file, not forty. It also gives you a seam for logging and metrics.
Push side-effecting calls onto the queue. Anything that hits a network or slow store should be a job with $tries, $backoff and failed() implemented. First releases commonly lack built-in retry semantics; your job wrapper is where you supply them. Use ShouldBeUnique if the operation is idempotency-sensitive.
Keep the package's own events and your domain events separate. If it fires events, listen to them and re-emit your own domain events rather than dispatching application events from inside a package listener — otherwise you inherit their payload shape as a public contract.
Test with a fake, not a mock. If the package ships a fake()/swap() helper, use it in feature tests and keep a small number of integration tests that hit the real thing behind a @group integration annotation. If it ships no fake, that is your first contribution — it is the single highest-leverage addition to a 1.0.0 package.
Config over code for environment differences. Every value you would plausibly change between local/staging/production (endpoint, TTL, driver, queue name) belongs in config/ and read via config(), referenced by env var in .env.example. Never call env() outside config files — it returns null once config is cached, and this bites hardest with freshly released packages.
Log with context on the boundary. One log line at the adapter boundary including the operation, a correlation/request id, and duration. When something misbehaves in production, this is the difference between a five-minute and a five-hour diagnosis.
env() after config:cache. Classic first-release killer. If the package reads env() at runtime internally, php artisan config:cache in a deploy will silently blank its credentials. Verify by running config:cache locally before you ship.config/app.php (legacy habit), you get double registration — duplicated migrations, doubled listeners, doubled middleware. Pick one.vendor:publish --tag=... tags are commonly renamed between 1.0.0 and 1.0.1. Run it once early, commit the published files, and stop re-publishing.1.0.0. ^1.0 is fine after you have tests pinning behaviour; before that, tag-lock (1.0.0) so a 1.0.1 patch cannot change behaviour under you mid-sprint.migrations table. On multi-tenant or multi-connection setups, confirm which connection the package assumes before migrating anywhere real.mixed or were renamed. Trust vendor/ source or php artisan ide-helper:generate output over the shipped docblock.booted() callback or a health-check command) that validates required config and fails loudly in non-local environments.php artisan about → php artisan config:show <package> → resolve the binding in tinker → enable the package's own debug/log channel → finally reach for Xdebug. Most first-release issues are config-shaped, not code-shaped.Manager class with extend(), a driver config array, or interfaces bound in the provider. If any exist, prefer them over subclassing concrete classes — subclassing a 1.0.0 internals is the fastest route to a painful 1.1.0 upgrade.1.0.0 is the cheapest moment to influence the API. Keep a docs/vendor-notes.md of workarounds you apply; if the package fixes them, that file is your upgrade checklist.How can I help you explore Laravel packages today?