def setupLangAndBackend( pm: ProfileManager, app: QApplication, force: Optional[str] = None, firstTime: bool = False, ) -> RustBackend: global _qtrans try: locale.setlocale(locale.LC_ALL, "") except: pass # add _ and ngettext globals used by legacy code def fn__(arg): print("".join(traceback.format_stack()[-2])) print("_ global will break in the future; please see anki/lang.py") return arg def fn_ngettext(a, b, c): print("".join(traceback.format_stack()[-2])) print( "ngettext global will break in the future; please see anki/lang.py" ) return b builtins.__dict__["_"] = fn__ builtins.__dict__["ngettext"] = fn_ngettext # get lang and normalize into ja/zh-CN form if firstTime: lang = pm.meta["defaultLang"] else: lang = force or pm.meta["defaultLang"] lang = anki.lang.lang_to_disk_lang(lang) ldir = locale_dir() if not firstTime: # set active language anki.lang.set_lang(lang, ldir) # switch direction for RTL languages if anki.lang.is_rtl(lang): app.setLayoutDirection(Qt.RightToLeft) else: app.setLayoutDirection(Qt.LeftToRight) # load qt translations _qtrans = QTranslator() qt_dir = os.path.join(ldir, "qt") qt_lang = lang.replace("-", "_") if _qtrans.load("qtbase_" + qt_lang, qt_dir): app.installTranslator(_qtrans) return anki.lang.current_i18n
def setupLangAndBackend(pm: ProfileManager, app: QApplication, force: Optional[str] = None) -> RustBackend: global _qtrans try: locale.setlocale(locale.LC_ALL, "") except: pass # add _ and ngettext globals used by legacy code def fn__(arg): print( "accessing _ without importing from anki.lang will break in the future" ) print("".join(traceback.format_stack()[-2])) from anki.lang import _ return _(arg) def fn_ngettext(a, b, c): print( "accessing ngettext without importing from anki.lang will break in the future" ) print("".join(traceback.format_stack()[-2])) from anki.lang import ngettext return ngettext(a, b, c) builtins.__dict__["_"] = fn__ builtins.__dict__["ngettext"] = fn_ngettext # get lang and normalize into ja/zh-CN form lang = force or pm.meta["defaultLang"] lang = anki.lang.lang_to_disk_lang(lang) # load gettext catalog ldir = locale_dir() anki.lang.set_lang(lang, ldir) # switch direction for RTL languages if anki.lang.is_rtl(lang): app.setLayoutDirection(Qt.RightToLeft) else: app.setLayoutDirection(Qt.LeftToRight) # load qt translations _qtrans = QTranslator() qt_dir = os.path.join(ldir, "qt") qt_lang = lang.replace("-", "_") if _qtrans.load("qtbase_" + qt_lang, qt_dir): app.installTranslator(_qtrans) return anki.lang.current_i18n
def setupLang(pm: ProfileManager, app: QApplication, force: Optional[str] = None) -> None: global _qtrans try: locale.setlocale(locale.LC_ALL, "") except: pass lang = force or pm.meta["defaultLang"] def fn__(arg): print( "accessing _ without importing from anki.lang will break in the future" ) print("".join(traceback.format_stack()[-2])) from anki.lang import _ return _(arg) def fn_ngettext(a, b, c): print( "accessing ngettext without importing from anki.lang will break in the future" ) print("".join(traceback.format_stack()[-2])) from anki.lang import ngettext return ngettext(a, b, c) builtins.__dict__["_"] = fn__ builtins.__dict__["ngettext"] = fn_ngettext ldir = locale_dir() anki.lang.setLang(lang, ldir, local=False) if lang in ("he", "ar", "fa"): app.setLayoutDirection(Qt.RightToLeft) else: app.setLayoutDirection(Qt.LeftToRight) # qt _qtrans = QTranslator() if _qtrans.load("qt_" + lang, ldir): app.installTranslator(_qtrans)
def setLang(self, code) -> None: self.meta["defaultLang"] = code sql = "update profiles set data = ? where name = ?" self.db.execute(sql, self._pickle(self.meta), "_global") self.db.commit() anki.lang.set_lang(code, locale_dir())
def _run(argv: Optional[List[str]] = None, exec: bool = True) -> Optional[AnkiApp]: """Start AnkiQt application or reuse an existing instance if one exists. If the function is invoked with exec=False, the AnkiQt will not enter the main event loop - instead the application object will be returned. The 'exec' and 'argv' arguments will be useful for testing purposes. If no 'argv' is supplied then 'sys.argv' will be used. """ global mw global profiler if argv is None: argv = sys.argv # parse args opts, args = parseArgs(argv) if opts.version: print(f"Anki {appVersion}") return None elif opts.syncserver: from anki.syncserver import serve serve() return None if PROFILE_CODE: profiler = cProfile.Profile() profiler.enable() # default to specified/system language before getting user's preference so that we can localize some more strings lang = anki.lang.get_def_lang(opts.lang) anki.lang.set_lang(lang[1], locale_dir()) # profile manager pm = None try: pm = ProfileManager(opts.base) pmLoadResult = pm.setupMeta() except AnkiRestart as error: if error.exitcode: sys.exit(error.exitcode) return None except: # will handle below traceback.print_exc() pm = None if pm: # gl workarounds setupGL(pm) # apply user-provided scale factor os.environ["QT_SCALE_FACTOR"] = str(pm.uiScale()) # opt in to full hidpi support? if not os.environ.get("ANKI_NOHIGHDPI"): QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling) QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1" os.environ["QT_SCALE_FACTOR_ROUNDING_POLICY"] = "PassThrough" # Opt into software rendering. Useful for buggy systems. if os.environ.get("ANKI_SOFTWAREOPENGL"): QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL) if (isWin and (qtminor == 14 or (qtminor == 15 and qtpoint == 0)) and "QT_QPA_PLATFORM" not in os.environ): os.environ["QT_QPA_PLATFORM"] = "windows:altgr" # create the app QCoreApplication.setApplicationName("Anki") QGuiApplication.setDesktopFileName("anki.desktop") app = AnkiApp(argv) if app.secondInstance(): # we've signaled the primary instance, so we should close return None if not pm: QMessageBox.critical( None, tr(TR.QT_MISC_ERROR), tr(TR.PROFILES_COULD_NOT_CREATE_DATA_FOLDER), ) return None # disable icons on mac; this must be done before window created if isMac: app.setAttribute(Qt.AA_DontShowIconsInMenus) # disable help button in title bar on qt versions that support it if isWin and qtminor >= 10: QApplication.setAttribute(Qt.AA_DisableWindowContextHelpButton) # proxy configured? from urllib.request import getproxies, proxy_bypass disable_proxies = False try: if "http" in getproxies(): # if it's not set up to bypass localhost, we'll # need to disable proxies in the webviews if not proxy_bypass("127.0.0.1"): disable_proxies = True except UnicodeDecodeError: # proxy_bypass can't handle unicode in hostnames; assume we need # to disable proxies disable_proxies = True if disable_proxies: print("webview proxy use disabled") proxy = QNetworkProxy() proxy.setType(QNetworkProxy.NoProxy) QNetworkProxy.setApplicationProxy(proxy) # we must have a usable temp dir try: tempfile.gettempdir() except: QMessageBox.critical( None, tr(TR.QT_MISC_ERROR), tr(TR.QT_MISC_NO_TEMP_FOLDER), ) return None if pmLoadResult.firstTime: pm.setDefaultLang(lang[0]) if pmLoadResult.loadError: QMessageBox.warning( None, tr(TR.PROFILES_PREFS_CORRUPT_TITLE), tr(TR.PROFILES_PREFS_FILE_IS_CORRUPT), ) if opts.profile: pm.openProfile(opts.profile) # i18n & backend backend = setupLangAndBackend(pm, app, opts.lang, pmLoadResult.firstTime) driver = pm.video_driver() if isLin and driver == VideoDriver.OpenGL: from aqt.utils import gfxDriverIsBroken if gfxDriverIsBroken(): pm.set_video_driver(driver.next()) QMessageBox.critical( None, tr(TR.QT_MISC_ERROR), tr(TR.QT_MISC_INCOMPATIBLE_VIDEO_DRIVER), ) sys.exit(1) # load the main window import aqt.main mw = aqt.main.AnkiQt(app, pm, backend, opts, args) if exec: app.exec() else: return app if PROFILE_CODE: write_profile_results() return None