Skip to content

Decode msgctxt using the catalog's charset in read_mo() - #1295

Open
agu2347 wants to merge 1 commit into
python-babel:masterfrom
agu2347:fix-mofile-msgctxt-decode
Open

Decode msgctxt using the catalog's charset in read_mo()#1295
agu2347 wants to merge 1 commit into
python-babel:masterfrom
agu2347:fix-mofile-msgctxt-decode

Conversation

@agu2347

@agu2347 agu2347 commented Jul 28, 2026

Copy link
Copy Markdown

Fixes #1147.

read_mo() extracted the message context (msgctxt) as raw bytes and used it directly, while msgid/msgstr a few lines later are properly decoded via catalog.charset. write_mo() already expects (and calls .encode(catalog.charset) on) a plain str context when serializing, so this asymmetry broke round-tripping a catalog through write_mo() then read_mo(): a catalog written with a str context came back from read_mo() with a bytes context instead, and made it impossible to use Catalog.get()/Catalog.__getitem__ with a plain str context on the result without first manually re-encoding it to match -- exactly as described in the issue.

Fix: decode ctxt via catalog.charset immediately after splitting it off, matching how msg/tmsg are decoded a few lines below and matching what write_mo() already expects on the way out.

Testing: verified with a real write_mo() -> read_mo() round-trip: confirmed the context comes back as a plain str matching the original value, and that Catalog.get() finds the message using that same plain str context without needing any manual re-encoding -- the reporter's exact use case. Also confirmed messages without a context are unaffected.

Added a regression test performing this exact round-trip. I confirmed the test fails with the original code (context comes back as bytes) and passes with the fix. Ran the full existing test_mofile.py suite (5 passed: 4 baseline + 1 new) and the broader messages test suite (test_catalog.py, test_pofile.py: 82 passed total), no regressions.

read_mo() extracted the message context (msgctxt) as raw bytes and
used it directly, while msgid/msgstr a few lines later are properly
decoded via catalog.charset. write_mo() already expects (and calls
.encode(catalog.charset) on) a plain str context when serializing, so
this asymmetry broke round-tripping a catalog through write_mo() then
read_mo(): a catalog written with a str context came back from
read_mo() with a bytes context instead, and made it impossible to use
Catalog.get()/Catalog.__getitem__ with a plain str context on the
result without first manually re-encoding it to match.

Decode ctxt via catalog.charset immediately after splitting it off,
matching how msg/tmsg are decoded a few lines below and matching what
write_mo() already expects on the way out.

Verified with a real write_mo() -> read_mo() round-trip: confirmed
the context comes back as a plain str matching the original value,
and that Catalog.get() finds the message using that same plain str
context without needing any manual re-encoding -- the reporter's
exact use case. Also confirmed messages without a context are
unaffected.

Added a regression test performing this exact round-trip. Confirmed
the test fails with the original code (context comes back as bytes)
and passes with the fix. Ran the full existing test_mofile.py suite
(5 passed: 4 baseline + 1 new) and the broader messages test suite
(test_catalog.py, test_pofile.py: 82 passed total), no regressions.

Fixes python-babel#1147
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.

read_mo does not decode msgctxt

1 participant