Download the PHP package syriable/laravel-translations without Composer

On this page you can find all versions of the php package syriable/laravel-translations. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-translations

Laravel Translations

Tests Lint

Manage your Laravel translations from code — import and export language files, machine-translate with AI, enforce quality, track revision history, detect hardcoded strings, manage a glossary, report analytics, and expose KPIs through pre-built laravel-metrics definitions. It's a backend-only toolkit: one config file, one service provider, one Translations facade. No UI, no frontend, no opinions about how you render anything.


Table of contents


Installation

Require the package via Composer:

Run the installer — it publishes the config file, runs the migrations, and (with --import) loads your existing language files:

Or do the steps yourself:

Requirements: PHP 8.4+, Laravel 12 or 13.

Dependencies: The package pulls in laravel/ai (AI translation and review) and syriable/laravel-metrics (pre-built KPI definitions). AI calls are still opt-in via config — set ai.enabled = true and configure a provider key in your .env before calling Translations::translate() or Translations::aiReview().


Configuration

Everything is driven by config/translations.php. The two settings you'll touch first:

All tables are prefixed (default tx_) and can live on a dedicated connection, so the package never clashes with your schema:

See the configuration reference for every key.


How it's modelled

Four core records describe your catalog:

Record Table What it is
Locale tx_locales A language (en, es, …). Exactly one is the source (is_source = true).
Bundle tx_bundles A language file — auth.php, the JSON bundle (_json), or a vendor namespace.
Phrase tx_phrases A translation key within a bundle (e.g. failed, nested.key), with detected placeholders/HTML/plural flags, an optional developer note, and a priority.
Message tx_messages The translated value of one phrase in one locale, with a status, optional AI metadata (ai_generated, ai_provider), and review fields.

A dotted key like auth.failed resolves to bundle auth + phrase failed. Nested lang files use their slash path as the bundle name (filament/resources/bundle-resource.title), matching Laravel's own group convention. Keys with no dot live in the JSON bundle (_json).

Every message carries a status (opendraft/pending_reviewapproved). Writing a value fires a MessageSaved event that records a revision, runs quality checks, and flushes analytics.


Usage

Everything is reachable from the Translations facade, or by resolving the underlying classes from the container (app(TranslationManager::class), app(Inspector::class), …). The examples use the facade.

Reading and writing translations

set() is wrapped in a database transaction and returns the saved Message.

Finding similar keys

Surface phrases in the same bundle that share a leading key segment — handy for spotting related rules while you work (e.g. validation.accepted and its accepted_if / accepted_unless cousins). Segments are split on ., _ and -.

It returns a Collection<Phrase> from the same bundle only, ordered by key, excluding the given phrase by default. An unknown key yields an empty collection.

Locales

Each Locale exposes computed accessors — flag (SVG data URI via outhebox/blade-flags) and translation_progress (percent of non-open messages) — and scopes enabled(), targets(), and withTranslationProgressCounts().

Importing and exporting language files

Import reads PHP (including nested directories), JSON and vendor namespace files from lang_path into the database. The whole import runs in a transaction and suppresses per-row events, so a large or --fresh import never bloats history or leaves a half-written catalog behind.

Export writes the database back to disk, preserving nesting, key sorting, plurals and Unicode:

Set export.approved_only in config to export only reviewer-approved strings.

Imports are the catalog's source of truth and skip per-row quality/revisions; run php artisan translations:validate afterwards to check imported strings.

AI translation

Requires laravel/ai and ai.enabled = true. Translations are produced through a swappable Translator contract, so the engine can be faked in tests with no HTTP.

Prompts are context-aware (glossary terms, developer notes, where the key is used, sibling keys) and fence untrusted context so it can't act as instructions. Context is on by default; pass 'context' => false (or set ai.context to false) for a leaner, cheaper prompt — useful on large batch runs. Every call is logged to tx_ai_usages with an estimated cost from ai.cost_rates.

To discover which providers are actually usable — allowlisted and configured with a key in .env (via the laravel/ai config) — call AiProviders::usable(). It returns a Collection<AiProvider> (Ollama is treated as usable without a key, since it authenticates via its URL):

Each suggestion in the returned TranslationResult carries a value (the translation as proposed), a base_value (the clean, copy/store-ready translation — the exact string to write to a language file, stripped of any framing the model may add such as Translate to German, for example: "…"), a confidence score, a recommended flag (exactly one variant is always recommended), and an optional note — a concise, human-readable explanation of why that wording was chosen (terminology, common usage, natural phrasing, framework conventions), written in the source language so the translator reading it understands the reasoning. Read the recommended variant directly:

