Skip to content

Phrases ​

Every text the site and its admin say, per module, theme and language: change a word, or translate the site into a language of your own — without a file.

kitloom/phrases · admins: kitloom/phrases-filament, kitloom/phrases-nova

Video lessons ​

Recorded in the Filament admin; the Nova admin works the same way.

Every text your site and its admin say — a button, a label, a message of a module, a theme or the application — listed per package and per language, so you can change a word or translate the site into a language kitloom does not ship, without touching a file. The Phrases screen is in both admins; kitloom/phrases-filament and kitloom/phrases-nova draw it.

What a phrase is — and what it is not ​

A phrase is a text written by a developer in the code: Read more, Add to cart, Leave a comment, Your order is on its way. Laravel calls these translation lines; the English sentence is the key, and a package may ship a translation of it in lang/<locale>.json. Phrases shows them to you, with the package's own line beside yours.

What you typed is not a phrase: the site's title, a page, a menu item, a product's name, a form's placeholders. Those are content, options and — with kitloom/languages — Site Texts, translated with the rest of the site. Phrases never touches them.

The Phrases screen ​

Phrases: change a word on your site

The first screen lists where the phrases come from — each module, each theme, the core packages, and This site (the application's own code) — with how many texts each says and, for every language, how many have a line. Open a package in a language to see its texts:

  • Source — the English text, as the code says it. Under it, also in N packages when other packages say the very same text: Laravel keeps one dictionary, so your line is read everywhere the text appears.
  • Shipped — what the package itself translates it as, when it does. Read-only: the file belongs to the package.
  • Yours — your line. Type it and it is shown on the site at once, on every page in that language. Empty it and the shipped text stands again.

A line must keep what the text fills in: :name, :count, %s, %1$s, and the | that separates plural forms (:count book|:count books). A line that lost one is refused with a note — the page would draw the text without its value otherwise.

Filters show the texts missing a line, those you changed, and the drafts. Sync reads the packages' code anew after an update.

Languages ​

Phrases: translate the site into your language

The editor offers the site's own language, the languages of kitloom/languages when it is installed, and any you add under More languages (a locale: de, uk, pt_BR). A line written for fr is read on a Canadian French page (fr_CA) too, unless fr_CA has a line of its own.

To make the site speak a language you translated, set Site Language in Settings → General to that locale: every language here is on its list. What has no line in it yet stays in English. With kitloom/languages, a page speaks that module's languages instead: add German there, and its lines come from here.

With an AI model ​

With kitloom/ai-writer set up, Translate empty with AI sends the texts that have no line in a language to the site's model, in the background. The answers come back as drafts: kept, marked, shown nowhere until you have read them — Publish drafts puts them on the site. A line the model returned without its placeholders is dropped and counted.

Files in and out ​

  • Import JSON — a dictionary file ("English text": "line") into a language: a translator's work, a lang/<locale>.json from another site.
  • Export JSON — a package's lines as its lang/<locale>.json, with the shipped lines merged in if you ask: the file a developer commits into the package, so the next site gets your translation out of the box.
  • Move to code — every line of a language written into the application's own lang/<locale>.json, which Laravel reads over the packages'; tick remove the rows and the file alone speaks from then on. For a site that has settled and keeps its words in git. The web server must be allowed to write lang/; the screen says when it is not.

The same from the console:

bash
php artisan phrases:scan                       # read the packages anew; counts per package
php artisan phrases:scan --check               # the texts without a line, per package and language; fails when any
php artisan phrases:export fr --package=kitloom/shop --merge   # the shop's lang/fr.json
php artisan phrases:export de --application --prune           # every German line into lang/de.json, rows removed
php artisan phrases:import translations.json --locale=de      # a dictionary into German

For developers ​

  • Lines live in the phrases table — group, key, locale, text, status, source, who wrote it — and reach Laravel's translator through spatie/laravel-translation-loader: its manager reads a group from the language files as Laravel does, then lays the loaders' lines over them. This module names itself as the one loader (translation-loader.translation_loaders); spatie's own Db loader and its language_lines table are not used. The manager is the module's TranslationManager (translation-loader.translation_manager): spatie's, built with the framework's own language files under the application's, as Laravel builds its loader — spatie leaves them out, and auth.failed would come back as the key. Namespaced groups (filament::…) never reach a loader, by spatie's design — Filament ships its own languages.
  • The lines of a group and a locale are read once into the cache and forgotten when one is written. A long-lived worker (Octane, a queue) compares a version in the cache at the start of each request and job, and drops the translator's lines when another worker wrote one.
  • Which texts a package says is read from its code with the same scanner the packages' translation tests use (Kitloom\WpSchema\Translations\CodeTexts): __(), trans_choice(), @lang(), a post type's declared labels, t() and __() in a theme's scripts, and the keys of its own lang/*.json. Scans are cached per package version; Sync or phrases:scan forgets them.
  • A line may also stand in for one of Laravel's own group files — auth, validation, passwords, pagination (validation.required) — through phrases:import/phrases_set with that group; other group files are the packages' alone. Laravel tries every text its files lack as a group (Read more → lang/en/Read more.php), so the loader answers for those four groups and the JSON lines only, and touches the table for nothing else.
  • A page cache is cleared whole when a line changes: the loader reads the cache, not the table, so no page's reads name the row.
  • Events: Kitloom\Phrases\Events\PhraseSaved, PhraseDeleted (the row, the actor), PhrasesTranslated (the AI job is done).
  • Agents (kitloom/ai): phrases_packages, phrases_list, phrases_set, behind manage_phrases; off with kitloom-phrases.ai.register.
  • Permission: manage_phrases — administrators. Settings: kitloom_phrases_locales, kitloom_phrases_scan_application.
  • Config kitloom-phrases.php: the admin switches, the AI switch, and scan.paths / scan.except — which directories of a package are read and which are passed over (tests, node_modules, vendor, dist).

kitloom — modules and themes for Laravel.
Contact · Pricing · Services · License · Refunds · Privacy · Community · YouTube · [email protected]