simonecerruti/laravel-translation-audit
Audit your Laravel translation files from the command line: spot missing keys, unused strings, duplicate entries, and inconsistencies across locales so every language stays complete and in sync. A lightweight PHP dev tool for cleaner, more reliable localization before shipping.
translation:audit and translation:purge-unused. It fits Laravel applications that rely on Laravel’s translator and __() / @lang helpers, especially modular monoliths and apps with large, actively maintained locale files. v0.13.0 broadens pipeline fit by shipping a ready-made GitLab CI job alongside the GitHub workflow, so teams on either platform get a supported first-class integration. It remains a weaker fit for frontends with separate i18n pipelines or organizations standardizing on an external TMS unless export/import workflows are added.unused_ignore_paths is removed and merged into ignore_paths, which is now scoped per audit via the new AuditType enum (Missing / Unused). The GitHub workflow publish tag is renamed to laravel-translation-audit-github-workflow. The public API is now delimited ahead of v1.0 (service provider, commands, AuditCommand, TranslationKeyResolver, Result and results, Data\Translation, DisplayFormat, SaveFormat, InvalidConfigException, AuditType), and every concrete class is final. Most applications will only need a config migration and a CI include; only teams that extended commands, results, or the service provider are materially affected.@internal boundary—good long-term signal, but v0.13.0 delivers real breaking changes. The highest-severity risk is the config merge: a published config that defines its own ignore_paths without adding the new defaults will cause Laravel’s own translation files (e.g. lang/*/validation.php) to be reported as unused and removed by translation:purge-unused. The tag rename can silently break existing publish scripts or CI bootstrap steps. Making classes final removes extension-based workarounds teams may have used to patch detection behavior. Per-audit ignore scoping is powerful but adds a new class of misconfiguration: a path ignored only for Missing still counts its keys as used (so purge-unused keeps them), while a path ignored only for Unused is still audited for missing keys—the inverse of what a reviewer might assume.unused_ignore_paths → ignore_paths + AuditType, and does the package fail loudly when defaults are missing?translation:purge-unused support dry-run, backup, or diff review, and does it fully honor AuditType scoping before deletion?AuditType values and the public API surface now frozen until v1.0, or can they change in the next minor?--tag="laravel-translation-audit-github-workflow" or the GitLab job with --tag="laravel-translation-audit-gitlab-workflow" (written to .gitlab/ci/audit-translations.yml and included from .gitlab-ci.yml, running on default-branch pushes, merge requests, and web-UI pipelines). The umbrella laravel-translation-audit tag publishes config plus both workflows. Less direct fit for JavaScript-only translation files, mobile localization, or TMS-owned translation workflows.unused_ignore_paths patterns into ignore_paths mapped to AuditType::Unused (e.g. 'lang/*/validation.php' => AuditType::Unused) and re-add the Laravel defaults. Update any scripts referencing the old workflow publish tag. Only after triage and diff review should translation:purge-unused be introduced.final commands, results, or service provider, or calls AuditTranslationsResult::withUnused() / jsonSections() (now @internal). Anything relying on those must be rewritten against the public API or pinned to v0.12.x.unused_ignore_paths, ignore_paths, ignore_locales, ignore_keys), publish-tag usage, and any class extension of commands/results.unused_ignore_paths into ignore_paths with AuditType::Unused and restore the Laravel translation-file defaults.translation:audit to produce a fresh baseline and diff it against the v0.12.x baseline; triage new unused findings, especially any Laravel-provided translation files.translation:purge-unused only after dry-run/diff review and VCS rollback are established, verifying AuditType scoping protects shared/vendor files.AuditType ignore rules, CI exceptions, and periodic baseline refreshes.final. The new public/@internal boundary should reduce future upgrade churn by making it clearer what is safe to depend on. Pre-1.0 status still warrants pinning and reading release notes before every upgrade.AuditType semantics (which audit an ignore rule applies to) and the unused_ignore_paths migration; a short internal runbook covering both is worthwhile. A named internal owner should own configuration, AuditType rules, CI gating, and exception lists.Missing while still letting purge-unused see their key usage—but rule volume becomes its own maintenance surface at scale. Very large monorepos may still need scoped paths or split jobs, and purge-unused at scale can produce large diffs.ignore_paths that omits the new defaults causes Laravel’s own translation files to be flagged unused and deleted by translation:purge-unused.AuditType rules applied to the wrong audit—e.g. a path intended to be protected from deletion mapped to Missing only.final classes or @internal methods (withUnused(), jsonSections()).purge-unused removing keys used only through dynamic construction; require dry-run, diff review, and VCS rollback.AuditType model and CI policy need explicit agreement. Budget roughly half a day for installation and baseline, an extra half day to a day for the v0.13.0 config migration and workflow integration, plus one sprint for triage, CI integration, and ownership definition. Define success metrics: missing-key count, false-positive rate on dynamic keys, unused-key cleanup volume, zero unintended deletions of framework translation files, CI pass stability, and time saved in localization QA.How can I help you explore Laravel packages today?