base_value comes from a dedicated structured-output field the model fills, and is cleaned defensively (surrounding quotes stripped, and the quoted translation lifted out of an e.g. "…" example) so a "copy" button always gets just the translation. apply() stores best(), so the value written to your catalog is the clean one even when the model wraps its answer in commentary.

Swapping the engine (e.g. in tests) is a one-liner — Translator has a single method:

Quality checks

Ten pluggable checks compare each translation against its source. They run automatically on every save (when quality.run_on_save is on) and on demand.

Check Severity Auto-fix
missing_placeholder — a :name/{count} from the source is missing error
unexpected_placeholder — a placeholder not in the source warning
plural — the translation's plural selectors/segments don't match the source error
inconsistent_plural_selector — the source plural mixes selectored ({0}, [1,19]) and selectorless segments warning
html_tag_mismatch — HTML tags differ from the source error
length_ratio — translation length is outside the expected band warning
whitespace — leading/trailing whitespace differs warning
casing — first-letter capitalization differs info
url_email — a URL or email was altered/dropped error
glossary — a glossary term wasn't applied warning

Disable a check by removing its class from quality.checks, or add your own implementing Syriable\Translations\Contracts\QualityCheck.

AI quality review

The deterministic checks above catch mechanical problems (placeholders, HTML, plural selectors). For the linguistic ones they can't see — unnatural phrasing, gender issues, pluralization errors, context mismatches and cross-key inconsistencies — the package ships an AI reviewer. Like AI translation it requires laravel/ai and ai.enabled = true, and runs through a swappable Reviewer contract so it can be faked in tests with no HTTP.

It gathers the source/target pairs for the locale's translated messages, sends them to the model in batches (ai.review.batch_size, default 50) and returns a ReviewResult:

