Download the PHP package alex-no/field-lingo without Composer
On this page you can find all versions of the php package alex-no/field-lingo. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download alex-no/field-lingo
More information about alex-no/field-lingo
Files in alex-no/field-lingo
Package field-lingo
Short Description Field-lingo β lightweight library to map structured multi-language column names (e.g. @@name) to localized DB columns, with Yii2, Yii3, Laravel, and Symfony integration and framework-agnostic core.
License MIT
Informations about the package field-lingo
ποΈ Field-lingo
Field-lingo β lightweight library to easily work with database columns that store multiple language versions of the same attribute in one row (e.g. name_en, name_uk, name_ru).
It provides a simple, consistent mechanism to reference "structured localized attribute names" (like @@name) and transparently map them to the actual column name_<lang> according to current language settings.
This repository contains full integrations for:
- Yii2 (ActiveRecord / ActiveQuery / DataProvider) β
src/Adapters/Yii2 - Yii3 (ActiveRecord / ActiveQuery) β
src/Adapters/Yii3 - Laravel (Eloquent Models / Query Builder) β
src/Adapters/Laravel - Symfony (Doctrine Entities / Repositories / QueryBuilder) β
src/Adapters/Symfony - Framework-agnostic core β
src/Corefor custom implementations
π Table of Contents
- Overview
- Requirements
- Key Classes
- Quick Start
- Yii2
- Yii3
- Laravel
- Symfony
- Detailed Usage (Yii2)
- Install
- Optional Recommendation
- Basic Idea
- Configure
- Configuration Options
- LocalizedAttributeTrait Behavior
- Usage Examples
- ActiveRecord
- ActiveQuery
- ActiveDataProvider
- Fallback Mechanism
- Exception Handling
- Advanced Topics
- Migration Guide
- Troubleshooting
- Core Design
- Directory Structure
- Examples
- Testing
- Contribution
- Roadmap
- License
- Contact
π Overview
Field-lingo provides three Yii2 adapters that transparently translate specially formatted field names into language-specific attributes. The pattern is simple: a prefix (by default @@) marks a structured field name. When Field-lingo encounters a name like @@name, it resolves the current language and converts that token to name_{lang} (for example name_en or name_uk).
Works in:
- Attribute access (
$model->@@name) and property-style ($model->namevia trait). - Query building:
select,where,orderBy,groupByusing@@names. - DataProvider sorting integration.
Primary goals:
- Allow code and queries to use language-agnostic field names (
@@title) and get language-specific attributes automatically. - Support per-adapter and per-model configuration (prefixes, fallback language, strict mode).
- Keep the adapter API close to native Yii classes so integration is minimal.
π¦ Requirements
- PHP: >= 8.2
Framework-specific requirements:
- Yii2: ^2.0 (for Yii2 adapter)
- Yii3: ^3.0 (yiisoft/active-record ^3.0, optional: yiisoft/translator ^3.0)
- Laravel: ^9.0 || ^10.0 || ^11.0 (for Laravel adapter)
- Symfony: ^5.4 || ^6.0 || ^7.0 (for Symfony adapter)
- Doctrine ORM: ^2.10 || ^3.0 (for Symfony/Doctrine adapter)
Optional but recommended:
- alex-no/language-detector β for automatic user language detection (requires separate configuration)
π§© Key classes
-
\FieldLingo\Adapters\Yii2\LingoActiveRecord- Extends
yii\db\ActiveRecord. - Used when working with model attributes (reads/writes, forms,
toArray()).
- Extends
-
\FieldLingo\Adapters\Yii2\LingoActiveQuery- Extends
yii\db\ActiveQuery. - Used to transform field names in conditions,
select()lists, and custom textual SQL logic within the query layer.
- Extends
\FieldLingo\Adapters\Yii2\LingoActiveDataProvider- Extends
yii\data\ActiveDataProvider(oryii\db\ActiveDataProviderdepending on implementation). - Used for operations that require field translation in the data provider level (for example sorting, pagination where attribute names are passed externally).
- Extends
These adapters rely on a shared trait LocalizedAttributeTrait which performs the core parsing and resolution logic.
βοΈ Quick Start
Installation
Choose your framework adapter:
Yii2
1. Install
Optional Recommendation
For automatic user language detection, it is recommended to install:
Note: This package requires its own separate configuration.
Basic idea
In DB table we keep language-specific columns:
In code we refer to @@name. FieldLingo maps @@name β name_{lang} (e.g. name_uk) depending on Yii::$app->language.
Configure
Add to params (or any config area) the LingoActive section (example):
Notes:
- Per-model overrides have higher priority than adapter-level defaults.
- The trait reads Yii::$app->params['LingoActive'] by adapter name or model class name.
Configuration options
Main options:
localizedPrefixes(string|array) β prefix(es) used to mark structured names. Default:@@.defaultLanguage(string) β fallback language when localized column is missing. Default:en.isStrict (bool)β if true throw when localized column missing; iffalsefallback todefaultLanguage.
These options may be set globally, per-class (LingoActiveRecord / LingoActiveQuery) or per-model.
Yii3
1. Install
2. Extend your models
3. Use localized attributes
4. Database Connection
The compatibility layer uses PDO for database access. You can configure it in two ways:
1. Via Dependency Injection (recommended):
2. Via Environment Variables:
5. Optional: Integrate with Translator service
6. Working with Relations
Compatibility Layer
The Yii3 adapter includes a compatibility layer (src/Adapters/Yii3/Compatibility/) that provides basic ActiveRecord and ActiveQuery functionality using PDO. This layer includes:
- Basic CRUD operations (
findOne(),all(),one(),count()) - Query building (
select(),where(),orderBy(),groupBy(),limit(),offset()) - Attribute management (
getAttribute(),setAttribute(), magic properties) - Simple relations support (
hasMany(),hasOne())
This compatibility layer is designed to work until Yii3 has an official stable ActiveRecord implementation.
Key Differences from Yii2:
- Explicit locale setting: Use
setLocale('uk')instead of relying onYii::$app->language - Translator integration: Optional integration with
yiisoft/translatorfor automatic locale detection - Modern PHP: Uses PHP 8.2+ type hints and return types
- No global state: Doesn't depend on global application configuration
See examples/Yii3/ for complete examples and detailed documentation.
Laravel
1. Extend your Eloquent models
2. Use localized attributes
See examples/Laravel/ for complete examples.
Symfony
1. Extend your Doctrine entities
2. Create repository
3. Use in controllers
See examples/Symfony/ for complete examples and configuration.
βοΈ Detailed Usage (Yii2)
π§ LocalizedAttributeTrait β behavior summary
The LocalizedAttributeTrait does the heavy lifting:
- Normalizes
localizedPrefixesto an array (supports a single prefix string or an array). - Reads runtime language from
Yii::$app->languageand uses its first part (e.g. en-US β en). - Produces a candidate attribute name
{base}_{lang}. - If the using class implements
hasAttribute()(as ActiveRecord does), the trait checks attribute existence:- If attribute exists β returns it.
- If not and
isStrict === trueβ throwsMissingLocalizedAttributeException. - If not and
isStrict === falseβ tries fallback{base}_{defaultLanguage}and returns it if exists; otherwise returns the candidate.
- If
hasAttribute()is not available (e.g. at query layer), the trait returns the candidate name and lets the caller use it in SQL / selections.
You can call $this->convertLocalizedFields([ ... ]) to map arrays of fields at once.
π Usage examples
ActiveRecord
When using LingoActiveRecord, you can reference localized attributes directly in code:
Notes for ActiveRecord:
- Because
hasAttribute()is available, missing localized columns are validated according toisStrict.- If you rely on
toArray()orfields()to export language-aware data, ensure the adapter or model callsconvertLocalizedFields()where appropriate.
ActiveQuery
LingoActiveQuery resolves names used in select(), andWhere(), orderBy(), groupBy() and similar places.
CRITICAL: Override the
find()method To useLingoActiveQuery, you must override thefind()method in your model:
Now you can use @@ fields in queries:
Notes for ActiveQuery:
- Query layer cannot check
hasAttribute()easily before SQL execution. The trait returns language-specific candidates and the DB will determine if the column exists.- Without overriding
find(), your queries will use standardActiveQueryand@@fields will not be converted.
ActiveDataProvider
LingoActiveDataProvider is helpful when you expose sorting/filtering to external requests (like GridView) and need to map @@ tokens to real DB columns.
Basic usage:
Usage with GridView:
Advanced: Custom sort configuration
Notes for ActiveDataProvider:
LingoActiveDataProviderautomatically converts@@field names in sort attributes and filter conditions.- When defining custom sort attributes, use
@@notation consistently across query, sort config, and GridView columns.- The provider works seamlessly with Yii2's pagination and filtering mechanisms.
π Fallback Mechanism
Field-lingo includes a smart fallback system to handle missing localized columns gracefully. The behavior depends on the isStrict configuration option.
How Fallback Works
When you request a localized attribute (e.g., @@title with current language = uk):
-
Library looks for
title_uk- If exists β returns
title_ukβ - If not exists β proceeds to step 2
- If exists β returns
-
Check
isStrictmode:- If
isStrict = trueβ throwsMissingLocalizedAttributeExceptionπ« - If
isStrict = falseβ tries fallback language (step 3)
- If
- Fallback to
defaultLanguage:- Library looks for
title_{defaultLanguage}(e.g.,title_enifdefaultLanguage = 'en') - If exists β returns
title_enβ - If not exists β returns candidate name
title_uk(DB will handle error if column truly missing)
- Library looks for
Configuration Examples
Strict mode (recommended for development):
Non-strict mode with fallback (production-friendly):
Practical Example
Per-Model Fallback Configuration
You can override fallback behavior for specific models:
Recommendation:
- Use
isStrict = trueduring development to catch missing translations early- Use
isStrict = falsein production to gracefully handle missing translations with fallback
β οΈ Exception
MissingLocalizedAttributeException is thrown when isStrict is enabled and a localized attribute candidate does not exist (only thrown when attribute existence can be checked).
Make sure this exception is available in the adapter namespace or imported where the trait is used.
π§© Advanced topics / hooks
- Custom language resolver: If your app resolves the current language from a non-standard place (cookie, user preferences, model property), consider overriding the trait by providing a
protected function resolveLanguage(): stringor modify the trait to call aresolveLanguage()hook. - Multiple prefixes: Set
localizedPrefixesto an array such as['@@', '##']to support multiple patterns. - Per-model overrides: Per-model keys in
LingoActiveallow you to change prefixes and strictness for specific models.
π Migration Guide
Migrating an existing Yii2 project to Field-lingo is straightforward. Follow these steps:
Step 1: Install the package
Step 2: Prepare database schema
If you don't have localized columns yet, add them to your tables:
Step 3: Configure Field-lingo
Add configuration to config/params.php or config/web.php:
Step 4: Update your models
Before (standard ActiveRecord):
After (LingoActiveRecord):
Step 5: Update controllers and views
Before:
After:
Step 6: Update DataProviders
Before:
After:
Step 7: Update GridView columns
Before:
After:
Step 8: Test thoroughly
Migration Checklist
- [ ] Database schema updated with localized columns
- [ ] Existing data migrated to default language columns
- [ ] Configuration added to params
- [ ] Models extend
LingoActiveRecord - [ ]
find()method overridden in models - [ ] Controllers updated to use
getAttribute()/setAttribute() - [ ] Views updated to use
getAttribute() - [ ] DataProviders changed to
LingoActiveDataProvider - [ ] GridView columns updated
- [ ] Search models updated (if using)
- [ ] Tests updated
- [ ] All functionality tested in both languages
Gradual Migration Strategy
You can migrate gradually by:
- Keep both old and new columns during transition period
- Migrate model by model instead of all at once
- Use per-model configuration to customize behavior:
π§ Troubleshooting
Problem: @@field notation is not working in queries
Symptoms: Queries like Post::find()->where(['@@title' => 'Test']) fail or @@title is treated as literal string.
Solution:
-
Make sure you've overridden the
find()method in your model: - Check that you're importing the correct class:
Problem: getAttribute('@@field') returns null or wrong value
Possible causes:
-
Configuration not loaded
- Check
Yii::$app->params['LingoActive']is properly configured - Verify config file is being loaded
- Check
-
Column doesn't exist in database
- If
isStrict = true, you'll getMissingLocalizedAttributeException - If
isStrict = false, library will try fallback language - Check database schema:
SHOW COLUMNS FROM your_table
- If
- Language format mismatch
- Current language:
Yii::$app->language(e.g.,en-US,uk) - Library uses first part:
en-USβen - Make sure column names match:
title_en,title_uk, etc.
- Current language:
Problem: GridView sorting not working with localized fields
Solution:
-
Use
LingoActiveDataProviderinstead ofActiveDataProvider: - Configure sort attributes with
@@notation:
Problem: How to check if Field-lingo is working correctly?
Quick test:
Problem: Exception "MissingLocalizedAttributeException"
Cause: isStrict = true and requested localized column doesn't exist in the table.
Solutions:
-
Add missing column to database:
-
Use fallback mode (non-strict):
- Add only columns you need:
- If you only support English and Ukrainian, only create
*_enand*_ukcolumns - Set
defaultLanguageto one you always have
- If you only support English and Ukrainian, only create
Problem: Getting "Unknown column" SQL error
Cause: Query uses @@field but it wasn't converted to actual column name.
Check:
- Model extends
LingoActiveRecord - Query uses
LingoActiveQuery(via overriddenfind()) - DataProvider uses
LingoActiveDataProvider - Column actually exists in database
FAQ
Q: Can I use multiple prefixes like @@ and ##?
A: Yes! Configure as array:
Q: Can I change the language dynamically during runtime?
A: Yes, Field-lingo reads Yii::$app->language on each call:
Q: Does Field-lingo work with relations?
A: Yes, as long as related models also extend LingoActiveRecord:
Q: Can I use this in forms and validation?
A: Yes, but reference actual column names in rules:
In forms, you can use @@ notation for display:
π§± Core design
Core/Localizer.php β centralized logic for mapping structured names to real column names.
Core/Contracts/LocalizerInterface.php β contract for Localizer implementations.
The core can be reused later for adapters (Laravel Eloquent, Doctrine, plain SQL builders).
π Directory Structure
Examples
- Yii2: See examples/Yii2/ for ActiveRecord and ActiveQuery examples
- Yii3: See examples/Yii3/ for modern Yii3 ActiveRecord examples with Translator integration
- Laravel: See examples/Laravel/ for Eloquent model and query examples
- Symfony: See examples/Symfony/ for Doctrine entity and repository examples with detailed README
π§ͺ Testing
Unit tests in tests/. PHPUnit recommended. Example:
- Add unit tests that switch Yii::$app->language and assert correct conversions.
- Test both strict and non-strict modes and per-model overrides.
π€ Contribution
Contributions welcome! Suggested workflow:
-
Fork repository.
-
Create feature branch.
-
Add tests.
- Open pull request.
Please follow PSR-12 and add PHPDoc (English) for public APIs.
πΊοΈ Roadmap
- β Core mapping logic.
- β Yii2 integration (ActiveRecord, ActiveQuery, DataProvider).
- β Yii3 integration (ActiveRecord, ActiveQuery with Translator support).
- β Laravel Eloquent adapter (Models, Query Builder).
- β Symfony/Doctrine adapter (Entities, Repositories, QueryBuilder).
- π§© Advanced column patterns: nested access, JSON, relation-aware localization.
- π‘ Optionally store translation meta in separate table(s) as alternative mode.
π License
MIT. See LICENSE.
π¬ Contact
*Field-lingo Β© 2025 Oleksandr Nosov. Released under the MIT License.