PHPackages                             brunoscode/twill-translation-handler - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. brunoscode/twill-translation-handler

ActiveLibrary[Localization &amp; i18n](/categories/localization)

brunoscode/twill-translation-handler
====================================

This is my package twill-translation-handler

v2.1.1(1mo ago)0279↓42.3%[1 PRs](https://github.com/BrunosCode/TwillTranslationHandler/pulls)MITPHPPHP ^8.2CI passing

Since Mar 17Pushed 1w ago1 watchersCompare

[ Source](https://github.com/BrunosCode/TwillTranslationHandler)[ Packagist](https://packagist.org/packages/brunoscode/twill-translation-handler)[ Docs](https://github.com/brunoscode/twill-translation-handler)[ GitHub Sponsors](https://github.com/BrunosCode)[ RSS](/packages/brunoscode-twill-translation-handler/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (10)Dependencies (28)Versions (11)Used By (0)

Twill Translation Handler
=========================

[](#twill-translation-handler)

> A [Twill CMS](https://twillcms.com) capsule for managing Laravel translations directly from the admin panel. Built on top of [LaravelTranslationHandler](https://github.com/BrunosCode/LaravelTranslationHandler).

[![Latest Version on Packagist](https://camo.githubusercontent.com/d16f6d2beeb58fe01fed4d4b0e4240aa73705b5ef3c33fc217ceecfb67298021/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6272756e6f73636f64652f7477696c6c2d7472616e736c6174696f6e2d68616e646c65722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/brunoscode/twill-translation-handler)[![GitHub Tests Action Status](https://camo.githubusercontent.com/ff8d65d1cb0035d29d4b56a2475c7a356b1a31e2abe4013d13ac294d8e1663e2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f4272756e6f73436f64652f5477696c6c5472616e736c6174696f6e48616e646c65722f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/BrunosCode/TwillTranslationHandler/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/c9be5671c3926970b54f6205cc82f74a9f82c861e1a043fb613cfea60d13f8c3/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f4272756e6f73436f64652f5477696c6c5472616e736c6174696f6e48616e646c65722f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/BrunosCode/TwillTranslationHandler/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/35ad5d93aa95fbcebd0e0d8106753260e772a94f64f1c9eeafff744a03e393c6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6272756e6f73636f64652f7477696c6c2d7472616e736c6174696f6e2d68616e646c65722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/brunoscode/twill-translation-handler)[![License](https://camo.githubusercontent.com/ac17ba9b80101fe984de3f433c73dc679e0a38e5b4dc2a227c75dabef35750d4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6272756e6f73636f64652f7477696c6c2d7472616e736c6174696f6e2d68616e646c65722e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)

> **Twill compatibility:** Currently supports **Twill 3** (Laravel 11–12, PHP 8.2+). Twill 2 support is available in the `v0.x` releases.

Table of Contents
-----------------

[](#table-of-contents)

- [Supported versions](#supported-versions)
- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Navigation](#navigation)
- [Configuration](#configuration)
- [Usage](#usage)
- [Editorial interface](#editorial-interface)
- [Deployment](#deployment)
- [Syncing translations from production](#syncing-translations-from-production)
- [AI integration (Laravel Boost)](#ai-integration-laravel-boost)
- [Database Structure](#database-structure)
- [Testing](#testing)
- [Changelog](#changelog)
- [Credits](#credits)
- [Contributing](#contributing)
- [License](#license)

Supported versions
------------------

[](#supported-versions)

Package versionPHPLaravelTwill**v2.2**8.2 · 8.3 · 8.411 · 123.xv2.08.2 · 8.3113.xv1.x8.1+102.xFeatures
--------

[](#features)

- **Translation key management** — Browse and edit all translation keys and their per-locale values from a clean Twill module interface.
- **Group-based organization** — Translations are automatically grouped by prefix (e.g. `messages`, `messages.validation`). Groups are created automatically on import and provide a focused editing view via Twill repeaters.
- **Multi-locale support** — Edit translations for all configured locales side by side. Individual locale values can be marked active or inactive.
- **Import / Export** — Sync translations between the database and CSV files:
    - Import from PHP files to populate the database
    - Export all translations to CSV or upload a CSV to import
    - Export a single group as CSV directly from its edit page
- **Automatic group syncing** — When translations are imported, the `DatabaseHandler` automatically creates all intermediate group levels (e.g. importing `messages.validation.required` creates both `messages` and `messages.validation` groups).
- **Auto-sync to PHP files** — Saving a translation key or a group automatically exports the affected PHP language file, keeping the filesystem always in sync with the database.

Requirements
------------

[](#requirements)

- PHP 8.2, 8.3, or 8.4
- Laravel 11 or 12
- Twill 3.x

Installation
------------

[](#installation)

```
composer require brunoscode/twill-translation-handler
```

Run the migrations:

```
php artisan migrate
```

Publish the config file:

```
php artisan vendor:publish --tag="twill-translation-handler-config"
```

Optionally publish the views to customise them:

```
php artisan vendor:publish --tag="twill-translation-handler-views"
```

Navigation
----------

[](#navigation)

The package provides three sub-pages:

- **Translations** — browse and edit individual translation keys
- **Groups** — edit translations grouped by prefix
- **Import / Export** — sync translations via CSV

### TwillNavigation builder

[](#twillnavigation-builder)

If your app uses the newer `TwillNavigation` builder API, disable the automatic registration in `config/translation-handler.php`:

```
'legacy-twill-navigation' => false,
```

Then register the entries in your `AppServiceProvider` (or wherever you build your Twill navigation):

```
use A17\Twill\Facades\TwillNavigation;
use A17\Twill\View\Components\Navigation\NavigationLink;

TwillNavigation::addLink(
    NavigationLink::make()->title('Translations')
        ->forModule('translations')
        ->doNotAddSelfAsFirstChild()
        ->setChildren([
            NavigationLink::make()->title('Translations')->forModule('translations'),
            NavigationLink::make()->title('Groups')->forModule('translationGroups'),
            NavigationLink::make()->title('Import / Export')->forRoute('twill.translations.translationTools.index'),
        ])
);
```

If you have a custom `admin_route_name_prefix`, replace `twill.` accordingly:

```
NavigationLink::make()->title('Import / Export')
    ->forRoute(config('twill.admin_route_name_prefix', 'twill.') . 'translations.translationTools.index'),
```

### Legacy twill-navigation config array

[](#legacy-twill-navigation-config-array)

By default the package registers the navigation automatically via the legacy `twill-navigation` config array. The package will merge the `translations` key into the array at boot. To control where it appears in the sidebar, add an empty placeholder in the right position — PHP arrays preserve the insertion order of existing keys:

```
// config/twill-navigation.php

return [
    'dashboard' => [
        'title' => 'Dashboard',
        'route' => 'admin.dashboard',
    ],

    // Placeholder — position is preserved, structure is filled in by the package
    'translations' => [],

    'pages' => [
        'title' => 'Pages',
        'route' => 'admin.pages.index',
    ],
];
```

Configuration
-------------

[](#configuration)

```
// config/translation-handler.php

return [
    'keyDelimiter' => '.',          // Separator used in nested translation keys

    'fileNames' => ['messages'],    // PHP file names to sync (without .php extension)
    'locales'   => ['en', 'it'],    // Supported locales

    // Default import/export direction
    'defaultImportFrom' => TranslationOptions::PHP,
    'defaultImportTo'   => TranslationOptions::DB,
    'defaultExportFrom' => TranslationOptions::DB,
    'defaultExportTo'   => TranslationOptions::PHP,

    'phpPath'      => lang_path(),          // Path to PHP language files
    'csvDelimiter' => ';',                  // CSV column delimiter
    'csvFileName'  => 'translations',       // Default CSV file name
    'csvPath'      => storage_path('lang'), // Directory for CSV files
    'jsonPath'     => lang_path(),          // Path to JSON language files
];
```

See [LaravelTranslationHandler](https://github.com/BrunosCode/LaravelTranslationHandler) for the full list of configuration options.

Usage
-----

[](#usage)

Once installed, a **Translations** section will appear in the Twill admin navigation with three pages:

### Keys

[](#keys)

Lists all translation keys stored in the database. Each key can be opened to edit its translated value for every configured locale. Translation keys are managed exclusively through import — manual creation is intentionally disabled to keep the database in sync with source files.

### Groups

[](#groups)

Lists all translation groups, auto-generated from the key prefixes. Opening a group shows all matching keys in a repeater, allowing batch editing of every locale's value from a single form.

### Import / Export

[](#import--export)

A tools page with actions to sync translations:

ActionDescriptionImport from CSVUploads a CSV file, imports all translations into the database, and writes the PHP language filesExport to CSVDownloads all database translations as a CSV filePer-group CSV export is also available directly from each group's edit page.

#### CSV import rules

[](#csv-import-rules)

- The file does not need to contain all keys — only the keys present in the file will be updated.
- All locale columns must be present in the file header.
- Empty values will overwrite the existing translation with an empty string.

> PHP language files are kept in sync automatically: every import (CSV via the tools page or per-group) writes the affected PHP files immediately after updating the database. Saving a single key or group from the edit form also triggers the same export.

Editorial interface
-------------------

[](#editorial-interface)

### Editing a key

[](#editing-a-key)

Opening a translation key shows:

FieldBehaviour**Key**Read-only. Keys are created only via import.**Value**Translatable textarea — one tab per configured locale.**Allow empty**Checkbox (sidebar). See [below](#allow-empty).Saving a key immediately exports the affected PHP language file.

### Editing a group

[](#editing-a-group)

Opening a group shows the **prefix** (read-only) and one textarea per translation key that belongs to the group. Each textarea is translatable — every configured locale is available as a tab. A **Download CSV** button lets editors export the group directly from the edit page.

Field naming: each textarea is internally keyed as `trans_` where `` is the `translation_keys.id`. This is transparent to editors but relevant if you extend the form.

Saving a group writes all locale values and immediately exports the affected PHP language file.

### allow\_empty

[](#allow_empty)

Both modules show an **Allow empty** checkbox in the sidebar. Its effect is on form validation:

Module`allow_empty` unchecked`allow_empty` checked**Keys**Value is `required` for every localeValue is `nullable` — empty strings are accepted**Groups**Every locale value of every key is `required`No validation — any combination of values is acceptedWhen a value reaches the repository as `null` (e.g. the editor cleared a field), it is normalised to an empty string before being persisted. This means the database never stores `null` in `translation_values.value` through a form save.

Deployment
----------

[](#deployment)

The **database is the source of truth** for translation values. PHP language files are used only to carry new keys and new locales between environments.

A typical deploy script:

```
php artisan migrate

# Add new keys and locales from PHP files to the DB, without overwriting existing DB values
php artisan translation-handler:sync php db

# Overwrite PHP files with the authoritative DB values
php artisan translation-handler:sync db php --force
```

The first command (without `--force`) inserts only keys and locale entries that do not yet exist in the DB — existing values are left untouched. The second command rewrites the PHP files so they always reflect the DB state.

> **First deploy / fresh environment:** if the DB is empty, seed it from the PHP files:
>
> ```
> php artisan translation-handler:sync php db --force
> ```

Syncing translations from production
------------------------------------

[](#syncing-translations-from-production)

When content editors have updated translations directly in production or staging, you can pull those changes back into the repository:

1. **Download the CSV** from the production admin panel via *Translations → Import / Export → Export to CSV*.
2. **Copy the file** into your project (e.g. `storage/lang/translations.csv`) and import it to regenerate the PHP files:

```
php artisan translation-handler:sync csv php --force
```

3. **Commit the updated PHP files** and push:

```
git add lang/
git commit -m "chore: sync translations from production"
git push
```

The next deploy will import the updated PHP files into any environment whose DB does not yet have those values.

AI integration (Laravel Boost)
------------------------------

[](#ai-integration-laravel-boost)

The underlying [LaravelTranslationHandler](https://github.com/BrunosCode/LaravelTranslationHandler) exposes its translation operations as [Model Context Protocol](https://modelcontextprotocol.io) tools through [Laravel Boost](https://github.com/laravel/boost). Boost is an **optional** dependency — install it only if you want an AI agent (e.g. in your editor) to read and edit translations directly.

```
composer require laravel/boost:^2.0
```

Once Boost is installed the core package auto-registers the translation MCP tools — no configuration. Any MCP-compatible agent (Claude, Cursor, GitHub Copilot, …) can then browse and edit translations directly. They cover the same operations as the admin panel and CLI:

- **Read** — `get-translation-config-tool`, `list-translation-groups-tool`, `list-translations-tool`, `find-translation-tool`
- **Write** — `set-translation-tool`, `set-all-locales-translation-tool`, `set-translation-group-tool`, `sync-translations-tool`, `delete-translation-tool`, `delete-translation-group-tool`
- **Maintenance** — `sort-translations-tool`, `check-translations-tool` (reports keys used in code but missing per locale)

The tools are registered by the core package and operate on the same database and language files described above. See the [LaravelTranslationHandler](https://github.com/BrunosCode/LaravelTranslationHandler) README for the full tool reference.

### Guidelines and skills

[](#guidelines-and-skills)

Running `php artisan boost:install` and selecting **twill-translation-handler (guidelines, skills)** installs an AI guideline plus two skills — `translation-handler-mcp` (the agent workflow) and `translation-handler-development` (writing custom PHP) — into your editor's agent. This package ships them because Boost only discovers the guidelines and skills of *direct* Composer dependencies: in a Twill app the core `laravel-translation-handler` package is a transitive dependency, so its own Boost resources would never be offered. The content is read live from the installed core package at install time, so it always reflects the installed `laravel-translation-handler` version, plus a Twill-specific note on editing translations from the admin.

Database Structure
------------------

[](#database-structure)

TableDescription`translation_keys`Translation keys (`key`, `published`)`translation_values`Per-locale values (`locale`, `value`, `active`)`translation_groups`Group prefixes (`prefix`, `published`)Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG.md](CHANGELOG.md) for what has changed recently.

Credits
-------

[](#credits)

- [BrunosCode](https://github.com/BrunosCode)
- [All Contributors](https://github.com/BrunosCode/TwillTranslationHandler/graphs/contributors)

Contributing
------------

[](#contributing)

Contributions are welcome! Please submit a pull request or open an issue to discuss what you would like to change.

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

46

—

FairBetter than 92% of packages

Maintenance95

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity53

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 81.4% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Recently: every ~13 days

Total

8

Last Release

43d ago

Major Versions

v0.2 → v1.02026-03-18

v1.0 → v2.02026-03-19

PHP version history (2 changes)v0.1PHP ^8.1

v1.0PHP ^8.2

### Community

Maintainers

![](https://www.gravatar.com/avatar/a76a0e4fa1309d69450b1e860c42a4cc7973277bda7a3b8aac15b14a1f78e408?d=identicon)[BrunosCode](/maintainers/BrunosCode)

---

Top Contributors

[![BrunosCode](https://avatars.githubusercontent.com/u/78606186?v=4)](https://github.com/BrunosCode "BrunosCode (57 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (8 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (5 commits)")

---

Tags

laravellaravel-packagelaravel-translation-managerlaravel-translationsmcp-toolstwilllaravelTwillTranslationHandlertwill-translation-handler

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/brunoscode-twill-translation-handler/health.svg)

```
[![Health](https://phpackages.com/badges/brunoscode-twill-translation-handler/health.svg)](https://phpackages.com/packages/brunoscode-twill-translation-handler)
```

###  Alternatives

[typicms/base

A modular multilingual CMS built with Laravel, enabling developers to manage structured content like pages, news, events, and more.

1.6k20.4k](/packages/typicms-base)[elegantly/laravel-translator

All on one translations management for Laravel

6326.3k](/packages/elegantly-laravel-translator)[osama-98/laravel-enum-translatable

A Laravel package that provides translatable enum functionality with easy-to-use methods for working with enum values and their translations

561.1k](/packages/osama-98-laravel-enum-translatable)[34ml/filament-translatable-field

A laravel filament field that handle translation

183.1k](/packages/34ml-filament-translatable-field)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