Each ReviewIssue carries the dotted key it refers to, a severity as a dedicated ReviewSeverity (Low, Medium, High — the reviewer's own priority scale, distinct from the deterministic checks' Severity), a description of the problem (in the source language), an optional suggestion explaining the fix, and — when the reviewer proposes a corrected translation — a baseSuggestion: that correction on its own, in the target language, cleaned of any framing so it can be copied straight into the catalog (same treatment as a translation suggestion's base_value). The reviewer fences untrusted source/target text so it can't act as instructions, drops any issue the model invents for a key that wasn't reviewed, and logs every batch to tx_ai_usages with an estimated cost. Unlike the deterministic checks it does not persist QualityIssue rows — it's an on-demand review you run before approving a batch.

Run it from the CLI (exits non-zero when high-priority issues are found, so it slots into CI):

Swapping the engine (e.g. in tests) is a one-liner — Reviewer has a single method:

Validation rules

For validating a translation value as it's submitted (e.g. in a form request or Livewire component), the package ships two reusable Laravel ValidationRules under Syriable\Translations\Rules. Each takes the Phrase the value belongs to, so it can compare against the source and the phrase's metadata:

These complement the quality checks: the rules block bad input up front, while the checks audit already-stored translations.

Glossary

Per-locale approved terminology that feeds both AI prompts and the glossary quality check.

Revision history

Every value change is recorded in tx_revisions. Roll a message back, or undo a batch of changes.

Prune old history with php artisan translations:prune-revisions (keeps the latest per message).

Who made the change

Revision::member(), Message::translator() and Message::reviewer() are belongsTo relations against your configured member_model — resolving $revision->member/$message->translator needs no manual lookup:

You don't need to pass by explicitly for this to work. Every write path (set(), AI translation, review approve/reject, rollback) accepts an optional by in its $options/args, but when it's omitted the package asks Syriable\Translations\Contracts\ResolvesActor to identify the actor instead. The default implementation reads the currently authenticated user off auth_guard (null = your app's default guard) — so changed_by / translated_by / reviewed_by are filled in automatically, including who triggered an AI translation (the human who clicked "translate", not the AI itself — that's already tracked separately via reason: RevisionReason::Ai and Message::ai_provider). When nobody is authenticated (a console command, queue job, or script), the resolver falls back to system_actor (null by default, so unattended runs stay honestly unattributed rather than impersonating a user). Bind your own ResolvesActor in the container to customize resolution — e.g. to tag queue jobs with a service-account id:

Review workflow

When review.enabled is on, non-reviewer saves land in pending_review instead of approved.

The actor string is advisory — it's recorded, not enforced. Authorization is your application's job. MemberRole is a plain value object; if your member_model implements Syriable\Translations\Contracts\HasTranslationRole, the package ships a MessagePolicy stub you can register yourself (Gate::policy(Message::class, MessagePolicy::class)), or write your own. See Security.

Comments

Attach threaded discussion to a message. Comments fire CommentPosted, which the package listens to for activity logging when activities.enabled is on:

Each Comment belongs to its message and optionally to a member (via member_model).

Analytics

The Insights service returns simple, cached PHP arrays — handy for dashboards that don't need ranges or comparisons:

Metrics

For richer analytics — date ranges, trend buckets, partition breakdowns, formula datasets, and a normalized API payload — the package registers four metrics with syriable/laravel-metrics at boot. Run them by key:

Key Type Grouped by Datasets / formula
translations.coverage all-time partition locale name total, translated, untranslated, approvedcoverage = translated / total * 100
translations.quality all-time partition locale name translated, approved, issuesreview, validation, weighted quality
translations.velocity trend date (revisions.created_at) changes (revision count per bucket)
translations.bundle_coverage all-time partition bundle label total_phrases, completed_phrasespercent = completed_phrases / total_phrases * 100

Only enabled, non-source target locales are included. Quality weights default to 60% review (approved / translated) and 40% validation (100 - issues / translated * 100); override via translations.analytics.quality.weights.

Metric classes live in Syriable\Translations\Metrics if you want to inspect or extend them. See the laravel-metrics README for ranges, comparisons, caching, and building your own metrics.

Scanning your source code

Both return a stats array. Run them in the background with the --queue flag on the corresponding commands, or set scanning.scan_after_import to queue a usage scan after every import.

Hardcoded-string hits are stored as LooseString records (PendingResolved when the source text disappears, or Converted / Ignored when you action them). Persisted ignore rules live in IgnoredString.

Activity log

When activities.enabled is on, the package automatically records status changes and comments via RecordStatusActivity and RecordCommentActivity. For arbitrary actions, use the recorder directly:

Background jobs

Long-running work can be queued on the connection/name from translations.queue:

Job Dispatched by What it does
TranslateLocaleJob translations:translate --queue AI-translate every open message in a locale
ScanQualityJob translations:validate --queue Run the quality inspector
ScanUsageJob translations:scan-usage --queue Record phrase usages from source files
ScanLooseJob translations:scan-loose --queue Detect hardcoded strings

ScanUsageAfterImport also queues a usage scan when scanning.scan_after_import is enabled.


API reference

Every method on the Translations facade (backed by TranslationManager):

Method Returns Description
get(string $key, ?string $locale = null) ?string Value for a key, or null.
has(string $key, ?string $locale = null) bool Whether a value exists.
set(string $key, string $value, ?string $locale = null, array $options = []) Message Write a value (transactional); creates the phrase on demand. Options: by, reason, status, meta.
forget(string $key, ?string $locale = null) void Clear one locale's value, or delete the phrase.
all(?string $locale = null) array All values for a locale, keyed by dotted key.
similar(string $key, array $options = []) Collection Phrases in the same bundle sharing a leading key segment. Options: segments, limit, include_self.
locales() Collection All locales.
addLocale(string $code, array $attributes = []) Locale Create a locale and seed its messages.
import(array $options = []) ImportSummary Disk → DB. Options: fresh, overwrite, lang_path, source, triggered_by.
export(array $options = []) ExportSummary DB → disk. Options: locale, bundle, lang_path, source.
translate(string $key, string $locale, array $options = []) ?Message AI-translate a single key and save it.
ai() MachineTranslation The AI translation service.
aiReview() MachineReview The AI quality-review service.
quality() Inspector The quality-check service.
glossary() Glossary The glossary service.
insights() Insights The analytics service.
revisions() RevisionRollback Revision rollback service.
review() ReviewFlow The review/approval service.
scanUsage(?string $path = null) array Scan source for key usages.
scanLoose(?string $path = null) array Detect hardcoded strings.

The sub-services:

Service Methods
MachineTranslation suggest(Phrase, Locale, array), apply(Phrase, Locale, array), translateOpen(Locale, array): int, estimate(array $phraseIds, string $locale): array
MachineReview review(Locale, array): ReviewResult
Inspector inspect(Message): array, inspectAndStore(Message): array, scan(?int $localeId): array, fix(QualityIssue, ?string $by = null): bool
Glossary define(string, ?string, bool, bool, ?string): Term, translate(Term, int, string, ?string): TermDefinition, forget(Term), matching(string, int): Collection, pairsFor(string, int): array
RevisionRollback toRevision(Revision, ?string): Message, byMember(string, ?string $from, ?string $to, ?string $by): array, afterDate(string, ?int $localeId, ?string $by): array
Insights dashboard(), coverage(), bundleCoverage(?string), overallCoverage(): float, leaderboard(), velocity(int $days = 30), stale(?int), staleCounts(), flush()
ReviewFlow statusForSave(?MemberRole): MessageStatus, approve(Message, ?string): Message, reject(Message, string $note, ?string): Message

Artisan commands


Configuration reference


Events

Hook into the translation lifecycle with standard Laravel listeners:

Event Fired when Payload
MessageSaved a message's value changes $message, $oldValue, $reason, $changedBy, $meta
MessageStatusChanged a message's status changes (not on create) $message, $oldStatus, $newStatus, $reason, $changedBy, $meta
CommentPosted a comment is added to a message $comment
ImportFinished an import completes $summary (ImportSummary)
ExportFinished an export completes $summary (ExportSummary)
PhraseCreated a new phrase is created via the API $phrase
LocaleAdded a new locale is added $locale

Internally, MessageSaved drives RecordRevision, RunQualityChecks and FlushInsightsCache; MessageStatusChanged and CommentPosted drive activity logging (when enabled); ImportFinished drives ScanUsageAfterImport (when enabled) and a cache flush.


Models

All models live in Syriable\Translations\Models and use the configured table prefix.

Model Notable relations / methods
Locale messages(), members() (belongs-to-many against your configured member_model); scopes enabled(), targets(), withTranslationProgressCounts(); accessors flag, translation_progress; static source(), flushSourceCache(); casts directionDirection, toneTone
Bundle phrases(); isJson(), label(); scope withTranslationProgress(), translationProgressPercent()
Phrase bundle(), messages(), usages(), sourceMessage(); dottedKey(); scope missingIn(int $localeId); casts priorityPriority, placeholders → array
Message phrase(), locale(), revisions(), issues(), comments(), activities(), translator(), reviewer() (belongs-to against member_model); comment(string $body, ?string $memberId, array $meta); scopes translated(), open(), pendingReview(); static stamp(), clearStamp(), withStamp(), resolveActor(); accessor source
Revision message(), member() (belongs-to against member_model); scopes forLocale(int), between(?string, ?string)
QualityIssue message(), locale(); severity cast to Severity
Comment message(), member() (belongs-to against member_model)
Term / TermDefinition definitions() / term(), locale(); definitionFor(int $localeId)
AiUsage, Activity, PhraseUsage, LooseString, IgnoredString, ImportRecord, ExportRecord audit / support records

Enums

In Syriable\Translations\Enums:


Contracts

Swappable interfaces in Syriable\Translations\Contracts:

Contract Default binding Purpose
Translator AiTranslator AI translation engine (FakeTranslator in tests)
Reviewer AiReviewer AI quality-review engine (FakeReviewer in tests)
ResolvesActor AuthActorResolver Who performed a write when by is omitted
QualityCheck Implement to add a deterministic quality check
HasTranslationRole Implement on member_model to resolve MemberRole
SourceScanner Extend source-code scanning (used internally)

Testing

The suite runs on Pest 4 + Orchestra Testbench against in-memory SQLite. AI paths are tested through the Translator contract with FakeTranslator, so no test makes a network call.


Security

This is a backend-only toolkit with no auth layer; a few responsibilities sit with the consuming application (importing .php lang files executes them, models are mass-assignable, AI output is untrusted, authorization is yours). Read SECURITY.md for the full trust model and how to report a vulnerability.

Contributing

See CONTRIBUTING.md. Run composer test, composer analyse, and composer format before opening a PR.

Changelog

See CHANGELOG.md.

License

The MIT License (MIT). See LICENSE.md.


All versions of laravel-translations with dependencies

PHP Build Version
Package Version
Requires php Version ^8.4
illuminate/contracts Version ^12.0||^13.0
illuminate/database Version ^12.0||^13.0
illuminate/support Version ^12.0||^13.0
filament/support Version ^5.0
outhebox/blade-flags Version ^1.7.0
laravel/ai Version ^0.8.0
syriable/laravel-metrics Version ^1.0.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package syriable/laravel-translations contains the following files

Loading the files please wait ...