import os import json from flask import Flask, request, session, current_app from flask_sqlalchemy import SQLAlchemy from flask_login import LoginManager from sqlalchemy import event from sqlalchemy.engine import Engine db = SQLAlchemy() login_manager = LoginManager() @event.listens_for(Engine, "connect") def set_sqlite_pragma(dbapi_connection, connection_record): if dbapi_connection.__class__.__module__ == "sqlite3": cursor = dbapi_connection.cursor() cursor.execute("PRAGMA journal_mode=WAL") cursor.execute("PRAGMA synchronous=NORMAL") cursor.close() # Load all i18n jsons i18n_dict = {} def load_i18n(app): global i18n_dict i18n_dir = os.path.join(app.root_path, 'assets', 'i18n') if os.path.exists(i18n_dir): for f in os.listdir(i18n_dir): if f.endswith('.json'): lang_code = f.replace('.json', '') with open(os.path.join(i18n_dir, f), 'r', encoding='utf-8') as jf: i18n_dict[lang_code] = json.load(jf) def get_locale(): # 用户手动选择的语言保存在 cookie 中优先 lang = request.cookies.get('lang') if lang in i18n_dict: return lang # Check accept_languages with our available dict keys best_match = request.accept_languages.best_match(list(i18n_dict.keys())) return best_match if best_match else 'en' def _t(key): lang = get_locale() # Fallback to english if language missing or key missing if lang in i18n_dict and key in i18n_dict[lang]: return i18n_dict[lang][key] if 'en' in i18n_dict and key in i18n_dict['en']: return i18n_dict['en'][key] return key # fallback to the key itself def create_app(): app = Flask(__name__, static_url_path='/assets', static_folder='assets') app.config['SECRET_KEY'] = 'your-secret-key-change-it-in-production' app.config['SESSION_COOKIE_NAME'] = 'aio_session' # Prevent collision with OctoPrint's 'session' cookie app.config['REMEMBER_COOKIE_NAME'] = 'aio_remember' app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///../instance/aio_3d.db' app.config['SQLALCHEMY_ENGINE_OPTIONS'] = {'connect_args': {'timeout': 15}} app.config['UPLOAD_FOLDER'] = os.environ.get('UPLOAD_FOLDER', os.path.abspath(os.path.join(app.root_path, '..', 'uploads'))) app.config['PRINT_CONFIG_FOLDER'] = os.environ.get('PRINT_CONFIG_FOLDER', os.path.abspath(os.path.join(app.root_path, '..', 'print_config'))) app.config['PRUSA_SLICE_BIN'] = os.environ.get('PRUSA_SLICE_BIN', os.path.abspath(os.path.join(app.root_path, '..', 'prusaslicer', 'PrusaSlicer-2.9.4-aarch64-full.AppImage'))) os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) load_i18n(app) db.init_app(app) login_manager.init_app(app) # Inject translation function into jinja @app.context_processor def inject_i18n(): return dict(_=_t) login_manager.login_view = 'auth.login' with app.app_context(): from . import models db.create_all() from .routes.main_routes import main_bp from .routes.auth_routes import auth_bp from .routes.admin_routes import admin_bp from .routes.printer_routes import printer_bp from .utils.api_handle import api_bp app.register_blueprint(main_bp) app.register_blueprint(auth_bp) app.register_blueprint(admin_bp) app.register_blueprint(printer_bp) app.register_blueprint(api_bp) return app