3030
3131import polib
3232
33- ROLE_PATTERN = re .compile (r":(?:\w+:)?[\w.-]+:`([^`]+)`" )
33+ ROLE_PATTERN = re .compile (r":(( ?:\w+:)?[\w.-]+) :`([^`]+)`" )
3434# Sphinx itself accepts `label<target>` (no space) as well as the more
3535# common `label <target>` -- both are valid RST role syntax, and the
3636# upstream English source uses the no-space form in a few places (e.g.
6464 r'^(?:msgid|msgstr(?:\[\d+\])?|msgctxt)?\s*"((?:[^"\\]|\\.)*)"\s*$'
6565)
6666
67+ DISPLAY_ONLY_ROLES = {"dfn" , "kbd" , "guilabel" , "menuselection" , "samp" , "file" }
68+
69+ DFN_PATTERN = re .compile (r":dfn:`" )
70+ DFN_ANGLE = re .compile (r":dfn:`[^`]*<[^`>]+>`" )
6771
6872def find_invalid_escapes_in_raw (raw : str ):
6973 """Scan raw (undecoded) quoted-string content left-to-right the way
@@ -113,10 +117,12 @@ def check_raw_escapes(path: Path):
113117
114118def extract_role_targets (text : str ):
115119 """For each Sphinx role, return its target: the <target> anchor if
116- present, otherwise the role's full display text (which IS the target
117- when there's no explicit anchor) ."""
120+ present, otherwise the role's full display text. Display-only roles
121+ (like :dfn:) are skipped, since their text is translatable ."""
118122 targets = []
119- for body in ROLE_PATTERN .findall (text ):
123+ for role , body in ROLE_PATTERN .findall (text ):
124+ if role in DISPLAY_ONLY_ROLES :
125+ continue
120126 m = TARGET_PATTERN .match (body )
121127 targets .append (m .group (2 ).strip () if m else body .strip ())
122128 return targets
@@ -143,6 +149,16 @@ def check_file(path: Path):
143149 if extra :
144150 findings .append (f"role target(s) not in source: { extra } " )
145151
152+ # --- :dfn: checks (display-only role, so compare count, not text) ---
153+ msgid_dfn_count = len (DFN_PATTERN .findall (entry .msgid ))
154+ msgstr_dfn_count = len (DFN_PATTERN .findall (entry .msgstr ))
155+ if msgid_dfn_count != msgstr_dfn_count :
156+ findings .append (
157+ f":dfn: count differs ({ msgid_dfn_count } vs { msgstr_dfn_count } )"
158+ )
159+ if DFN_ANGLE .search (entry .msgstr ):
160+ findings .append (":dfn: contains <...>, which Sphinx renders literally" )
161+
146162 for label , pattern in LITERAL_PATTERNS :
147163 expected = Counter (pattern .findall (entry .msgid ))
148164 found = Counter (pattern .findall (entry .msgstr ))
0 commit comments