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

Autotext Laravel Package

meniam/autotext

AutoText is a Laravel package that automates text translation for multilingual apps. It translates selected model fields via a translation service, reducing manual copy work and making localized content easier to manage.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin.

composer require meniam/autotext

The last release is April 2020, so before anything else open composer.json in the package and check the php and symfony/* constraints. On PHP 8.1+ you will likely hit deprecation noise (implicit nullable params, dynamic properties) even if it still runs. If you're on Laravel 10/11, treat this as a "wrap it, don't spread it" dependency — pin the exact version in composer.lock and avoid ^ ranges, because there is no maintainer to ship a PHP 9 fix.

Where to look first.

  1. vendor/meniam/autotext/src — the public entry point is a small number of classes; find the one that takes a template string and returns text.
  2. vendor/meniam/autotext/tests — with a 5-star, 2020-era package, the test suite is the documentation for template syntax. Read every fixture string in there before writing your own templates.
  3. The README for the template grammar (alternation/spin syntax, placeholder tokens). The grammar is the whole product; the PHP API is a thin shell around it.

First use case. Generate a product or category meta description from structured attributes rather than from nothing:

// config/autotext.php — copy this out of the vendor dir so it survives updates
return [
    'templates' => [
        'product.meta' => 'Buy {name} — {color|shade|finish} {model}, {in_stock|ready to ship|available now}.',
        'category.intro' => '{Category} selection: {count} items from {brand_a|brand_b|brand_c}.',
    ],
];

Then generate once, at write time, and persist the result into a meta_description column — not on every page render (see Gotchas).

Laravel wiring. Don't rely on auto-discovery here; assume there is no service provider. Register the generator as a singleton in your own AppServiceProvider so dictionary/synonym configuration is loaded once, and bind it behind an interface:

$this->app->singleton(TextGenerator::class, fn () => new AutoTextAdapter(
    config('autotext.templates'),
    config('autotext.dictionaries'),
));

That adapter is your firewall. If the package dies, you rewrite one class.

Implementation Patterns

Adapter + interface, always. The day-to-day ergonomics of a 2020 SEO library are fine until you need to swap it for a maintained alternative or an LLM call. Give it one seam:

interface TextGenerator
{
    public function render(string $templateKey, array $data, ?int $seed = null): string;
}

class AutoTextAdapter implements TextGenerator
{
    public function render(string $templateKey, array $data, ?int $seed = null): string
    {
        // one call into the package; everything else is your code
        return $this->generator->generate($this->templates[$templateKey], $data);
    }
}

Templates live in the database, not in code. The whole reason to use this package is that copywriters iterate on phrasing without a deploy. Store template_key, body, version, locale, is_active in a table, cache the resolved set, and invalidate on save. You get an audit trail of what text was generated from which template version for free.

Generate at write time, not read time. The single most important pattern for SEO use: on product import / category save, run the generator, store the output. This gives you stable, cacheable HTML, allows human review, and prevents the same product returning different text on two crawls.

Seed your randomness. If the package picks alternatives randomly, you want reproducibility for debugging and for "regenerate but get the same thing back". Wrap generation in a seed derived from entity_id so the same product always yields the same variant:

mt_srand(crc32("product:{$product->id}:{$template->version}"));
$text = $this->generator->render($template->body, $product->toArray());
mt_srand(); // restore

Batch via jobs. Generating for 50k SKUs belongs in a queued job with chunking, per-chunk error capture, and a progress/failed_at column. Never inside a request or an importer's synchronous loop — a single malformed template will otherwise abort the whole import.

Integration points that pay off:

  • A @autotext('product.meta', $product) Blade directive is tempting — resist it for anything crawler-visible. Use it only for internal previews.
  • Bind as an injectable dependency and fake it in tests: $this->mock(TextGenerator::class) returning a fixture string. Your feature tests should never exercise the template engine.
  • If you have a translation layer already, store a separate template set per locale; don't try to make one template serve both. Russian-language origin means grammar patterns are language-specific (see below).

Testing pattern. Three assertions per template: (1) output is non-empty and within your meta-length budget; (2) over 500 renders with different seeds, no placeholder token or raw {/| leaks into output; (3) with a fixed seed, output is byte-identical — catches accidental global-state bugs.

Gotchas and Tips

It is unmaintained. Plan for the exit. Last release 2020, zero dependents, five stars. Vendor the class if you must, or keep the adapter thin enough that replacement is a day's work. Don't let template strings and the engine's dialect leak into code outside the adapter.

Russian-language heritage. This class of library grew out of Cyrillic "spin text" tooling, where morphology (case/gender agreement) matters. If it exposes word-form dictionaries, they are almost certainly Russian. For English content you are essentially getting alternation ({a|b|c}) and placeholder substitution — which is fine, but don't budget for grammatical inflection you won't get. Verify against the package's own test fixtures.

Exponential blowup on nested alternation. {a|b} {c|d} {e|f} is 8 combinations; nesting three levels deep with long lists runs into thousands. Two consequences: generation time, and — more importantly — a small pool of outputs that search engines see as near-duplicate boilerplate across thousands of pages. Cap the cartesian size when validating a template at save time and reject anything above your threshold.

Duplicate content is the real SEO risk. Pure spun text on thin pages is exactly what Google's spam policies target. Use this package on pages that have genuine substance (real attributes, real prices, real specs) and let it only phrase the connective tissue. Never use it to manufacture a page whose only content is generated prose.

HTML escaping and encoding. Output will be embedded in <title>, meta description, or HTML body — each needs different escaping. The library returns raw text; escape at the edge (e() for attributes, plain for titles) and store the unescaped version in the DB so you can re-render into different contexts. Confirm the engine is mb_*-safe on UTF-8 input; a 2020 library doing strlen/substr will truncate multibyte characters mid-sequence and produce mojibake in your meta descriptions.

Silent failure modes. Missing dictionary keys or unknown placeholders typically render as an empty string or as the literal token — no exception. Guard at the boundary:

$text = $this->adapter->render($key, $data);

abort_if($text === '' || str_contains($text, '{') || str_contains($text, '}'),
    new TextGenerationException("Template [{$key}] produced invalid output"));

Log the template key, version, and input data on failure. Without that, debugging a bad meta description on one product out of 40k is miserable.

Length budgeting. Meta descriptions have a ~155-character soft limit. Do this check inside the generator wrapper, not in a review process — reject-at-write is the only thing that scales. Better: give each template a max_length and have the adapter try N variants (different seeds) and pick the first that fits, which also naturally diversifies output.

Debugging the grammar. When a template renders wrong, don't guess — dump the parsed token stream (most such engines have a parse/tokenize step you can call directly) and diff it against what you expected. Write templates in isolation, in a unit test, before wiring them to data.

Extension points to look for. Two are worth the dig through src: (a) a way to inject a custom dictionary/synonym provider — lets your SEO team manage synonyms in the admin rather than in PHP arrays; (b) a way to override the random-selection strategy — needed for weighted variants (e.g. the primary phrasing 80% of the time). If neither exists, do the selection yourself before calling the engine and keep the package doing pure substitution.

Composer hygiene. Check for symfony/console or symfony/yaml pins that conflict with your Laravel version; if the package pulls in a Symfony major you don't use, composer why meniam/autotext before assuming the conflict is your fault.

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.
takashato/laravel-vietqr
aitor24/laralang
kraenzle-ritter/entity-relations
dindigital/din-image
pomirleanu/image-colors
sawmainek/laravel-api-generator
delatbabel/jsonresponses
mouhamedfd/permissions-generator
eduplus/qr
laravel2580/idehelpers
delatbabel/viewpages
anavel/gettext
muhamadrezaar/highcharts
delatbabel/keylists
frankkessler/salesforce-laravel-oauth2-rest
anavel/foundation
wdmtech/enviricons
eii/laravel-captcha
muka/shape-reader
tdt/json