#!/usr/bin/env python3 """ Comprehensive script to add i18n translation tags to all Django templates """ import os import re from pathlib import Path # Patterns for text that should be translated TRANSLATION_PATTERNS = [ # Simple text in common HTML elements (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)

', r'>{%% trans "%s" %%}

'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), (r'>([A-Z][^<>{}\n]+?)', r'>{%% trans "%s" %%}'), ] def add_i18n_load(content): """Add {% load i18n %} at the top if not present""" if '{% load i18n %}' in content or '{%load i18n%}' in content: return content # Check if it extends a template if content.strip().startswith('{% extends'): # Add after extends lines = content.split('\n') for i, line in enumerate(lines): if '{% extends' in line: lines.insert(i + 1, '{% load i18n %}') return '\n'.join(lines) # Add at the very top return '{% load i18n %}\n' + content def wrap_text_in_trans(text): """Wrap text in {% trans %} tag""" text = text.strip() if not text or '{%' in text or '{{' in text: return text return f'{{% trans "{text}" %}}' def process_template_content(content): """Process template content and add translation tags""" lines = content.split('\n') processed_lines = [] for line in lines: original_line = line # Skip lines that already have trans tags if '{% trans' in line or '{%trans' in line: processed_lines.append(line) continue # Skip lines with only Django template tags or variables if line.strip().startswith('{%') or line.strip().startswith('{{'): processed_lines.append(line) continue # Process specific patterns # Button text if '' in line: match = re.search(r'>([^<>{}\n]+)', line) if match: text = match.group(1).strip() if text and not '{' in text and len(text) > 1: line = line.replace(f'>{text}', f'>{{% trans "{text}" %}}') # Link text if '' in line: match = re.search(r'>([^<>{}\n]+)', line) if match: text = match.group(1).strip() if text and not '{' in text and len(text) > 1 and not text.startswith('<'): line = line.replace(f'>{text}', f'>{{% trans "{text}" %}}') # Label text if '' in line: match = re.search(r'>([^<>{}\n]+)', line) if match: text = match.group(1).strip() if text and not '{' in text and len(text) > 1: line = line.replace(f'>{text}', f'>{{% trans "{text}" %}}') # Heading text for i in range(1, 7): if f'' in line: match = re.search(rf'>([^<>{{}}\n]+)', line) if match: text = match.group(1).strip() if text and not '{' in text and len(text) > 1: line = line.replace(f'>{text}', f'>{{% trans "{text}" %}}') # Table headers if '' in line: match = re.search(r'>([^<>{}\n]+)', line) if match: text = match.group(1).strip() if text and not '{' in text and len(text) > 1: line = line.replace(f'>{text}', f'>{{% trans "{text}" %}}') # Paragraph text (be careful with this one) if '' in line and '

' in line: match = re.search(r'

([^<>{}\n]+)

', line) if match: text = match.group(1).strip() if text and not '{' in text and len(text) > 1: line = line.replace(f'

{text}

', f'

{{% trans "{text}" %}}

') # Placeholder attributes if 'placeholder="' in line: match = re.search(r'placeholder="([^"]+)"', line) if match: text = match.group(1) if not '{' in text: line = line.replace(f'placeholder="{text}"', f'placeholder="{{% trans \'{text}\' %}}"') # Title attributes if 'title="' in line and not '{% trans' in line: match = re.search(r'title="([^"]+)"', line) if match: text = match.group(1) if not '{' in text and len(text) > 2: line = line.replace(f'title="{text}"', f'title="{{% trans \'{text}\' %}}"') processed_lines.append(line) return '\n'.join(processed_lines) def process_template(filepath): """Process a single template file""" print(f"Processing: {filepath}") try: with open(filepath, 'r', encoding='utf-8') as f: content = f.read() original_content = content # Add i18n load tag content = add_i18n_load(content) # Process content for translations content = process_template_content(content) if content != original_content: with open(filepath, 'w', encoding='utf-8') as f: f.write(content) print(f" ✓ Updated: {filepath}") return True else: print(f" - No changes needed: {filepath}") return False except Exception as e: print(f" ✗ Error processing {filepath}: {e}") return False def main(): """Main function to process all templates""" base_dir = Path(__file__).parent templates_dir = base_dir / 'templates' if not templates_dir.exists(): print(f"Templates directory not found: {templates_dir}") return # Find all HTML files html_files = sorted(list(templates_dir.rglob('*.html'))) print(f"Found {len(html_files)} template files") print("=" * 80) updated_count = 0 for html_file in html_files: if process_template(html_file): updated_count += 1 print() print("=" * 80) print(f"Completed! Updated {updated_count} out of {len(html_files)} files") if __name__ == '__main__': main()