Skip to content

feat: add XLIFF 2.x support to XliffParser#107

Merged
konradmichalik merged 2 commits intomainfrom
feature/xliff-2-support
Mar 26, 2026
Merged

feat: add XLIFF 2.x support to XliffParser#107
konradmichalik merged 2 commits intomainfrom
feature/xliff-2-support

Conversation

@konradmichalik
Copy link
Copy Markdown
Contributor

@konradmichalik konradmichalik commented Mar 26, 2026

Closes #105

Summary

  • Add XLIFF 2.0/2.1/2.2 parsing support to XliffParser
  • Handle structural differences between XLIFF 1.2 and 2.x (unit/segment vs trans-unit/body, srcLang/trgLang vs source-language/target-language)
  • Version detection via version_compare() to cover all 2.x versions

Changes

  • src/Parser/XliffParser.php - Detect XLIFF version, delegate to version-specific XML paths for units, content, and language attributes
  • tests/src/Parser/XliffParserTest.php - Add 7 test cases for XLIFF 2.0 and 2.2 (key extraction, content retrieval, language detection, fallback behavior)

Summary by CodeRabbit

  • New Features

    • Support for XLIFF 2.0 and 2.2 parsing, including improved extraction of translation units and content retrieval.
    • Smarter primary-vs-fallback selection when source or target text is missing.
  • Bug Fixes

    • Handles missing/empty translation units gracefully and improves language detection for XLIFF v2 files.
  • Tests

    • Expanded test coverage for XLIFF 2.0/2.2 scenarios (key extraction, content selection, and language handling).

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 26, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

Added XLIFF 2.0/2.2 support by detecting version in the parser, branching parsing behavior for v1 vs v2 XML structures, refactoring key/content extraction into new helpers, and extending language/target detection. Tests for XLIFF 2.0 and 2.2 were added.

Changes

Cohort / File(s) Summary
Parser (XLIFF v1 & v2 branching)
src/Parser/XliffParser.php
Introduce private $isVersion2 flag; add getTranslationUnits() and getUnitContent() helpers; refactor extractKeys() and getContentByKey() to iterate units safely and return null/empty when no units; adjust language/target detection to read srcLang/trgLang for v2 and fallback to v1 attributes.
Tests: XLIFF v2 fixtures & cases
tests/src/Parser/XliffParserTest.php
Add XLIFF 2.0 and 2.2 test fixtures (source-only and source+target) and new PHPUnit cases verifying key extraction, source/target selection, language reading from srcLang, and fallback behavior for empty/missing elements.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰
I hopped through tags and units bright,
Found source and target in the night,
Version two at last I cheer,
Keys and language now appear,
A tiny hop — translations clear! 🎋

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: adding XLIFF 2.x support to XliffParser, which is the primary objective of this pull request.
Linked Issues check ✅ Passed The PR successfully addresses issue #105 by implementing XLIFF 2.x parsing support with version detection and handling structural differences (unit/segment vs trans-unit/body, srcLang/trgLang attributes), resolving the foreach() null error reported in TYPO3 v14 XLIFF 2.0 files.
Out of Scope Changes check ✅ Passed All changes are directly aligned with the PR objectives: XliffParser modifications add XLIFF 2.x support, and test additions comprehensively validate new functionality for versions 2.0 and 2.2 without unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/xliff-2-support

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 PHPStan (2.1.44)

Composer install failed: this project depends on private packages that require authentication (e.g. GitLab/GitHub, Laravel Nova, etc.).
CodeRabbit tooling environment cannot access private registries.
If your project requires private packages, disable the PHPStan tool in your coderabbit settings.

Instead, run PHPStan in a CI/CD pipeline where you can use custom packages — our pipeline remediation tool can use the PHPStan output from your CI/CD pipeline.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
tests/src/Parser/XliffParserTest.php (1)

458-480: Consider adding edge case test for XLIFF 2.0 with no translation units.

The existing tests cover the happy path well. For completeness, consider adding a test for an XLIFF 2.0 file with an empty <file> element (no <unit> children) to verify that extractKeys() returns an empty array.

