Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Language Field Type Laravel Package

anomaly/language-field_type

A PyroCMS Streams Platform field type that adds a language selector to your forms, letting users pick from configured locales and storing the selected language code with each entry.

View on GitHub
Deep Wiki
Context7

Getting Started

What it is: A PyroCMS/Streams Platform field type addon (anomaly.field_type.language) that renders a language selector in the control panel, backed by the languages registered in the anomaly/language module. It is not a standalone Laravel form component — it requires a Streams-based application.

Prerequisites:

  • A PyroCMS 3 / Streams Platform app.
  • The anomaly/language module installed and seeded with at least one language (languages table).
  • The addon installed into the app, not just pulled into vendor/.

Install:

composer require anomaly/language-field_type
php artisan addon:install anomaly.field_type.language
php artisan addon:dump

If your platform version auto-discovers Streams addons via the composer manifest, the addon:install step still needs to run once to register the addon and run its migrations.

Where to look first:

  • src/LanguageFieldType.php — the field type class, its $columnType, $presenter, and the method that builds the selectable options.
  • src/LanguageFieldTypePresenter.php — runtime helpers for displaying a stored value.
  • resources/views/input.twig — the actual form markup (plain <select> or select2 depending on version).
  • src/LanguageFieldTypeServiceProvider.php — registration and asset loading.
  • resources/lang/{locale}/addon.php — the addon's own labels/instructions.

First use case: Add a locale to a "posts" stream so editors can tag content with a language, then filter and display entries by that code.

// In a stream migration
$stream->addField('language', [
    'type'   => 'anomaly.field_type.language',
    'config' => [
        'default_value' => config('app.locale'),
    ],
]);

Render it in a Streams form (automatic when the assignment exists), or explicitly in Twig:

{{ form.fields.language.input|raw }}

Read it back:

$entry->language;                        // raw stored value, e.g. "en"
$entry->presenter()->language->name();   // presenter helper, if provided

Confirm the presenter method names in LanguageFieldTypePresenter.php before relying on them; field type presenters in this ecosystem commonly expose name(), code(), and sometimes direction()/native().


Implementation Patterns

Define the field in a stream migration. The field type slug is anomaly.field_type.language.

$stream->addField('language', [
    'type'   => 'anomaly.field_type.language',
    'config' => [
        'default_value' => 'en',
        'instructions'  => 'Language this entry is written in.',
    ],
]);

Common config keys passed through by the Streams field type base class include default_value, placeholder, instructions, required, and rules. The addon may only consume default_value; verify in LanguageFieldType::getConfig() / getOptions().

Manual form building. When assembling a form with the FormBuilder instead of a stream assignment, use the same field type slug:

$builder->add('language', 'anomaly.field_type.language', [
    'config' => ['default_value' => app()->getLocale()],
]);

Validation. Treat the stored value as a language code string and validate membership explicitly — the field type does not guarantee the submitted code is still installed:

'language' => [
    'required',
    'string',
    Rule::in(array_keys($languageOptions)),
],

Where $languageOptions is derived from the language repository or from LanguageFieldType::getOptions().

Querying by language. The raw value is what you filter on:

PostModel::where('language', app()->getLocale())->get();

Multi-language content pattern. Combine the language field with a translation-group key to correlate translations of the same logical entry:

$stream->addField('language', ['type' => 'anomaly.field_type.language']);
$stream->addField('translation_key', ['type' => 'anomaly.field_type.slug']);

Then resolve a translation set with where('translation_key', $key)->get()->keyBy('language').

Restricting or customizing options. If you need a subset of languages, extend the field type and override its option-building method rather than duplicating the input view:

class CuratedLanguageFieldType extends \Anomaly\LanguageFieldType\LanguageFieldType
{
    public function getOptions()
    {
        return array_intersect_key(
            parent::getOptions(),
            array_flip(['en', 'fr', 'de'])
        );
    }
}

Register the subclass as its own addon/field type. The same extension point lets you swap in a repository call or a cached list.

Overriding the input view. The addon's resources/views/input.twig can be shadowed by a view in your app with the same namespaced path, or by extending the field type and overriding getInputView(). This is the cleanest place to add a flag icon, searchable select2, or a native <select> if the CP assets are missing.

Seeding and programmatic assignment. The value is just a field assignment on the entry model:

$post->language = 'en';
$post->save();

Presenter usage in templates. If the presenter is wired up, prefer it over raw codes wherever users see the value:

$entry->presenter()->language->name();

Fall back to the language repository when the presenter is null or the code has been removed:

app(\Anomaly\LanguageModule\Language\LanguageRepositoryInterface::class)
    ->findByCode($entry->language)
    ?->name;

Gotchas and Tips

It is an addon, not a package. Adding it to composer.json and stopping there will not make the field type available. Run addon:install, and after addon changes run addon:dump. Check php artisan addon:list to confirm it is registered.

Hard dependency on anomaly/language. If the language module is missing, disabled, or has no seeded languages, the dropdown renders empty with no obvious error. Check select * from languages first when the field "does nothing."

Confirm what is persisted. Read protected $columnType in LanguageFieldType.php and inspect the generated column. It is almost certainly a short string holding the language code, but if a version stores an ID, your queries, validation, and migration defaults are all different. Verify before writing production filters.

Presenter methods are not guaranteed. Field type addons in this ecosystem vary in what they expose. Open the presenter file and use only methods that exist. Guard against null when a stored code was deleted or deactivated in the languages module.

Default value quirks. default_value applies when the field type is instantiated for new entries; it is not a database column default. Existing rows and raw inserts will ignore it. If you need a database-level default, set it in the migration that creates the column.

Option queries on list views. If getOptions() queries the languages table on every render, a CP list with many rows can issue repeated queries. Cache the option map (languages change rarely) or override getOptions() in your own subclass.

Empty options after a language is deactivated. A stored code can become orphaned. Decide whether to fall back to the raw code, display a "missing language" label, or block deactivation in the language module.

Validation is on you. Do not assume the field type rejects a code that is not in the languages table. Add Rule::in(...) or exists:languages,code as appropriate, especially for APIs or frontend forms.

Control panel assets. If the input uses select2 and appears unstyled in a custom view, the addon's CP assets were likely not loaded. Either render the field through the standard Streams form pipeline or include the addon assets explicitly; overriding input.twig with a plain <select> is a reliable fallback.

Project health. This is a zero-star, zero-dependent addon in a legacy ecosystem. Pin the version in composer.json, read the source rather than relying on documentation, and expect compatibility constraints against modern Laravel/PHP. If it breaks, the fallback is anomaly/select-field_type with a static options array, or a small custom field type modeled on anomaly/country-field_type.

Debugging checklist:

  1. php artisan addon:list — is anomaly.field_type.language installed?
  2. app(LanguageRepositoryInterface::class)->all() in Tinker — are there languages?
  3. Inspect the stream assignment and the generated column type.
  4. Dump getOptions() output to confirm the code/name map.
  5. Check storage/logs/laravel.log for Twig or presenter errors when the input renders blank.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager