Fix double-escaped quote regex in translation catalogs - #64
Open
YoannChabert wants to merge 2 commits into
Open
Conversation
MinkContext's step definitions are declared as PHP single-quoted string attributes, e.g. '/^(?:|I )press "(?P<button>(?:[^"]|\\")*)"$/'. PHP decodes \\" to a single backslash followed by a quote before Behat uses that decoded string as the translation msgid. The i18n/*.xliff catalogs are raw XML CDATA, not PHP string literals, so they go through no such decoding. Every <source> entry that used \\" therefore held a different byte sequence (backslash-backslash-quote) than the actual msgid Behat looks up (backslash-quote), causing an exact-match failure in the translator for every step whose regex contains an escaped-quote alternative — the large majority of MinkContext's string-argument steps (press, follow, fill in, select, check, uncheck, attach file, should (not) see, field should (not) contain, etc.). Because the msgid never matched, Behat silently fell back to untranslated matching for these steps in every non-English locale, so translated feature files could not use them at all. Fix: strip the extra backslash so <source> exactly mirrors the PHP-decoded regex, and apply the same correction to <target> where present, across all 17 translation catalogs (all locales but English, which needs no catalog). Verified byte-for-byte against the actual attribute string via reflection for the i-press-button unit.
features/search.fr.feature mirrors search.feature but is written entirely in French (Gherkin keywords via '# language: fr', step text via the fr.xliff translations), exercising four of the steps affected by the previous double-escaping bug: "je suis sur", "je remplis ... avec ...", "je presse", "je devrais voir". Confirmed the regression this guards against: running this feature with a --dry-run against the pre-fix fr.xliff reports 6 of 8 steps as undefined (every affected step except "je suis sur", whose regex doesn't use the escaped-quote alternative). With the fix, all 8 steps are recognized, and the full suite passes against Wikipedia the same way the existing English suite does.
Author
|
Added `features/search.fr.feature` — a French translation of the existing `search.feature`, exercising 4 of the affected steps (`je suis sur`, `je remplis ... avec ...`, `je presse`, `je devrais voir`). Confirmed the regression this guards against by running it with `--dry-run` against the pre-fix `fr.xliff`: (`je suis sur` is the one step here whose regex doesn't use the escaped-quote alternative, so it was already matching.) With the fix, all 8 steps are recognized and the suite passes for real against Wikipedia, the same way the existing English `search.feature` does in CI: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Every non-English translation catalog under
i18n/*.xliff(17 files:cs,da,de,es,fr,hu,id,it,ja,nl,pl,pt,pt-br,ro,ru,sk,sv,zh-CN) has a<source>(and, where the same construct appears,<target>) entry that is a byte-for-byte mismatch with the actual regex Behat looks up as a translation key, for every step whose pattern contains an escaped-quote alternative such as(?:[^"]|\\")*. In practice this is most ofMinkContext's string-argument steps:press,follow,fill in,select,check,uncheck,attach the file,should (not) see,the field should (not) contain,the element should (not) contain, etc.Root cause
MinkContext's step patterns are declared as PHP single-quoted string literals, e.g.:PHP decodes the
\\"escape sequence in a single-quoted string to a single backslash followed by a literal quote before Behat ever sees the string. That decoded string — one backslash, one quote — is what Behat's translator uses as the lookup key (msgid) against each catalog's<source>.The
i18n/*.xlifffiles are raw XMLCDATA, not PHP string literals, so there is no such decoding step for their contents. Every affected<source>still contained the literal two-backslash sequence\\"(i.e. an actual backslash character followed by a quote character, four bytes wide:\,\,"), rather than the one-backslash sequence Behat actually looks for.Because Symfony's translator does an exact match on the
msgid, the lookup silently fails for all of these entries. The practical effect: any step that uses this escaped-quote pattern is never translated in any locale — writing a# language: xxfeature file and using, say, "I press" translated into that language for these steps doesn't work, with no error, just a step definition that doesn't match.Fix
Strip the redundant backslash so each
<source>(and<target>, where it also used the pattern) exactly mirrors the string PHP actually decodes from the corresponding attribute inMinkContext.php. Applied identically across all 17 locale files — this is the same bug repeated in every catalog, not a per-language issue.Verified byte-for-byte for a sample unit (
i-press-button) viaReflectionClass/ReflectionAttributeagainst the liveMinkContext::pressButtonstep definition (both hex-dumped to 43 identical bytes) rather than by inspection alone.Test plan
hex_dump/ReflectionAttributecomparison that the fixedfr.xliff<source>fori-press-buttonis now byte-identical to the actual PHP-decoded regex used byMinkContext::pressButton.features/search.fr.feature, a French translation of the existingsearch.feature, exercising 4 of the affected steps. Confirmed it reproduces the regression against the pre-fix catalog (6 of 8 steps undefined) and passes fully with the fix (8/8 steps, full suite green against Wikipedia) — see comment below for details.