brunoscode / laravel-translation-handler
This is my package laravel-translation-handler
Package info
github.com/BrunosCode/LaravelTranslationHandler
pkg:composer/brunoscode/laravel-translation-handler
Fund package maintenance!
Requires
- php: ^8.2
- spatie/laravel-package-tools: ^1.14.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/mcp: ^0.7.0
- laravel/pint: ^1.0
- nunomaduro/collision: ^7.8 || ^8.0
- orchestra/testbench: ^9.0 || ^10.0
- pestphp/pest: ^2.34 || ^3.0
- pestphp/pest-plugin-arch: ^2.7 || ^3.0
- pestphp/pest-plugin-laravel: ^2.3 || ^3.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^2.0
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.26
Suggests
- laravel/boost: Required to expose translation MCP tools to AI agents via boost:mcp.
This package is auto-updated.
Last update: 2026-05-10 14:22:34 UTC
README
Manage translations in Laravel across PHP files, JSON files, CSV files, and database — and let an AI agent handle them for you via Laravel Boost MCP tools.
Requirements
| Laravel | PHP |
|---|---|
| 12.x | 8.2, 8.3, 8.4 |
| 11.x | 8.2, 8.3, 8.4 |
Supported Formats
| Format | Constant | Description |
|---|---|---|
| php_file | TranslationOptions::PHP |
Standard Laravel PHP translation files |
| json_file | TranslationOptions::JSON |
JSON translation files |
| csv_file | TranslationOptions::CSV |
CSV translation files |
| db | TranslationOptions::DB |
Database-backed translations |
Installation
composer require brunoscode/laravel-translation-handler
Publish the configuration file:
php artisan vendor:publish --provider="BrunosCode\TranslationHandler\TranslationHandlerServiceProvider"
AI-Powered Translation Management with Laravel Boost
When Laravel Boost is installed, this package automatically registers 11 MCP tools into Boost's MCP server. This lets any MCP-compatible AI agent (Claude, Cursor, GitHub Copilot, etc.) read and write your translations directly — no manual commands, no copy-pasting.
What the AI can do
- Browse your translation keys by group and depth level
- Look up a specific key in any locale
- Add or update a single translation in any format
- Add or update a key across all locales at once
- Translate an entire group in one call (every subkey, every locale)
- Sync translations between storage formats
- Delete a single key (optionally for a specific locale only)
- Delete all keys under a group prefix
- Sort keys alphabetically in PHP, JSON, and CSV formats
- Read the full translation configuration
Setup
Install Laravel Boost, then connect your AI assistant to its MCP server. No further configuration is required — the tools register automatically on package detection.
composer require laravel/boost
Available MCP Tools
Format values for format / from / to parameters: php_file, json_file, csv_file, db.
get-translation-config-tool (read-only)
Returns the active configuration: locales, file names, key delimiter, default formats, and storage paths. Useful as a first call to understand the project's translation setup.
No parameters.
list-translations-tool (read-only)
Lists translations from a format with optional filters.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to read from |
locale |
string | no | Filter by locale (e.g. en) |
group |
string | no | Filter by key prefix (e.g. auth returns all auth.* keys) |
list-translation-groups-tool (read-only)
Lists unique key groups at a given depth. Use this to explore the key hierarchy before reading or writing translations — especially useful in large projects.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to read from |
level |
integer | no | Number of delimiters in the group name. 0 = top-level (e.g. auth), 1 = second-level (e.g. auth.messages). Defaults to 0. |
search |
string | no | Case-insensitive filter on group names |
find-translation-tool (read-only)
Finds a specific translation by key and locale.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to read from |
key |
string | yes | Dot-delimited key (e.g. auth.welcome) |
locale |
string | yes | Locale to look up |
set-translation-tool (write)
Sets or updates a single translation value.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to write to |
key |
string | yes | Dot-delimited key |
locale |
string | yes | Target locale |
value |
string | yes | Translation value |
force |
boolean | no | Overwrite existing value (default false) |
set-all-locales-translation-tool (write)
Sets or updates a translation key for all locales at once. Ideal when the AI generates translations for every supported language in a single step.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to write to |
key |
string | yes | Dot-delimited key |
values |
object | yes | Map of locale → value, e.g. {"en": "Hello", "it": "Ciao"} |
force |
boolean | no | Overwrite existing values (default false) |
set-translation-group-tool (write)
Translates an entire group in a single call. The AI provides a group prefix and an object of subkey → {locale: value}; the tool joins each subkey to the group and writes all locales for all subkeys in one DB transaction.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to write to |
group |
string | yes | Group prefix (e.g. auth). Trailing delimiter is tolerated. |
translations |
object | yes | Map of subkey → locale=>value, e.g. {"welcome": {"en": "Welcome", "it": "Benvenuto"}, "logout": {"en": "Logout", "it": "Esci"}}. Subkeys may contain the delimiter (nested.deep). |
force |
boolean | no | Overwrite existing values (default false) |
sync-translations-tool (write)
Copies translations from one storage format to another.
| Parameter | Type | Required | Description |
|---|---|---|---|
from |
string | yes | Source format |
to |
string | yes | Destination format (must differ from from) |
force |
boolean | no | Overwrite existing translations in destination (default false) |
delete-translation-tool (write)
Deletes a translation key from a storage format. Omit locale to delete the key for all locales.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to delete from |
key |
string | yes | Dot-delimited key to delete (e.g. auth.welcome) |
locale |
string | no | Delete only this locale. Omit to delete all locales for the key. |
delete-translation-group-tool (write)
Deletes all translation keys under a group prefix from a storage format.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to delete from |
group |
string | yes | Key group prefix to delete (e.g. auth removes all auth.* keys) |
sort-translations-tool (write)
Sorts translation keys alphabetically within a storage format. Supports php_file, json_file, and csv_file only.
| Parameter | Type | Required | Description |
|---|---|---|---|
format |
string | yes | Storage format to sort (php_file, json_file, or csv_file) |
locales |
array | no | Restrict sorting to these locales. Omit to sort all locales. |
groups |
array | no | Restrict sorting to these key group prefixes. Omit to sort all groups. |
Recommended workflow for editing translations
Use db as the working format for all writes, then sync to files at the end.
File-based formats (PHP, JSON, CSV) rewrite the entire file on every write operation. The database format writes only the affected rows, making each change significantly faster. Once all edits are done, a single sync pushes everything to the target file format.
1. Read/browse → db (or any format for read-only queries)
2. Write keys → always db
3. Finalise → sync-translations-tool from: db to: <target format>
When no database is configured, write directly to the file format but batch all locales for a key into a single set-all-locales-translation-tool call rather than one call per locale.
Example AI workflow
You: "Add a
auth.too_many_attemptskey in English and Italian to the JSON files."
The AI will:
- Call
get-translation-config-toolto confirm the locales and format - Call
set-all-locales-translation-toolwith{"en": "Too many attempts. Please try again later.", "it": "Troppi tentativi. Riprova più tardi."}targetingjson_file
You: "Translate the entire
authgroup into English, Italian, and Spanish."
The AI will call set-translation-group-tool with format: db, group: auth, and a translations object containing every auth subkey mapped to all three locales — written in a single DB transaction.
You: "Migrate all translations from PHP files to the database."
The AI will call sync-translations-tool with from: php_file, to: db.
You: "What translation groups exist at the top level?"
The AI will call list-translation-groups-tool with format: php_file, level: 0.
Quick Start
# Sync translations between formats php artisan translation-handler:sync php_file json_file # Import / export using config defaults php artisan translation-handler:import php artisan translation-handler:export --force # List all translations from PHP files php artisan translation-handler:list php_file # List translations filtered by locale and group php artisan translation-handler:list php_file --locale=en --group=auth # List top-level key groups php artisan translation-handler:list-groups php_file # List second-level groups, filtered by search php artisan translation-handler:list-groups php_file --level=1 --search=messages # Find a specific translation php artisan translation-handler:find php_file auth.welcome en # Get the raw value of a translation php artisan translation-handler:get php_file auth.welcome en # Set a specific translation php artisan translation-handler:set php_file auth.welcome en "Welcome!" # Delete a translation key (all locales) php artisan translation-handler:delete php_file auth.welcome # Delete a translation key for a specific locale php artisan translation-handler:delete php_file auth.welcome --locale=en # Delete all keys under a group php artisan translation-handler:delete-group php_file auth # Sort all keys alphabetically php artisan translation-handler:sort php_file # Sort only specific locales and groups php artisan translation-handler:sort php_file --locale=en --group=auth
Or use the Facade:
use BrunosCode\TranslationHandler\Facades\TranslationHandler; use BrunosCode\TranslationHandler\Data\TranslationOptions; // Copy PHP → JSON (explicit formats) TranslationHandler::sync(TranslationOptions::PHP, TranslationOptions::JSON); // Copy JSON → PHP, overwriting existing TranslationHandler::sync(TranslationOptions::JSON, TranslationOptions::PHP, force: true); // Import using config defaults TranslationHandler::import(); // Export using config defaults TranslationHandler::export();
Commands
Shared Options
These options are available on translation-handler, translation-handler:import, and translation-handler:export:
| Option | Type | Default | Description |
|---|---|---|---|
--force |
bool | false |
Overwrite existing translations |
--fresh |
bool | false |
Delete existing translations before writing |
--file-names |
array | config fileNames |
Translation file names to process |
--locales |
array | config locales |
Locales to process |
--from-path |
string | format default | Custom source path |
--to-path |
string | format default | Custom destination path |
--guided |
bool | false |
Interactive mode, prompts for each option |
translation-handler:sync
Sync translations from one format to another. Source and destination are positional arguments.
php artisan translation-handler:sync {from?} {to?} [options]
If from or to are omitted, you will be prompted to choose.
translation-handler (deprecated)
Deprecated. Use
translation-handler:syncinstead.
php artisan translation-handler {from?} {to?} [options]
translation-handler:import
Import translations. Source and destination are passed via --from and --to options, defaulting to config values (defaultImportFrom, defaultImportTo).
php artisan translation-handler:import [options]
translation-handler:export
Export translations. Source and destination are passed via --from and --to options, defaulting to config values (defaultExportFrom, defaultExportTo).
php artisan translation-handler:export [options]
translation-handler:list
List translations from a storage format. Optionally filter by locale or key group prefix.
php artisan translation-handler:list {from?} {--from-path=} {--locale=} {--group=}
| Option | Description |
|---|---|
--locale |
Filter by locale (e.g. en) |
--group |
Filter by key group prefix (e.g. auth returns all auth.* keys) |
translation-handler:list-groups
List unique translation key groups from a storage format. A group is a key prefix at a given depth level. Optionally filter by search string.
php artisan translation-handler:list-groups {from?} {--from-path=} {--level=0} {--search=}
| Option | Description |
|---|---|
--level |
Number of delimiters in the group name. 0 = top-level (e.g. auth), 1 = second-level (e.g. auth.messages). Defaults to 0. |
--search |
Case-insensitive filter on group names |
translation-handler:find
Find a specific translation by key and locale. Outputs a table with format, key, locale, and value.
php artisan translation-handler:find {from?} {key?} {locale?} {--from-path=}
translation-handler:get
Get the raw value of a single translation.
php artisan translation-handler:get {from?} {key?} {locale?} {--from-path=}
translation-handler:set
Set a single translation value.
php artisan translation-handler:set {to?} {key?} {locale?} {value?} {--to-path=} {--force}
translation-handler:delete
Delete a translation key from a storage format. Omit --locale to delete all locales for the key.
php artisan translation-handler:delete {from?} {key?} {--locale=} {--from-path=}
translation-handler:delete-group
Delete all translation keys under a group prefix from a storage format.
php artisan translation-handler:delete-group {from?} {group?} {--from-path=}
translation-handler:sort
Sort translation keys alphabetically. Works on php_file, json_file, and csv_file only.
php artisan translation-handler:sort {from?} {--from-path=} {--locale=*} {--group=*}
| Option | Description |
|---|---|
--locale |
Restrict sorting to this locale (repeatable: --locale=en --locale=it) |
--group |
Restrict sorting to this key group prefix (repeatable) |
Facade API
use BrunosCode\TranslationHandler\Facades\TranslationHandler;
sync
Copies translations from one format to another. Unlike import/export, from and to are required — no config defaults are used.
TranslationHandler::sync( from: string, // source format to: string, // destination format force: bool, // overwrite existing (default: false) fromPath: ?string, // custom source path (default: null) toPath: ?string, // custom destination path (default: null) ): bool;
import / export
Both methods share the same signature. from and to fall back to config defaults (defaultImportFrom/defaultImportTo and defaultExportFrom/defaultExportTo) when omitted.
TranslationHandler::import( from: ?string, // source format (default: config value) to: ?string, // destination format (default: config value) force: bool, // overwrite existing (default: false) fromPath: ?string, // custom source path (default: null) toPath: ?string, // custom destination path (default: null) ): bool; TranslationHandler::export(/* same signature */): bool;
find
Finds a single translation by key and locale. Returns null if not found.
$translation = TranslationHandler::find( from: string, // source format key: string, // dot-delimited key locale: string, // locale to look up path: ?string, // custom path (default: null) ): ?Translation;
listTranslations
Returns a filtered TranslationCollection. Applies locale and/or group prefix filters on top of get().
$translations = TranslationHandler::listTranslations( from: string, // source format path: ?string, // custom path (default: null) locale: ?string, // filter by locale (default: null = all) group: ?string, // filter by key group prefix (default: null = all) ): TranslationCollection;
listGroups
Returns a sorted Collection of unique key group names at a given depth level.
$groups = TranslationHandler::listGroups( from: string, // source format path: ?string, // custom path (default: null) level: int, // 0 = top-level groups, 1 = second-level, … (default: 0) search: ?string, // case-insensitive filter on group names (default: null) ): Collection;
get
$translations = TranslationHandler::get( from: string, // source format path: ?string, // custom path (default: null) ): TranslationCollection;
set
$count = TranslationHandler::set( translations: TranslationCollection, to: string, // destination format path: ?string, // custom path (default: null) force: bool, // overwrite existing (default: false) ): int;
Example:
use BrunosCode\TranslationHandler\Collections\TranslationCollection; use BrunosCode\TranslationHandler\Data\Translation; use BrunosCode\TranslationHandler\Data\TranslationOptions; $translation = new Translation('welcome', 'en', 'Welcome!'); $collection = new TranslationCollection([$translation]); TranslationHandler::set($collection, TranslationOptions::JSON);
deleteKey
Deletes a specific translation key from a format. Pass locale to target a single locale; omit to delete all locales.
$count = TranslationHandler::deleteKey( from: string, // format to delete from key: string, // dot-delimited key locale: ?string, // locale to delete (default: null = all locales) path: ?string, // custom path (default: null) ): int;
deleteGroup
Deletes all keys whose name starts with the given group prefix.
$count = TranslationHandler::deleteGroup( from: string, // format to delete from group: string, // group prefix (e.g. "auth" removes all "auth.*" keys) path: ?string, // custom path (default: null) ): int;
sortKeys
Sorts translation keys alphabetically within a format. Supports php_file, json_file, and csv_file. Optionally restrict by locale and/or group.
$count = TranslationHandler::sortKeys( from: string, // format to sort (php_file, json_file, csv_file) locales: array, // restrict to these locales (default: [] = all) groups: array, // restrict to these group prefixes (default: [] = all) path: ?string, // custom path (default: null) ): int;
delete
$count = TranslationHandler::delete( from: string, // format to delete from path: ?string, // custom path (default: null) ): int;
Options Management
// Get/set individual options TranslationHandler::setOption('keyDelimiter', '_'); $value = TranslationHandler::getOption('keyDelimiter'); // Replace all options TranslationHandler::setOptions(new TranslationOptions([...])); // Reset to defaults TranslationHandler::resetOptions();
Configuration
The config/translation-handler.php file contains:
General
| Option | Default | Description |
|---|---|---|
keyDelimiter |
. |
Delimiter used in translation keys |
fileNames |
['translation-handler'] |
Translation file names to process |
locales |
['en'] |
Supported locales |
Default Formats
| Option | Default | Description |
|---|---|---|
defaultImportFrom |
php_file |
Default source format for import |
defaultImportTo |
json_file |
Default destination format for import |
defaultExportFrom |
json_file |
Default source format for export |
defaultExportTo |
php_file |
Default destination format for export |
PHP
| Option | Default | Description |
|---|---|---|
phpPath |
lang_path() |
Path to PHP translation files |
phpFormat |
false |
Format PHP output |
phpHandlerClass |
PhpFileHandler::class |
Handler class |
JSON
| Option | Default | Description |
|---|---|---|
jsonPath |
lang_path() |
Path to JSON translation files |
jsonFileName |
'' |
File name (empty = use locale as filename, set = use locale as folder) |
jsonNested |
false |
Nest output like PHP files |
jsonFormat |
true |
Pretty-print JSON output |
jsonHandlerClass |
JsonFileHandler::class |
Handler class |
CSV
| Option | Default | Description |
|---|---|---|
csvPath |
storage_path('lang') |
Path to CSV files |
csvFileName |
translations |
CSV file name |
csvDelimiter |
; |
CSV delimiter (must differ from keyDelimiter) |
csvHandlerClass |
CsvFileHandler::class |
Handler class |
Database
| Option | Default | Description |
|---|---|---|
dbHandlerClass |
DatabaseHandler::class |
Handler class |
Contributing
Contributions are welcome! Please submit a pull request or open an issue to discuss what you would like to change.
License
The MIT License (MIT). Please see License File for more information.