PHPackages                             opencat/qa - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. opencat/qa

ActiveLibrary[Testing &amp; Quality](/categories/testing)

opencat/qa
==========

Per-segment quality checks for the OpenCAT Framework

00PHP

Since May 9Pushed 1mo agoCompare

[ Source](https://github.com/shaikhammar/opencat-qa)[ Packagist](https://packagist.org/packages/opencat/qa)[ RSS](/packages/opencat-qa/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

opencat/qa
==========

[](#opencatqa)

Per-segment quality checks for the [OpenCAT Framework](https://github.com/shaikhammar/opencat-framework).

`QualityRunner` runs registered checks against a `BilingualDocument` and returns `QualityIssue` objects. Checks are small, independent classes — register only the ones you need.

Installation
------------

[](#installation)

```
composer require opencat/qa
```

Requires `ext-intl` and `ext-mbstring`.

Usage
-----

[](#usage)

```
use CatFramework\Qa\QualityRunner;
use CatFramework\Qa\Check\TagConsistencyCheck;
use CatFramework\Qa\Check\NumberConsistencyCheck;
use CatFramework\Qa\Check\EmptyTranslationCheck;
use CatFramework\Qa\Check\WhitespaceCheck;
use CatFramework\Qa\Check\DoubleSpaceCheck;

$runner = new QualityRunner();
$runner->register(new TagConsistencyCheck());
$runner->register(new NumberConsistencyCheck());
$runner->register(new EmptyTranslationCheck());
$runner->register(new WhitespaceCheck());
$runner->register(new DoubleSpaceCheck());

// Run against a full document
$issues = $runner->run($doc);

foreach ($issues as $issue) {
    echo "[{$issue->severity->name}] {$issue->checkId}: {$issue->message}" . PHP_EOL;
    echo "  Segment: {$issue->segmentId}" . PHP_EOL;
}
```

Built-in per-segment checks
---------------------------

[](#built-in-per-segment-checks)

These implement `QualityCheckInterface` and run on every `SegmentPair`:

ClassCheck IDSeverityWhat it flags`EmptyTranslationCheck``empty_translation`ERRORTarget segment is empty or whitespace-only`TagConsistencyCheck``tag_consistency`ERRORTarget has different `InlineCode` count or types than source`NumberConsistencyCheck``number_consistency`WARNINGNumbers present in source are absent from target`WhitespaceCheck``whitespace`INFOLeading or trailing whitespace mismatch between source and target`DoubleSpaceCheck``double_space`INFOTarget contains two or more consecutive spaces`TerminologyConsistencyCheck``terminology_consistency`WARNINGA forbidden term is used, or a known source term has no match in the target`TerminologyConsistencyCheck` requires a `TerminologyProviderInterface` instance:

```
use CatFramework\Qa\Check\TerminologyConsistencyCheck;
use CatFramework\Terminology\Provider\SqliteTerminologyProvider;

$provider = new SqliteTerminologyProvider('glossary.db');
$runner->register(new TerminologyConsistencyCheck($provider));
```

Built-in document-level checks
------------------------------

[](#built-in-document-level-checks)

These implement `DocumentQualityCheckInterface` and scan the full document after per-segment checks:

ClassCheck IDSeverityWhat it flags`SegmentConsistencyCheck``segment_consistency`WARNINGIdentical source segments that have divergent translations```
use CatFramework\Qa\Check\SegmentConsistencyCheck;

$runner->registerDocumentCheck(new SegmentConsistencyCheck());
$allIssues = array_merge($runner->run($doc), $runner->runOnDocument($doc));
```

Running on a single segment pair
--------------------------------

[](#running-on-a-single-segment-pair)

```
$issues = $runner->runOnPair($pair, 'en-US', 'fr-FR');
```

Useful for incremental QA as the translator edits individual segments.

Writing a custom check
----------------------

[](#writing-a-custom-check)

```
use CatFramework\Core\Contract\QualityCheckInterface;
use CatFramework\Core\Enum\QualitySeverity;
use CatFramework\Core\Model\QualityIssue;
use CatFramework\Core\Model\SegmentPair;

class NoCapsCheck implements QualityCheckInterface
{
    public function getId(): string { return 'no_all_caps'; }
    public function getName(): string { return 'No All-Caps Words'; }

    public function check(SegmentPair $pair, string $sourceLanguage, string $targetLanguage): array
    {
        if ($pair->target === null) {
            return [];
        }

        $text = $pair->target->getPlainText();

        if (preg_match('/\b[A-Z]{3,}\b/u', $text)) {
            return [new QualityIssue(
                checkId: $this->getId(),
                severity: QualitySeverity::WARNING,
                message: 'Target contains all-caps word.',
                segmentId: $pair->source->id,
            )];
        }

        return [];
    }
}

$runner->register(new NoCapsCheck());
```

Severity levels
---------------

[](#severity-levels)

`QualitySeverity`Meaning`INFO`Style suggestion — informational only`WARNING`Probable error — should be reviewed`ERROR`Definite error — must be fixed before deliveryThe [`opencat/workflow`](https://github.com/shaikhammar/opencat-framework/tree/main/packages/workflow) `WorkflowOptions::$qaFailOnSeverity` option throws `WorkflowException` if any issue reaches the configured severity level.

Related packages
----------------

[](#related-packages)

- [`opencat/core`](https://github.com/shaikhammar/opencat-framework/tree/main/packages/core) — `QualityCheckInterface`, `DocumentQualityCheckInterface`, `QualityIssue`, `QualitySeverity`
- [`opencat/terminology`](https://github.com/shaikhammar/opencat-framework/tree/main/packages/terminology) — provides `TerminologyProviderInterface` for `TerminologyConsistencyCheck`
- [`opencat/workflow`](https://github.com/shaikhammar/opencat-framework/tree/main/packages/workflow) — runs QA as the fourth step in the pipeline; supports `qaFailOnSeverity` threshold

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance61

Regular maintenance activity

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity11

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/c6b9044413071860fd6199e56c661a24f449797b77a1b130f0df7e98be8481f4?d=identicon)[shaikhammar](/maintainers/shaikhammar)

---

Top Contributors

[![actions-user](https://avatars.githubusercontent.com/u/65916846?v=4)](https://github.com/actions-user "actions-user (3 commits)")

### Embed Badge

![Health badge](/badges/opencat-qa/health.svg)

```
[![Health](https://phpackages.com/badges/opencat-qa/health.svg)](https://phpackages.com/packages/opencat-qa)
```

###  Alternatives

[szepeviktor/phpstan-wordpress

WordPress extensions for PHPStan

3309.4M1.2k](/packages/szepeviktor-phpstan-wordpress)[dms/phpunit-arraysubset-asserts

This package provides ArraySubset and related asserts once deprecated in PHPUnit 8

14228.7M340](/packages/dms-phpunit-arraysubset-asserts)[jasonmccreary/laravel-test-assertions

A set of helpful assertions when testing Laravel applications.

3524.1M38](/packages/jasonmccreary-laravel-test-assertions)[orchestra/workbench

Workbench Companion for Laravel Packages Development

8219.1M67](/packages/orchestra-workbench)[soyuka/contexts

Behatch contexts

282.2M21](/packages/soyuka-contexts)[roquie/laravel-dusk-select2

Select2.js support for the Laravel Dusk testing.

41356.2k5](/packages/roquie-laravel-dusk-select2)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
