giovani / spelling
PHP spell checking library with Composite Pattern — Brazilian Portuguese (pt_BR) and American English (en_US) rules, Enchant dictionary support, and custom word lists.
Requires
- php: ^8.1
- doctrine/inflector: ^2.0
Requires (Dev)
- phpunit/phpunit: ^10.0
Suggests
- ext-enchant: Required by EnchantChecker for system-level dictionary support (Hunspell, Aspell).
README
PHP spell checking library with Composite Pattern — Brazilian Portuguese (pt_BR) and American English (en_US).
Features
- Brazilian Portuguese rules — 2009 Spelling Reform: trema removal, open diphthong accents, hyphenation
- American English rules — US vs UK spelling, pronoun
Icapitalization, days/months enforcement - System dictionary support — via PHP
ext-enchant(Hunspell, Aspell), any language - Custom word lists — allowlist domain-specific vocabulary at runtime
- Composite Pattern — chain multiple checkers transparently with unanimous AND logic
- Spell suggestions — every checker surfaces correction candidates via
getSuggestions()
Requirements
| Dependency | Version | Notes |
|---|---|---|
| PHP | ^8.1 |
Required |
doctrine/inflector |
^2.0 |
Required |
ext-enchant |
any | Optional — only needed for EnchantChecker |
Installation
composer require giovani/spelling
Optional: system dictionaries for EnchantChecker
# Ubuntu / Debian sudo apt-get install aspell-pt-br hunspell-pt-br # macOS brew install enchant
Verify the extension is loaded:
php -m | grep enchant
Quick Start
Brazilian Portuguese (recommended)
use Giovani\Spelling\SpellingFactory; $checker = SpellingFactory::createDefault(); // Post-reform words are accepted $checker->isValid('ideia'); // true $checker->isValid('linguiça'); // true // Pre-reform forms are rejected and corrected $checker->isValid('idéia'); // false $checker->getSuggestions('idéia'); // ['ideia'] $checker->getSuggestions('lingüiça'); // ['linguiça'] // Months and days of the week must be lowercase in pt_BR $checker->isValid('janeiro'); // true $checker->isValid('Janeiro'); // false $checker->getSuggestions('Janeiro'); // ['janeiro']
With a custom vocabulary
Pass additional words that should always be accepted (brand names, technical terms, etc.):
$checker = SpellingFactory::createDefault(['MinhaMarca', 'Laravel', 'NomeTécnico']); $checker->isValid('minhamarca'); // true $checker->isValid('laravel'); // true
American English
use Giovani\Spelling\Checkers\CompositeSpellingChecker; use Giovani\Spelling\Checkers\AmericanEnglishRulesChecker; use Giovani\Spelling\Checkers\EnchantChecker; $composite = new CompositeSpellingChecker(); $composite->addChecker(new AmericanEnglishRulesChecker()); $composite->addChecker(new EnchantChecker('en_US')); $composite->isValid('color'); // true $composite->isValid('colour'); // false — British spelling rejected $composite->getSuggestions('colour'); // ['color'] $composite->isValid('I'); // true $composite->isValid('i'); // false — pronoun must be capitalized $composite->getSuggestions('i'); // ['I'] $composite->isValid('Monday'); // true $composite->isValid('monday'); // false
Building fully custom composites
use Giovani\Spelling\Checkers\CompositeSpellingChecker; use Giovani\Spelling\Checkers\PortugueseRulesChecker; use Giovani\Spelling\Checkers\SimpleSpellingChecker; $composite = new CompositeSpellingChecker(); $composite->addChecker(new PortugueseRulesChecker()); $composite->addChecker(new SimpleSpellingChecker(['PHP', 'Composer', 'Packagist'])); $composite->isValid('php'); // true $composite->isValid('idéia'); // false — Portuguese rule violation
Available Checkers
| Checker | Description | Language |
|---|---|---|
SimpleSpellingChecker |
Validates against a custom in-memory allowlist | Any |
CompositeSpellingChecker |
Chains multiple checkers (unanimous AND logic) | Any |
EnchantChecker |
System dictionary via ext-enchant |
Any (pt_BR, en_US, …) |
PortugueseRulesChecker |
2009 Spelling Reform rules for pt_BR | Portuguese |
AmericanEnglishRulesChecker |
US spelling and capitalization conventions | English (US) |
InflectorChecker |
Word normalization via Doctrine Inflector | English |
All checkers implement the same interface:
interface SpellingCheckerInterface { public function isValid(string $word): bool; /** @return string[] */ public function getSuggestions(string $word): array; }
Architecture
The library is built on the Composite design pattern. CompositeSpellingChecker holds a collection of SpellingCheckerInterface leaves and requires unanimous approval — all checkers must return true for a word to be considered valid. Suggestions are aggregated from every checker and deduplicated.
SpellingCheckerInterface
├── CompositeSpellingChecker ← groups checkers, AND logic, deduplicates suggestions
│ ├── PortugueseRulesChecker
│ ├── InflectorChecker
│ ├── EnchantChecker
│ └── SimpleSpellingChecker
└── (any custom checker implementing the interface)
SpellingFactory::createDefault() assembles the recommended pt_BR stack automatically, with EnchantChecker added gracefully when ext-enchant is available.
Running Tests
composer install vendor/bin/phpunit
Documentation
Full documentation is available in the docs/ directory:
Contributing
Contributions, bug reports, and feature requests are welcome. Please open an issue or pull request on GitHub.
License
MIT — see LICENSE.