Example test case
public function testExtractKeysReturnsEmptyArrayWhenNoUnitsXliff2(): void
{
    $emptyUnitsFile = $this->tempDir.'/empty_units_v2.xlf';
    $emptyUnitsContent = <<<'EOT'
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="en">
  <file id="messages">
  </file>
</xliff>
EOT;
    file_put_contents($emptyUnitsFile, $emptyUnitsContent);

    $parser = new XliffParser($emptyUnitsFile);
    $this->assertSame([], $parser->extractKeys());
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/src/Parser/XliffParserTest.php` around lines 458 - 480, Add a new unit
test method (e.g., testExtractKeysReturnsEmptyArrayWhenNoUnitsXliff2) that
creates an XLIFF 2.0 file whose <file> element has no <unit> children,
instantiates XliffParser with that file, and asserts that
XliffParser::extractKeys() returns an empty array; ensure the test writes the
file to the same tempDir pattern used in other tests and uses the parser methods
(extractKeys and optionally getLanguage) to validate behavior.
src/Parser/XliffParser.php (1)

59-72: Behavioral change: extractKeys() now returns [] instead of null when units are missing.

Returning an empty array instead of null when translation units are unavailable is a valid approach within the interface contract (array<int, string>|null). However, this is a subtle semantic shift: previously null may have indicated an error condition, while now [] indicates "no keys found."

Based on the relevant code snippets, existing validators handle this correctly:

  • MismatchValidator and DuplicateValuesValidator use if (!$keys) which handles both cases.
  • PlaceholderConsistencyValidator uses if (null === $keys) which becomes ineffective, but the foreach loop safely handles empty arrays.

No immediate fix needed, but consider documenting this behavior in the interface or aligning the guard in PlaceholderConsistencyValidator for consistency.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Parser/XliffParser.php` around lines 59 - 72, extractKeys() now returns
an empty array instead of null when getTranslationUnits() yields no units;
update the guard in PlaceholderConsistencyValidator (the method that currently
does if (null === $keys)) to treat empty arrays the same as null (e.g., change
the check to if (!$keys) or if (null === $keys || [] === $keys)) so it aligns
with MismatchValidator and DuplicateValuesValidator and preserves the original
semantic for "no keys available"; leave extractKeys() as-is.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Parser/XliffParser.php`:
- Around line 130-137: The getTranslationUnits() helper returns a
SimpleXMLElement even when no child nodes exist, so any downstream null checks
(e.g., the checks around retrieval of units in the parser) are ineffective;
update the code that expects null by replacing those null comparisons with an
explicit empty check using count() or casting to (array) to detect zero children
and return null when count($this->getTranslationUnits()) === 0 (or equivalent),
and update getTranslationUnits() callers to treat an empty SimpleXMLElement as
absent; specifically look at getTranslationUnits(), and the places that
previously did `null === $units` (the checks around retrieval of units) and
change them to use a count() === 0 test.

---

Nitpick comments:
In `@src/Parser/XliffParser.php`:
- Around line 59-72: extractKeys() now returns an empty array instead of null
when getTranslationUnits() yields no units; update the guard in
PlaceholderConsistencyValidator (the method that currently does if (null ===
$keys)) to treat empty arrays the same as null (e.g., change the check to if
(!$keys) or if (null === $keys || [] === $keys)) so it aligns with
MismatchValidator and DuplicateValuesValidator and preserves the original
semantic for "no keys available"; leave extractKeys() as-is.

In `@tests/src/Parser/XliffParserTest.php`:
- Around line 458-480: Add a new unit test method (e.g.,
testExtractKeysReturnsEmptyArrayWhenNoUnitsXliff2) that creates an XLIFF 2.0
file whose <file> element has no <unit> children, instantiates XliffParser with
that file, and asserts that XliffParser::extractKeys() returns an empty array;
ensure the test writes the file to the same tempDir pattern used in other tests
and uses the parser methods (extractKeys and optionally getLanguage) to validate
behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 33c92138-2470-490d-a388-604ea756f3bc

📥 Commits

Reviewing files that changed from the base of the PR and between ec3b6f8 and dfb12b5.

📒 Files selected for processing (2)
  • src/Parser/XliffParser.php
  • tests/src/Parser/XliffParserTest.php

@konradmichalik konradmichalik merged commit e5671fc into main Mar 26, 2026
33 of 36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TYPO3 v14 XLIFF 2.0

1 participant