# Hardcoded string scanner for ObsiGate frontend JS files # Finds user-visible strings that should be i18n'd but aren't. # Also checks EN locale for French contamination. # # Usage: # cd /c/dev/git/python/obsigate # python3 << 'PYEOF' ... PYEOF import re, os, json js_dir = 'frontend/js' # ── Part 1: Find hardcoded user-visible strings in JS ── noise_patterns = [ r'\.css', r'data-', r'console\.', r'getElementById', r'querySelector', r'\.json', r'/api/', r'CSS\.escape', r'encodeURI', r'font-size', r'background:', r'padding:', r'border', r'SSE parse', r'\[Offline', r'Failed to', r'Error ', r'Soft vault', r'\[Forge\]', r'CodeMirror', r'\[PWA\]', r'\[SW\]', r'DragDrop', r'Dashboard:', ] french_chars = re.compile(r'[àâäéèêëîïôöùûüçÀÂÄÉÈÊËÎÏÔÖÙÛÜÇ]') ui_words = ['loading', 'error', 'search', 'save', 'delete', 'create', 'cancel', 'download', 'upload', 'share', 'copy', 'rename', 'open', 'close', 'file', 'folder', 'vault'] for fname in sorted(os.listdir(js_dir)): if not fname.endswith('.js') or fname == 'i18n.js': continue fpath = os.path.join(js_dir, fname) with open(fpath, 'r', encoding='utf-8') as f: lines = f.readlines() hardcoded = [] for i, line in enumerate(lines, 1): strings = re.findall(r"'([^']+)'|\"([^\"]+)\"|`([^`]+)`", line) for s_tuple in strings: s = s_tuple[0] or s_tuple[1] or s_tuple[2] if len(s) < 4: continue if not re.search(r'[A-Za-zÀ-ÿ]', s): continue if any(re.search(p, s) for p in noise_patterns): continue if s.startswith('#') or s.startswith('.') or s.startswith('http'): continue context = ''.join(lines[max(0,i-2):i+1]) if 't(' in context or 'data-i18n' in context or 'tr(' in context: continue has_fr = bool(french_chars.search(s)) is_ui = has_fr or any(w in s.lower() for w in ui_words) if is_ui: hardcoded.append((i, s.strip()[:120])) if hardcoded: print(f"\n=== {fname} ({len(hardcoded)}) ===") for ln, s in hardcoded: print(f" L{ln}: {s}") # ── Part 2: Check EN locale for French contamination ── with open('frontend/locales/fr.json', encoding='utf-8') as f: fr = json.load(f) with open('frontend/locales/en.json', encoding='utf-8') as f: en = json.load(f) print(f"\n=== Locale alignment: FR={len(fr)} EN={len(en)} ===") only_fr = set(fr.keys()) - set(en.keys()) only_en = set(en.keys()) - set(fr.keys()) if only_fr: print(f"Keys in FR only: {sorted(only_fr)}") if only_en: print(f"Keys in EN only: {sorted(only_en)}") # EN values with French chars fr_in_en = [] for k in sorted(fr.keys()): if k in en and isinstance(en[k], str): if french_chars.search(en[k]): fr_in_en.append(k) if fr_in_en: print(f"\n=== EN keys with French text ({len(fr_in_en)}) ===") for k in fr_in_en: if not k.startswith('auto.') and not k.startswith('help.desc_'): print(f" {k}: {en[k][:80]}")