feat: FASE 4 - Editor Maker (Fabric.js) con annotazioni, task editor, preview e storico versioni
- recipe_list.html: lista ricette con filtri, paginazione, cards Alpine.js - recipe_editor.html: form metadati, upload drag-and-drop, canvas Fabric.js per annotazioni - annotation-editor.js: editor annotazioni Fabric.js (marker, frecce, rettangoli, zoom, pan) - task_editor.html: editor task/subtask inline con drag-and-drop reorder e tolleranze - recipe_preview.html: anteprima ricetta come MeasurementTec - version_history.html: timeline versioni con conteggio misurazioni AJAX - maker.py: 6 route pagina + 13 proxy AJAX, gestione sicura risposte lista API - i18n: 170+ stringhe tradotte IT/EN per tutti i template Maker Architect review: 3 CRITICO + 5 MEDIO + 3 NEW risolti, 2 BASSO differiti Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
#!/usr/bin/env python
|
||||
"""Verify i18n setup for TieMeasureFlow."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
def check_file(path: Path, description: str) -> bool:
|
||||
"""Check if a file exists and report."""
|
||||
exists = path.exists()
|
||||
status = "[OK]" if exists else "[FAIL]"
|
||||
print(f"{status} {description}: {path}")
|
||||
return exists
|
||||
|
||||
def check_json_valid(path: Path) -> bool:
|
||||
"""Check if JSON file is valid."""
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
json.load(f)
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f" ERROR: {e}")
|
||||
return False
|
||||
|
||||
def main():
|
||||
"""Verify i18n setup."""
|
||||
print("=== TieMeasureFlow i18n Verification ===\n")
|
||||
|
||||
root = Path(__file__).parent
|
||||
all_good = True
|
||||
|
||||
# Check Flask-Babel files
|
||||
print("Flask-Babel (Server-side):")
|
||||
files = [
|
||||
(root / "translations/babel.cfg", "Babel config"),
|
||||
(root / "translations/it/LC_MESSAGES/messages.po", "Italian .po"),
|
||||
(root / "translations/it/LC_MESSAGES/messages.mo", "Italian .mo"),
|
||||
(root / "translations/en/LC_MESSAGES/messages.po", "English .po"),
|
||||
(root / "translations/en/LC_MESSAGES/messages.mo", "English .mo"),
|
||||
]
|
||||
|
||||
for path, desc in files:
|
||||
if not check_file(path, desc):
|
||||
all_good = False
|
||||
|
||||
# Count messages in .po files
|
||||
if (root / "translations/it/LC_MESSAGES/messages.po").exists():
|
||||
with open(root / "translations/it/LC_MESSAGES/messages.po", 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
msgid_count = content.count('msgid "') - 1 # Exclude header
|
||||
print(f" Italian: {msgid_count} messages")
|
||||
|
||||
if (root / "translations/en/LC_MESSAGES/messages.po").exists():
|
||||
with open(root / "translations/en/LC_MESSAGES/messages.po", 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
msgid_count = content.count('msgid "') - 1
|
||||
print(f" English: {msgid_count} messages")
|
||||
|
||||
# Check Alpine.js i18n files
|
||||
print("\nAlpine.js i18n (Client-side):")
|
||||
json_files = [
|
||||
(root / "static/js/locales/it.json", "Italian locale"),
|
||||
(root / "static/js/locales/en.json", "English locale"),
|
||||
]
|
||||
|
||||
for path, desc in json_files:
|
||||
if check_file(path, desc):
|
||||
if not check_json_valid(path):
|
||||
all_good = False
|
||||
else:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
keys = count_keys(data)
|
||||
print(f" {keys} total keys")
|
||||
|
||||
# Check app.py integration
|
||||
print("\nApp Integration:")
|
||||
app_py = root / "app.py"
|
||||
if check_file(app_py, "app.py"):
|
||||
with open(app_py, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
checks = [
|
||||
("from flask_babel import Babel", "Flask-Babel imported"),
|
||||
("def get_locale()", "get_locale() function"),
|
||||
("Babel(app, locale_selector=get_locale)", "Babel initialized"),
|
||||
("def set_language(lang)", "set_language endpoint"),
|
||||
]
|
||||
for check_str, check_desc in checks:
|
||||
found = check_str in content
|
||||
status = "[OK]" if found else "[FAIL]"
|
||||
print(f" {status} {check_desc}")
|
||||
if not found:
|
||||
all_good = False
|
||||
|
||||
# Summary
|
||||
print("\n" + "="*40)
|
||||
if all_good:
|
||||
print("[OK] i18n setup verified successfully!")
|
||||
print("\nNext steps:")
|
||||
print("1. Use _() in Python code and templates")
|
||||
print("2. Use $t() in Alpine.js components")
|
||||
print("3. Test language switching: /set-language/en or /set-language/it")
|
||||
else:
|
||||
print("[FAIL] Some checks failed - review errors above")
|
||||
return 1
|
||||
|
||||
return 0
|
||||
|
||||
def count_keys(obj, depth=0):
|
||||
"""Recursively count keys in nested dict."""
|
||||
if not isinstance(obj, dict):
|
||||
return 0
|
||||
count = len(obj)
|
||||
for value in obj.values():
|
||||
if isinstance(value, dict):
|
||||
count += count_keys(value, depth + 1)
|
||||
return count
|
||||
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
Reference in New Issue
Block a user