Skip to content

Instantly share code, notes, and snippets.

@eduardomozart
Last active May 2, 2026 12:21
Show Gist options
  • Select an option

  • Save eduardomozart/c6e3203d8484cdad509ff25c4ef0d48d to your computer and use it in GitHub Desktop.

Select an option

Save eduardomozart/c6e3203d8484cdad509ff25c4ef0d48d to your computer and use it in GitHub Desktop.
Python QA script for .po files: checks for missing camelCase variables, Title Case mismatches, missing ampersands (UI mnemonics), and identical translations.
#!/usr/bin/env python3
import polib
import re
import sys
import os
from collections import Counter
def find_camel_case(text):
"""Finds camelCase variables/keys (e.g., userId)."""
camel_case_pattern = re.compile(r'\b[a-z]+[A-Z][a-zA-Z]*\b')
return camel_case_pattern.findall(text)
def find_title_case(text):
"""Finds words that start with an uppercase letter."""
# Supports accented characters naturally via \w+
words = re.findall(r'\w+', text)
return [w for w in words if w[0].isupper()]
def check_po_file(file_path):
try:
po = polib.pofile(file_path)
except Exception as e:
print(f"Error reading {file_path}: {e}")
sys.exit(1)
issues_found = 0
for entry in po:
# Skip obsolete texts (deleted from the system)
if entry.obsolete:
continue
# Handle Singular and Plural entries
comparisons = []
if entry.msgstr_plural:
for key, translation in entry.msgstr_plural.items():
if not translation: continue
original = entry.msgid if str(key) == '0' else entry.msgid_plural
comparisons.append((original, translation))
else:
if not entry.msgstr: continue
comparisons.append((entry.msgid, entry.msgstr))
# Analyze each text pair
for original_text, translated_text in comparisons:
issue_details = []
# --- 1. IDENTICAL STRINGS CHECK ---
if original_text.strip() == translated_text.strip():
issue_details.append("Identical strings: Translation is exactly the same as the original.")
# --- 2. CAMELCASE CHECK (Missing or Extra) ---
msgid_camel_words = find_camel_case(original_text)
msgstr_camel_words = find_camel_case(translated_text)
msgid_counts = Counter(msgid_camel_words)
msgstr_counts = Counter(msgstr_camel_words)
# Check if any camelCase from the original is missing in the translation
for word, expected_count in msgid_counts.items():
actual_count = msgstr_counts.get(word, 0)
if actual_count < expected_count:
issue_details.append(f"Missing camelCase: '{word}' (expected {expected_count}, found {actual_count})")
# Check if the translation inserted a camelCase that didn't exist in the original
for word, actual_count in msgstr_counts.items():
expected_count = msgid_counts.get(word, 0)
if actual_count > expected_count:
issue_details.append(f"Extra camelCase: '{word}' (expected {expected_count}, found {actual_count})")
# --- 3. CAPITALIZATION COUNT CHECK (Title Case) ---
id_titles = find_title_case(original_text)
str_titles = find_title_case(translated_text)
if len(id_titles) != len(str_titles):
issue_details.append(
f"Capitalization mismatch: Original has {len(id_titles)} capitalized words, "
f"but translation has {len(str_titles)}."
)
# --- 4. AMPERSAND (&) / MNEMONICS CHECK ---
if '&' in original_text and '&' not in translated_text:
issue_details.append("Missing ampersand (&): Original contains '&' (often a keyboard mnemonic shortcut) but the translation does not.")
# If any issues were found, print them to the console
if issue_details:
issues_found += 1
print(f"Issue found at line {entry.linenum}:")
print(f" Original: '{original_text}'")
print(f" Translation: '{translated_text}'")
# Highlight if the text is marked as fuzzy (unconfirmed translation)
if 'fuzzy' in entry.flags:
print(" ⚠️ WARNING: This entry is marked as 'fuzzy'.")
for detail in issue_details:
print(f" - {detail}")
print("-" * 70)
if issues_found == 0:
print(f"Success: No issues found in {file_path}.")
else:
print(f"\nTotal issues found: {issues_found}")
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: ./po_check_quality.py <path_to_po_file>")
sys.exit(1)
po_file_path = sys.argv[1]
# Check if the file exists before trying to open it
if not os.path.isfile(po_file_path):
print(f"Error: The file '{po_file_path}' does not exist. Please check the path and try again.")
sys.exit(1)
check_po_file(po_file_path)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment