update no-arg tr references in qt/

This commit is contained in:
Damien Elmes 2021-03-26 13:48:26 +10:00
parent ebe655975c
commit 0c338bfd53
45 changed files with 494 additions and 515 deletions

View File

@ -118,7 +118,7 @@ def translate_string_in(
class Translations(GeneratedTranslations): class Translations(GeneratedTranslations):
def __init__(self, backend: ref[RustBackend]): def __init__(self, backend: Optional[ref[RustBackend]]):
self.backend = backend self.backend = backend
def __call__(self, *args: Any, **kwargs: Any) -> str: def __call__(self, *args: Any, **kwargs: Any) -> str:

View File

@ -153,7 +153,7 @@ currentLang = "en"
# instance exists for legacy reasons, and as a convenience for the # instance exists for legacy reasons, and as a convenience for the
# Qt code. # Qt code.
current_i18n: Optional[anki._backend.RustBackend] = None current_i18n: Optional[anki._backend.RustBackend] = None
tr_legacyglobal: Optional[anki._backend.Translations] = None tr_legacyglobal = anki._backend.Translations(None)
def _(str: str) -> str: def _(str: str) -> str:
@ -167,10 +167,10 @@ def ngettext(single: str, plural: str, n: int) -> str:
def set_lang(lang: str) -> None: def set_lang(lang: str) -> None:
global currentLang, current_i18n, tr_legacyglobal global currentLang, current_i18n
currentLang = lang currentLang = lang
current_i18n = anki._backend.RustBackend(langs=[lang]) current_i18n = anki._backend.RustBackend(langs=[lang])
tr_legacyglobal = anki._backend.Translations(weakref.ref(current_i18n)) tr_legacyglobal.backend = weakref.ref(current_i18n)
def get_def_lang(lang: Optional[str] = None) -> Tuple[int, str]: def get_def_lang(lang: Optional[str] = None) -> Tuple[int, str]:

View File

@ -285,8 +285,8 @@ class AnkiApp(QApplication):
# existing instance running but hung # existing instance running but hung
QMessageBox.warning( QMessageBox.warning(
None, None,
tr(TR.QT_MISC_ANKI_IS_RUNNING), tr.qt_misc_anki_is_running(),
tr(TR.QT_MISC_IF_INSTANCE_IS_NOT_RESPONDING), tr.qt_misc_if_instance_is_not_responding(),
) )
sys.exit(1) sys.exit(1)
@ -379,7 +379,7 @@ def setupGL(pm: aqt.profiles.ProfileManager) -> None:
if "Failed to create OpenGL context" in msg: if "Failed to create OpenGL context" in msg:
QMessageBox.critical( QMessageBox.critical(
None, None,
tr(TR.QT_MISC_ERROR), tr.qt_misc_error(),
tr( tr(
TR.QT_MISC_ERROR_LOADING_GRAPHICS_DRIVER, TR.QT_MISC_ERROR_LOADING_GRAPHICS_DRIVER,
mode=driver.value, mode=driver.value,
@ -515,8 +515,8 @@ def _run(argv: Optional[List[str]] = None, exec: bool = True) -> Optional[AnkiAp
if not pm: if not pm:
QMessageBox.critical( QMessageBox.critical(
None, None,
tr(TR.QT_MISC_ERROR), tr.qt_misc_error(),
tr(TR.PROFILES_COULD_NOT_CREATE_DATA_FOLDER), tr.profiles_could_not_create_data_folder(),
) )
return None return None
@ -555,8 +555,8 @@ def _run(argv: Optional[List[str]] = None, exec: bool = True) -> Optional[AnkiAp
except: except:
QMessageBox.critical( QMessageBox.critical(
None, None,
tr(TR.QT_MISC_ERROR), tr.qt_misc_error(),
tr(TR.QT_MISC_NO_TEMP_FOLDER), tr.qt_misc_no_temp_folder(),
) )
return None return None
@ -566,8 +566,8 @@ def _run(argv: Optional[List[str]] = None, exec: bool = True) -> Optional[AnkiAp
if pmLoadResult.loadError: if pmLoadResult.loadError:
QMessageBox.warning( QMessageBox.warning(
None, None,
tr(TR.PROFILES_PREFS_CORRUPT_TITLE), tr.profiles_prefs_corrupt_title(),
tr(TR.PROFILES_PREFS_FILE_IS_CORRUPT), tr.profiles_prefs_file_is_corrupt(),
) )
if opts.profile: if opts.profile:
@ -584,8 +584,8 @@ def _run(argv: Optional[List[str]] = None, exec: bool = True) -> Optional[AnkiAp
pm.set_video_driver(driver.next()) pm.set_video_driver(driver.next())
QMessageBox.critical( QMessageBox.critical(
None, None,
tr(TR.QT_MISC_ERROR), tr.qt_misc_error(),
tr(TR.QT_MISC_INCOMPATIBLE_VIDEO_DRIVER), tr.qt_misc_incompatible_video_driver(),
) )
sys.exit(1) sys.exit(1)

View File

@ -83,9 +83,9 @@ def show(mw: aqt.AnkiQt) -> QDialog:
""" """
info = f" {' '.join(info.splitlines(True))}" info = f" {' '.join(info.splitlines(True))}"
QApplication.clipboard().setText(info) QApplication.clipboard().setText(info)
tooltip(tr(TR.ABOUT_COPIED_TO_CLIPBOARD), parent=dialog) tooltip(tr.about_copied_to_clipboard(), parent=dialog)
btn = QPushButton(tr(TR.ABOUT_COPY_DEBUG_INFO)) btn = QPushButton(tr.about_copy_debug_info())
qconnect(btn.clicked, onCopy) qconnect(btn.clicked, onCopy)
abt.buttonBox.addButton(btn, QDialogButtonBox.ActionRole) abt.buttonBox.addButton(btn, QDialogButtonBox.ActionRole)
abt.buttonBox.button(QDialogButtonBox.Ok).setFocus() abt.buttonBox.button(QDialogButtonBox.Ok).setFocus()
@ -93,8 +93,8 @@ def show(mw: aqt.AnkiQt) -> QDialog:
# WebView contents # WebView contents
###################################################################### ######################################################################
abouttext = "<center><img src='/_anki/imgs/anki-logo-thin.png'></center>" abouttext = "<center><img src='/_anki/imgs/anki-logo-thin.png'></center>"
abouttext += f"<p>{tr(TR.ABOUT_ANKI_IS_A_FRIENDLY_INTELLIGENT_SPACED)}" abouttext += f"<p>{tr.about_anki_is_a_friendly_intelligent_spaced()}"
abouttext += f"<p>{tr(TR.ABOUT_ANKI_IS_LICENSED_UNDER_THE_AGPL3)}" abouttext += f"<p>{tr.about_anki_is_licensed_under_the_agpl3()}"
abouttext += f"<p>{tr(TR.ABOUT_VERSION, val=versionWithBuild())}<br>" abouttext += f"<p>{tr(TR.ABOUT_VERSION, val=versionWithBuild())}<br>"
abouttext += ("Python %s Qt %s PyQt %s<br>") % ( abouttext += ("Python %s Qt %s PyQt %s<br>") % (
platform.python_version(), platform.python_version(),
@ -212,8 +212,8 @@ def show(mw: aqt.AnkiQt) -> QDialog:
abouttext += "<p>" + tr( abouttext += "<p>" + tr(
TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES, cont=", ".join(allusers) TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES, cont=", ".join(allusers)
) )
abouttext += f"<p>{tr(TR.ABOUT_IF_YOU_HAVE_CONTRIBUTED_AND_ARE)}" abouttext += f"<p>{tr.about_if_you_have_contributed_and_are()}"
abouttext += f"<p>{tr(TR.ABOUT_A_BIG_THANKS_TO_ALL_THE)}" abouttext += f"<p>{tr.about_a_big_thanks_to_all_the()}"
abt.label.setMinimumWidth(800) abt.label.setMinimumWidth(800)
abt.label.setMinimumHeight(600) abt.label.setMinimumHeight(600)
dialog.show() dialog.show()

View File

@ -41,7 +41,7 @@ class AddCards(QDialog):
self.mw = mw self.mw = mw
self.form = aqt.forms.addcards.Ui_Dialog() self.form = aqt.forms.addcards.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
self.setWindowTitle(tr(TR.ACTIONS_ADD)) self.setWindowTitle(tr.actions_add())
disable_help_button(self) disable_help_button(self)
self.setMinimumHeight(300) self.setMinimumHeight(300)
self.setMinimumWidth(400) self.setMinimumWidth(400)
@ -81,20 +81,20 @@ class AddCards(QDialog):
bb = self.form.buttonBox bb = self.form.buttonBox
ar = QDialogButtonBox.ActionRole ar = QDialogButtonBox.ActionRole
# add # add
self.addButton = bb.addButton(tr(TR.ACTIONS_ADD), ar) self.addButton = bb.addButton(tr.actions_add(), ar)
qconnect(self.addButton.clicked, self.add_current_note) qconnect(self.addButton.clicked, self.add_current_note)
self.addButton.setShortcut(QKeySequence("Ctrl+Return")) self.addButton.setShortcut(QKeySequence("Ctrl+Return"))
self.addButton.setToolTip(shortcut(tr(TR.ADDING_ADD_SHORTCUT_CTRLANDENTER))) self.addButton.setToolTip(shortcut(tr.adding_add_shortcut_ctrlandenter()))
# close # close
self.closeButton = QPushButton(tr(TR.ACTIONS_CLOSE)) self.closeButton = QPushButton(tr.actions_close())
self.closeButton.setAutoDefault(False) self.closeButton.setAutoDefault(False)
bb.addButton(self.closeButton, QDialogButtonBox.RejectRole) bb.addButton(self.closeButton, QDialogButtonBox.RejectRole)
# help # help
self.helpButton = QPushButton(tr(TR.ACTIONS_HELP), clicked=self.helpRequested) # type: ignore self.helpButton = QPushButton(tr.actions_help(), clicked=self.helpRequested) # type: ignore
self.helpButton.setAutoDefault(False) self.helpButton.setAutoDefault(False)
bb.addButton(self.helpButton, QDialogButtonBox.HelpRole) bb.addButton(self.helpButton, QDialogButtonBox.HelpRole)
# history # history
b = bb.addButton(f"{tr(TR.ADDING_HISTORY)} {downArrow()}", ar) b = bb.addButton(f"{tr.adding_history()} {downArrow()}", ar)
if isMac: if isMac:
sc = "Ctrl+Shift+H" sc = "Ctrl+Shift+H"
else: else:
@ -175,7 +175,7 @@ class AddCards(QDialog):
a = m.addAction(line) a = m.addAction(line)
qconnect(a.triggered, lambda b, nid=nid: self.editHistory(nid)) qconnect(a.triggered, lambda b, nid=nid: self.editHistory(nid))
else: else:
a = m.addAction(tr(TR.ADDING_NOTE_DELETED)) a = m.addAction(tr.adding_note_deleted())
a.setEnabled(False) a.setEnabled(False)
gui_hooks.add_cards_will_show_history_menu(self, m) gui_hooks.add_cards_will_show_history_menu(self, m)
m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0))) m.exec_(self.historyButton.mapToGlobal(QPoint(0, 0)))
@ -203,7 +203,7 @@ class AddCards(QDialog):
# workaround for PyQt focus bug # workaround for PyQt focus bug
self.editor.hideCompleters() self.editor.hideCompleters()
tooltip(tr(TR.ADDING_ADDED), period=500) tooltip(tr.adding_added(), period=500)
av_player.stop_and_clear_queue() av_player.stop_and_clear_queue()
self._load_new_note(sticky_fields_from=note) self._load_new_note(sticky_fields_from=note)
gui_hooks.add_cards_did_add_note(note) gui_hooks.add_cards_did_add_note(note)
@ -215,7 +215,7 @@ class AddCards(QDialog):
def _note_can_be_added(self, note: Note) -> bool: def _note_can_be_added(self, note: Note) -> bool:
result = note.duplicate_or_empty() result = note.duplicate_or_empty()
if result == DuplicateOrEmptyResult.EMPTY: if result == DuplicateOrEmptyResult.EMPTY:
problem = tr(TR.ADDING_THE_FIRST_FIELD_IS_EMPTY) problem = tr.adding_the_first_field_is_empty()
else: else:
# duplicate entries are allowed these days # duplicate entries are allowed these days
problem = None problem = None
@ -229,7 +229,7 @@ class AddCards(QDialog):
# missing cloze deletion? # missing cloze deletion?
if note.model()["type"] == MODEL_CLOZE: if note.model()["type"] == MODEL_CLOZE:
if not note.cloze_numbers_in_fields(): if not note.cloze_numbers_in_fields():
if not askUser(tr(TR.ADDING_YOU_HAVE_A_CLOZE_DELETION_NOTE)): if not askUser(tr.adding_you_have_a_cloze_deletion_note()):
return False return False
return True return True
@ -256,7 +256,7 @@ class AddCards(QDialog):
def ifCanClose(self, onOk: Callable) -> None: def ifCanClose(self, onOk: Callable) -> None:
def afterSave() -> None: def afterSave() -> None:
ok = self.editor.fieldsAreBlank(self._last_added_note) or askUser( ok = self.editor.fieldsAreBlank(self._last_added_note) or askUser(
tr(TR.ADDING_CLOSE_AND_LOSE_CURRENT_INPUT), defaultno=True tr.adding_close_and_lose_current_input(), defaultno=True
) )
if ok: if ok:
onOk() onOk()

View File

@ -320,7 +320,7 @@ class AddonManager:
meta = self.addon_meta(dir) meta = self.addon_meta(dir)
name = meta.human_name() name = meta.human_name()
if not meta.enabled: if not meta.enabled:
name += f" {tr(TR.ADDONS_DISABLED)}" name += f" {tr.addons_disabled()}"
return name return name
# Conflict resolution # Conflict resolution
@ -475,8 +475,8 @@ class AddonManager:
) -> List[str]: ) -> List[str]:
messages = { messages = {
"zip": tr(TR.ADDONS_CORRUPT_ADDON_FILE), "zip": tr.addons_corrupt_addon_file(),
"manifest": tr(TR.ADDONS_INVALID_ADDON_MANIFEST), "manifest": tr.addons_invalid_addon_manifest(),
} }
msg = messages.get( msg = messages.get(
@ -504,13 +504,13 @@ class AddonManager:
if result.conflicts: if result.conflicts:
strings.append( strings.append(
tr(TR.ADDONS_THE_FOLLOWING_CONFLICTING_ADDONS_WERE_DISABLED) tr.addons_the_following_conflicting_addons_were_disabled()
+ " " + " "
+ ", ".join(self.addonName(f) for f in result.conflicts) + ", ".join(self.addonName(f) for f in result.conflicts)
) )
if not result.compatible: if not result.compatible:
strings.append(tr(TR.ADDONS_THIS_ADDON_IS_NOT_COMPATIBLE_WITH)) strings.append(tr.addons_this_addon_is_not_compatible_with())
return strings return strings
@ -714,7 +714,7 @@ class AddonsDialog(QDialog):
qconnect(f.config.clicked, self.onConfig) qconnect(f.config.clicked, self.onConfig)
qconnect(self.form.addonList.itemDoubleClicked, self.onConfig) qconnect(self.form.addonList.itemDoubleClicked, self.onConfig)
qconnect(self.form.addonList.currentRowChanged, self._onAddonItemSelected) qconnect(self.form.addonList.currentRowChanged, self._onAddonItemSelected)
self.setWindowTitle(tr(TR.ADDONS_WINDOW_TITLE)) self.setWindowTitle(tr.addons_window_title())
disable_help_button(self) disable_help_button(self)
self.setAcceptDrops(True) self.setAcceptDrops(True)
self.redrawAddons() self.redrawAddons()
@ -752,7 +752,7 @@ class AddonsDialog(QDialog):
name = addon.human_name() name = addon.human_name()
if not addon.enabled: if not addon.enabled:
return f"{name} {tr(TR.ADDONS_DISABLED2)}" return f"{name} {tr.addons_disabled2()}"
elif not addon.compatible(): elif not addon.compatible():
return f"{name} {tr(TR.ADDONS_REQUIRES, val=self.compatible_string(addon))}" return f"{name} {tr(TR.ADDONS_REQUIRES, val=self.compatible_string(addon))}"
@ -813,7 +813,7 @@ class AddonsDialog(QDialog):
def onlyOneSelected(self) -> Optional[str]: def onlyOneSelected(self) -> Optional[str]:
dirs = self.selectedAddons() dirs = self.selectedAddons()
if len(dirs) != 1: if len(dirs) != 1:
showInfo(tr(TR.ADDONS_PLEASE_SELECT_A_SINGLE_ADDON_FIRST)) showInfo(tr.addons_please_select_a_single_addon_first())
return None return None
return dirs[0] return dirs[0]
@ -829,7 +829,7 @@ class AddonsDialog(QDialog):
if re.match(r"^\d+$", addon): if re.match(r"^\d+$", addon):
openLink(f"{aqt.appShared}info/{addon}") openLink(f"{aqt.appShared}info/{addon}")
else: else:
showWarning(tr(TR.ADDONS_ADDON_WAS_NOT_DOWNLOADED_FROM_ANKIWEB)) showWarning(tr.addons_addon_was_not_downloaded_from_ankiweb())
def onViewFiles(self) -> None: def onViewFiles(self) -> None:
# if nothing selected, open top level folder # if nothing selected, open top level folder
@ -869,13 +869,13 @@ class AddonsDialog(QDialog):
if log: if log:
show_log_to_user(self, log) show_log_to_user(self, log)
else: else:
tooltip(tr(TR.ADDONS_NO_UPDATES_AVAILABLE)) tooltip(tr.addons_no_updates_available())
def onInstallFiles(self, paths: Optional[List[str]] = None) -> Optional[bool]: def onInstallFiles(self, paths: Optional[List[str]] = None) -> Optional[bool]:
if not paths: if not paths:
key = f"{tr(TR.ADDONS_PACKAGED_ANKI_ADDON)} (*{self.mgr.ext})" key = f"{tr.addons_packaged_anki_addon()} (*{self.mgr.ext})"
paths_ = getFile( paths_ = getFile(
self, tr(TR.ADDONS_INSTALL_ADDONS), None, key, key="addons", multi=True self, tr.addons_install_addons(), None, key, key="addons", multi=True
) )
paths = paths_ # type: ignore paths = paths_ # type: ignore
if not paths: if not paths:
@ -887,7 +887,7 @@ class AddonsDialog(QDialog):
return None return None
def check_for_updates(self) -> None: def check_for_updates(self) -> None:
tooltip(tr(TR.ADDONS_CHECKING)) tooltip(tr.addons_checking())
check_and_prompt_for_updates(self, self.mgr, self.after_downloading) check_and_prompt_for_updates(self, self.mgr, self.after_downloading)
def onConfig(self) -> None: def onConfig(self) -> None:
@ -904,7 +904,7 @@ class AddonsDialog(QDialog):
conf = self.mgr.getConfig(addon) conf = self.mgr.getConfig(addon)
if conf is None: if conf is None:
showInfo(tr(TR.ADDONS_ADDON_HAS_NO_CONFIGURATION)) showInfo(tr.addons_addon_has_no_configuration())
return return
ConfigEditor(self, addon, conf) ConfigEditor(self, addon, conf)
@ -924,7 +924,7 @@ class GetAddons(QDialog):
self.form = aqt.forms.getaddons.Ui_Dialog() self.form = aqt.forms.getaddons.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
b = self.form.buttonBox.addButton( b = self.form.buttonBox.addButton(
tr(TR.ADDONS_BROWSE_ADDONS), QDialogButtonBox.ActionRole tr.addons_browse_addons(), QDialogButtonBox.ActionRole
) )
qconnect(b.clicked, self.onBrowse) qconnect(b.clicked, self.onBrowse)
disable_help_button(self) disable_help_button(self)
@ -940,7 +940,7 @@ class GetAddons(QDialog):
try: try:
ids = [int(n) for n in self.form.code.text().split()] ids = [int(n) for n in self.form.code.text().split()]
except ValueError: except ValueError:
showWarning(tr(TR.ADDONS_INVALID_CODE)) showWarning(tr.addons_invalid_code())
return return
self.ids = ids self.ids = ids
@ -1013,19 +1013,19 @@ def describe_log_entry(id_and_entry: DownloadLogEntry) -> str:
if isinstance(entry, DownloadError): if isinstance(entry, DownloadError):
if entry.status_code is not None: if entry.status_code is not None:
if entry.status_code in (403, 404): if entry.status_code in (403, 404):
buf += tr(TR.ADDONS_INVALID_CODE_OR_ADDON_NOT_AVAILABLE) buf += tr.addons_invalid_code_or_addon_not_available()
else: else:
buf += tr(TR.QT_MISC_UNEXPECTED_RESPONSE_CODE, val=entry.status_code) buf += tr(TR.QT_MISC_UNEXPECTED_RESPONSE_CODE, val=entry.status_code)
else: else:
buf += ( buf += (
tr(TR.ADDONS_PLEASE_CHECK_YOUR_INTERNET_CONNECTION) tr.addons_please_check_your_internet_connection()
+ "\n\n" + "\n\n"
+ str(entry.exception) + str(entry.exception)
) )
elif isinstance(entry, InstallError): elif isinstance(entry, InstallError):
buf += entry.errmsg buf += entry.errmsg
else: else:
buf += tr(TR.ADDONS_INSTALLED_SUCCESSFULLY) buf += tr.addons_installed_successfully()
return buf return buf
@ -1117,9 +1117,9 @@ def show_log_to_user(parent: QWidget, log: List[DownloadLogEntry]) -> None:
have_problem = download_encountered_problem(log) have_problem = download_encountered_problem(log)
if have_problem: if have_problem:
text = tr(TR.ADDONS_ONE_OR_MORE_ERRORS_OCCURRED) text = tr.addons_one_or_more_errors_occurred()
else: else:
text = tr(TR.ADDONS_DOWNLOAD_COMPLETE_PLEASE_RESTART_ANKI_TO) text = tr.addons_download_complete_please_restart_anki_to()
text += f"<br><br>{download_log_to_html(log)}" text += f"<br><br>{download_log_to_html(log)}"
if have_problem: if have_problem:
@ -1223,7 +1223,7 @@ class ChooseAddonsToUpdateList(QListWidget):
item = self.itemAt(point) item = self.itemAt(point)
addon_id = item.data(self.ADDON_ID_ROLE) addon_id = item.data(self.ADDON_ID_ROLE)
m = QMenu() m = QMenu()
a = m.addAction(tr(TR.ADDONS_VIEW_ADDON_PAGE)) a = m.addAction(tr.addons_view_addon_page())
qconnect(a.triggered, lambda _: openLink(f"{aqt.appShared}info/{addon_id}")) qconnect(a.triggered, lambda _: openLink(f"{aqt.appShared}info/{addon_id}"))
m.exec_(QCursor.pos()) m.exec_(QCursor.pos())
@ -1268,7 +1268,7 @@ class ChooseAddonsToUpdateDialog(QDialog):
self, parent: QWidget, mgr: AddonManager, updated_addons: List[UpdateInfo] self, parent: QWidget, mgr: AddonManager, updated_addons: List[UpdateInfo]
) -> None: ) -> None:
QDialog.__init__(self, parent) QDialog.__init__(self, parent)
self.setWindowTitle(tr(TR.ADDONS_CHOOSE_UPDATE_WINDOW_TITLE)) self.setWindowTitle(tr.addons_choose_update_window_title())
self.setWindowModality(Qt.WindowModal) self.setWindowModality(Qt.WindowModal)
self.mgr = mgr self.mgr = mgr
self.updated_addons = updated_addons self.updated_addons = updated_addons
@ -1277,7 +1277,7 @@ class ChooseAddonsToUpdateDialog(QDialog):
def setup(self) -> None: def setup(self) -> None:
layout = QVBoxLayout() layout = QVBoxLayout()
label = QLabel(tr(TR.ADDONS_THE_FOLLOWING_ADDONS_HAVE_UPDATES_AVAILABLE)) label = QLabel(tr.addons_the_following_addons_have_updates_available())
layout.addWidget(label) layout.addWidget(label)
addons_list_widget = ChooseAddonsToUpdateList( addons_list_widget = ChooseAddonsToUpdateList(
self, self.mgr, self.updated_addons self, self.mgr, self.updated_addons
@ -1475,7 +1475,7 @@ class ConfigEditor(QDialog):
def onRestoreDefaults(self) -> None: def onRestoreDefaults(self) -> None:
default_conf = self.mgr.addonConfigDefaults(self.addon) default_conf = self.mgr.addonConfigDefaults(self.addon)
self.updateText(default_conf) self.updateText(default_conf)
tooltip(tr(TR.ADDONS_RESTORED_DEFAULTS), parent=self) tooltip(tr.addons_restored_defaults(), parent=self)
def setupFonts(self) -> None: def setupFonts(self) -> None:
font_mono = QFontDatabase.systemFont(QFontDatabase.FixedFont) font_mono = QFontDatabase.systemFont(QFontDatabase.FixedFont)
@ -1541,11 +1541,11 @@ class ConfigEditor(QDialog):
showInfo(msg) showInfo(msg)
return return
except Exception as e: except Exception as e:
showInfo(f"{tr(TR.ADDONS_INVALID_CONFIGURATION)} {repr(e)}") showInfo(f"{tr.addons_invalid_configuration()} {repr(e)}")
return return
if not isinstance(new_conf, dict): if not isinstance(new_conf, dict):
showInfo(tr(TR.ADDONS_INVALID_CONFIGURATION_TOP_LEVEL_OBJECT_MUST)) showInfo(tr.addons_invalid_configuration_top_level_object_must())
return return
if new_conf != self.conf: if new_conf != self.conf:
@ -1574,14 +1574,12 @@ def installAddonPackages(
if warn: if warn:
names = ",<br>".join(f"<b>{os.path.basename(p)}</b>" for p in paths) names = ",<br>".join(f"<b>{os.path.basename(p)}</b>" for p in paths)
q = tr(TR.ADDONS_IMPORTANT_AS_ADDONS_ARE_PROGRAMS_DOWNLOADED) % dict( q = tr.addons_important_as_addons_are_programs_downloaded() % dict(names=names)
names=names
)
if ( if (
not showInfo( not showInfo(
q, q,
parent=parent, parent=parent,
title=tr(TR.ADDONS_INSTALL_ANKI_ADDON), title=tr.addons_install_anki_addon(),
type="warning", type="warning",
customBtns=[QMessageBox.No, QMessageBox.Yes], customBtns=[QMessageBox.No, QMessageBox.Yes],
) )
@ -1594,7 +1592,7 @@ def installAddonPackages(
if log: if log:
log_html = "<br>".join(log) log_html = "<br>".join(log)
if advise_restart: if advise_restart:
log_html += f"<br><br>{tr(TR.ADDONS_PLEASE_RESTART_ANKI_TO_COMPLETE_THE)}" log_html += f"<br><br>{tr.addons_please_restart_anki_to_complete_the()}"
if len(log) == 1 and not strictly_modal: if len(log) == 1 and not strictly_modal:
tooltip(log_html, parent=parent) tooltip(log_html, parent=parent)
else: else:
@ -1602,15 +1600,15 @@ def installAddonPackages(
log_html, log_html,
parent=parent, parent=parent,
textFormat="rich", textFormat="rich",
title=tr(TR.ADDONS_INSTALLATION_COMPLETE), title=tr.addons_installation_complete(),
) )
if errs: if errs:
msg = tr(TR.ADDONS_PLEASE_REPORT_THIS_TO_THE_RESPECTIVE) msg = tr.addons_please_report_this_to_the_respective()
showWarning( showWarning(
"<br><br>".join(errs + [msg]), "<br><br>".join(errs + [msg]),
parent=parent, parent=parent,
textFormat="rich", textFormat="rich",
title=tr(TR.ADDONS_ADDON_INSTALLATION_ERROR), title=tr.addons_addon_installation_error(),
) )
return not errs return not errs

View File

@ -142,7 +142,7 @@ class CellRow:
@staticmethod @staticmethod
def deleted(length: int) -> CellRow: def deleted(length: int) -> CellRow:
return CellRow.generic(length, tr(TR.BROWSING_ROW_DELETED)) return CellRow.generic(length, tr.browsing_row_deleted())
def backend_color_to_aqt_color(color: BrowserRow.Color.V) -> Optional[Tuple[str, str]]: def backend_color_to_aqt_color(color: BrowserRow.Color.V) -> Optional[Tuple[str, str]]:
@ -271,7 +271,7 @@ class DataModel(QAbstractTableModel):
break break
# give the user a hint an invalid column was added by an add-on # give the user a hint an invalid column was added by an add-on
if not txt: if not txt:
txt = tr(TR.BROWSING_ADDON) txt = tr.browsing_addon()
return txt return txt
else: else:
return None return None
@ -632,21 +632,21 @@ class Browser(QMainWindow):
def setupColumns(self) -> None: def setupColumns(self) -> None:
self.columns = [ self.columns = [
("question", tr(TR.BROWSING_QUESTION)), ("question", tr.browsing_question()),
("answer", tr(TR.BROWSING_ANSWER)), ("answer", tr.browsing_answer()),
("template", tr(TR.BROWSING_CARD)), ("template", tr.browsing_card()),
("deck", tr(TR.DECKS_DECK)), ("deck", tr.decks_deck()),
("noteFld", tr(TR.BROWSING_SORT_FIELD)), ("noteFld", tr.browsing_sort_field()),
("noteCrt", tr(TR.BROWSING_CREATED)), ("noteCrt", tr.browsing_created()),
("noteMod", tr(TR.SEARCH_NOTE_MODIFIED)), ("noteMod", tr.search_note_modified()),
("cardMod", tr(TR.SEARCH_CARD_MODIFIED)), ("cardMod", tr.search_card_modified()),
("cardDue", tr(TR.STATISTICS_DUE_DATE)), ("cardDue", tr.statistics_due_date()),
("cardIvl", tr(TR.BROWSING_INTERVAL)), ("cardIvl", tr.browsing_interval()),
("cardEase", tr(TR.BROWSING_EASE)), ("cardEase", tr.browsing_ease()),
("cardReps", tr(TR.SCHEDULING_REVIEWS)), ("cardReps", tr.scheduling_reviews()),
("cardLapses", tr(TR.SCHEDULING_LAPSES)), ("cardLapses", tr.scheduling_lapses()),
("noteTags", tr(TR.EDITING_TAGS)), ("noteTags", tr.editing_tags()),
("note", tr(TR.BROWSING_NOTE)), ("note", tr.browsing_note()),
] ]
self.columns.sort(key=itemgetter(1)) self.columns.sort(key=itemgetter(1))
@ -674,7 +674,7 @@ class Browser(QMainWindow):
qconnect(self.form.searchEdit.lineEdit().returnPressed, self.onSearchActivated) qconnect(self.form.searchEdit.lineEdit().returnPressed, self.onSearchActivated)
self.form.searchEdit.setCompleter(None) self.form.searchEdit.setCompleter(None)
self.form.searchEdit.lineEdit().setPlaceholderText( self.form.searchEdit.lineEdit().setPlaceholderText(
tr(TR.BROWSING_SEARCH_BAR_HINT) tr.browsing_search_bar_hint()
) )
self.form.searchEdit.addItems(self.mw.pm.profile["searchHistory"]) self.form.searchEdit.addItems(self.mw.pm.profile["searchHistory"])
if search is not None: if search is not None:
@ -805,7 +805,7 @@ QTableView {{ gridline-color: {grid} }}
TR.BROWSING_PREVIEW_SELECTED_CARD, TR.BROWSING_PREVIEW_SELECTED_CARD,
val=shortcut(preview_shortcut), val=shortcut(preview_shortcut),
), ),
tr(TR.ACTIONS_PREVIEW), tr.actions_preview(),
id="previewButton", id="previewButton",
keys=preview_shortcut, keys=preview_shortcut,
disables=False, disables=False,
@ -875,7 +875,7 @@ QTableView {{ gridline-color: {grid} }}
type = self.model.activeCols[idx] type = self.model.activeCols[idx]
noSort = ("question", "answer") noSort = ("question", "answer")
if type in noSort: if type in noSort:
showInfo(tr(TR.BROWSING_SORTING_ON_THIS_COLUMN_IS_NOT)) showInfo(tr.browsing_sorting_on_this_column_is_not())
type = self.col.conf["sortType"] type = self.col.conf["sortType"]
if self.col.conf["sortType"] != type: if self.col.conf["sortType"] != type:
self.col.conf["sortType"] = type self.col.conf["sortType"] = type
@ -925,7 +925,7 @@ QTableView {{ gridline-color: {grid} }}
if type in self.model.activeCols: if type in self.model.activeCols:
if len(self.model.activeCols) < 2: if len(self.model.activeCols) < 2:
self.model.endReset() self.model.endReset()
showInfo(tr(TR.BROWSING_YOU_MUST_HAVE_AT_LEAST_ONE)) showInfo(tr.browsing_you_must_have_at_least_one())
return return
self.model.activeCols.remove(type) self.model.activeCols.remove(type)
adding = False adding = False
@ -956,7 +956,7 @@ QTableView {{ gridline-color: {grid} }}
self.setColumnSizes() self.setColumnSizes()
def setupSidebar(self) -> None: def setupSidebar(self) -> None:
dw = self.sidebarDockWidget = QDockWidget(tr(TR.BROWSING_SIDEBAR), self) dw = self.sidebarDockWidget = QDockWidget(tr.browsing_sidebar(), self)
dw.setFeatures(QDockWidget.DockWidgetClosable) dw.setFeatures(QDockWidget.DockWidgetClosable)
dw.setObjectName("Sidebar") dw.setObjectName("Sidebar")
dw.setAllowedAreas(Qt.LeftDockWidgetArea) dw.setAllowedAreas(Qt.LeftDockWidgetArea)
@ -1085,7 +1085,7 @@ where id in %s"""
% ids2str(sf) % ids2str(sf)
) )
if mods > 1: if mods > 1:
showInfo(tr(TR.BROWSING_PLEASE_SELECT_CARDS_FROM_ONLY_ONE)) showInfo(tr.browsing_please_select_cards_from_only_one())
return [] return []
return sf return sf
@ -1185,8 +1185,8 @@ where id in %s"""
ret = StudyDeck( ret = StudyDeck(
self.mw, self.mw,
current=current, current=current,
accept=tr(TR.BROWSING_MOVE_CARDS), accept=tr.browsing_move_cards(),
title=tr(TR.BROWSING_CHANGE_DECK), title=tr.browsing_change_deck(),
help=HelpPage.BROWSING, help=HelpPage.BROWSING,
parent=self, parent=self,
) )
@ -1209,9 +1209,7 @@ where id in %s"""
tags: Optional[str] = None, tags: Optional[str] = None,
) -> None: ) -> None:
"Shows prompt if tags not provided." "Shows prompt if tags not provided."
if not ( if not (tags := tags or self._prompt_for_tags(tr.browsing_enter_tags_to_add())):
tags := tags or self._prompt_for_tags(tr(TR.BROWSING_ENTER_TAGS_TO_ADD))
):
return return
add_tags( add_tags(
mw=self.mw, mw=self.mw,
@ -1226,7 +1224,7 @@ where id in %s"""
def remove_tags_from_selected_notes(self, tags: Optional[str] = None) -> None: def remove_tags_from_selected_notes(self, tags: Optional[str] = None) -> None:
"Shows prompt if tags not provided." "Shows prompt if tags not provided."
if not ( if not (
tags := tags or self._prompt_for_tags(tr(TR.BROWSING_ENTER_TAGS_TO_DELETE)) tags := tags or self._prompt_for_tags(tr.browsing_enter_tags_to_delete())
): ):
return return
remove_tags_for_notes( remove_tags_for_notes(
@ -1320,7 +1318,7 @@ where id in %s"""
@ensure_editor_saved_on_trigger @ensure_editor_saved_on_trigger
def reposition(self) -> None: def reposition(self) -> None:
if self.card and self.card.queue != QUEUE_TYPE_NEW: if self.card and self.card.queue != QUEUE_TYPE_NEW:
showInfo(tr(TR.BROWSING_ONLY_NEW_CARDS_CAN_BE_REPOSITIONED), parent=self) showInfo(tr.browsing_only_new_cards_can_be_repositioned(), parent=self)
return return
reposition_new_cards_dialog( reposition_new_cards_dialog(
@ -1456,7 +1454,7 @@ where id in %s"""
self.duplicatesReport(frm.webView, field, search_text, frm, web_context) self.duplicatesReport(frm.webView, field, search_text, frm, web_context)
search = frm.buttonBox.addButton( search = frm.buttonBox.addButton(
tr(TR.ACTIONS_SEARCH), QDialogButtonBox.ActionRole tr.actions_search(), QDialogButtonBox.ActionRole
) )
qconnect(search.clicked, onClick) qconnect(search.clicked, onClick)
d.show() d.show()
@ -1478,7 +1476,7 @@ where id in %s"""
return return
if not self._dupesButton: if not self._dupesButton:
self._dupesButton = b = frm.buttonBox.addButton( self._dupesButton = b = frm.buttonBox.addButton(
tr(TR.BROWSING_TAG_DUPLICATES), QDialogButtonBox.ActionRole tr.browsing_tag_duplicates(), QDialogButtonBox.ActionRole
) )
qconnect(b.clicked, lambda: self._onTagDupes(res)) qconnect(b.clicked, lambda: self._onTagDupes(res))
t = "" t = ""
@ -1509,15 +1507,15 @@ where id in %s"""
if not res: if not res:
return return
self.model.beginReset() self.model.beginReset()
self.mw.checkpoint(tr(TR.BROWSING_TAG_DUPLICATES)) self.mw.checkpoint(tr.browsing_tag_duplicates())
nids = set() nids = set()
for _, nidlist in res: for _, nidlist in res:
nids.update(nidlist) nids.update(nidlist)
self.col.tags.bulk_add(list(nids), tr(TR.BROWSING_DUPLICATE)) self.col.tags.bulk_add(list(nids), tr.browsing_duplicate())
self.mw.progress.finish() self.mw.progress.finish()
self.model.endReset() self.model.endReset()
self.mw.requireReset(reason=ResetReason.BrowserTagDupes, context=self) self.mw.requireReset(reason=ResetReason.BrowserTagDupes, context=self)
tooltip(tr(TR.BROWSING_NOTES_TAGGED)) tooltip(tr.browsing_notes_tagged())
def dupeLinkClicked(self, link: str) -> None: def dupeLinkClicked(self, link: str) -> None:
self.search_for(link) self.search_for(link)
@ -1681,7 +1679,7 @@ class ChangeModel(QDialog):
map = QWidget() map = QWidget()
l = QGridLayout() l = QGridLayout()
combos = [] combos = []
targets = [x["name"] for x in dst] + [tr(TR.BROWSING_NOTHING)] targets = [x["name"] for x in dst] + [tr.browsing_nothing()]
indices = {} indices = {}
for i, x in enumerate(src): for i, x in enumerate(src):
l.addWidget(QLabel(tr(TR.BROWSING_CHANGE_TO, val=x["name"])), i, 0) l.addWidget(QLabel(tr(TR.BROWSING_CHANGE_TO, val=x["name"])), i, 0)
@ -1767,9 +1765,9 @@ class ChangeModel(QDialog):
fmap = self.getFieldMap() fmap = self.getFieldMap()
cmap = self.getTemplateMap() cmap = self.getTemplateMap()
if any(True for c in list(cmap.values()) if c is None): if any(True for c in list(cmap.values()) if c is None):
if not askUser(tr(TR.BROWSING_ANY_CARDS_MAPPED_TO_NOTHING_WILL)): if not askUser(tr.browsing_any_cards_mapped_to_nothing_will()):
return return
self.browser.mw.checkpoint(tr(TR.BROWSING_CHANGE_NOTE_TYPE)) self.browser.mw.checkpoint(tr.browsing_change_note_type())
b = self.browser b = self.browser
b.mw.col.modSchema(check=True) b.mw.col.modSchema(check=True)
b.mw.progress.start() b.mw.progress.start()

View File

@ -60,7 +60,7 @@ class CardLayout(QDialog):
self.mobile_emulation_enabled = False self.mobile_emulation_enabled = False
self.have_autoplayed = False self.have_autoplayed = False
self.mm._remove_from_cache(self.model["id"]) self.mm._remove_from_cache(self.model["id"])
self.mw.checkpoint(tr(TR.CARD_TEMPLATES_CARD_TYPES)) self.mw.checkpoint(tr.card_templates_card_types())
self.change_tracker = ChangeTracker(self.mw) self.change_tracker = ChangeTracker(self.mw)
self.setupTopArea() self.setupTopArea()
self.setupMainArea() self.setupMainArea()
@ -114,14 +114,14 @@ class CardLayout(QDialog):
self.topAreaForm = aqt.forms.clayout_top.Ui_Form() self.topAreaForm = aqt.forms.clayout_top.Ui_Form()
self.topAreaForm.setupUi(self.topArea) self.topAreaForm.setupUi(self.topArea)
self.topAreaForm.templateOptions.setText( self.topAreaForm.templateOptions.setText(
f"{tr(TR.ACTIONS_OPTIONS)} {downArrow()}" f"{tr.actions_options()} {downArrow()}"
) )
qconnect(self.topAreaForm.templateOptions.clicked, self.onMore) qconnect(self.topAreaForm.templateOptions.clicked, self.onMore)
qconnect( qconnect(
self.topAreaForm.templatesBox.currentIndexChanged, self.topAreaForm.templatesBox.currentIndexChanged,
self.update_current_ordinal_and_redraw, self.update_current_ordinal_and_redraw,
) )
self.topAreaForm.card_type_label.setText(tr(TR.CARD_TEMPLATES_CARD_TYPE)) self.topAreaForm.card_type_label.setText(tr.card_templates_card_type())
def updateTopArea(self) -> None: def updateTopArea(self) -> None:
self.updateCardNames() self.updateCardNames()
@ -211,9 +211,9 @@ class CardLayout(QDialog):
self.pform = aqt.forms.preview.Ui_Form() self.pform = aqt.forms.preview.Ui_Form()
pform = self.pform pform = self.pform
pform.setupUi(right) pform.setupUi(right)
pform.preview_front.setText(tr(TR.CARD_TEMPLATES_FRONT_PREVIEW)) pform.preview_front.setText(tr.card_templates_front_preview())
pform.preview_back.setText(tr(TR.CARD_TEMPLATES_BACK_PREVIEW)) pform.preview_back.setText(tr.card_templates_back_preview())
pform.preview_box.setTitle(tr(TR.CARD_TEMPLATES_PREVIEW_BOX)) pform.preview_box.setTitle(tr.card_templates_preview_box())
self.setup_edit_area() self.setup_edit_area()
self.setup_preview() self.setup_preview()
@ -223,10 +223,10 @@ class CardLayout(QDialog):
def setup_edit_area(self) -> None: def setup_edit_area(self) -> None:
tform = self.tform tform = self.tform
tform.front_button.setText(tr(TR.CARD_TEMPLATES_FRONT_TEMPLATE)) tform.front_button.setText(tr.card_templates_front_template())
tform.back_button.setText(tr(TR.CARD_TEMPLATES_BACK_TEMPLATE)) tform.back_button.setText(tr.card_templates_back_template())
tform.style_button.setText(tr(TR.CARD_TEMPLATES_TEMPLATE_STYLING)) tform.style_button.setText(tr.card_templates_template_styling())
tform.groupBox.setTitle(tr(TR.CARD_TEMPLATES_TEMPLATE_BOX)) tform.groupBox.setTitle(tr.card_templates_template_box())
cnt = self.mw.col.models.useCount(self.model) cnt = self.mw.col.models.useCount(self.model)
self.tform.changes_affect_label.setText( self.tform.changes_affect_label.setText(
@ -310,7 +310,7 @@ class CardLayout(QDialog):
qconnect(pform.preview_front.clicked, self.on_preview_toggled) qconnect(pform.preview_front.clicked, self.on_preview_toggled)
qconnect(pform.preview_back.clicked, self.on_preview_toggled) qconnect(pform.preview_back.clicked, self.on_preview_toggled)
pform.preview_settings.setText( pform.preview_settings.setText(
f"{tr(TR.CARD_TEMPLATES_PREVIEW_SETTINGS)} {downArrow()}" f"{tr.card_templates_preview_settings()} {downArrow()}"
) )
qconnect(pform.preview_settings.clicked, self.on_preview_settings) qconnect(pform.preview_settings.clicked, self.on_preview_settings)
@ -355,19 +355,19 @@ class CardLayout(QDialog):
def on_preview_settings(self) -> None: def on_preview_settings(self) -> None:
m = QMenu(self) m = QMenu(self)
a = m.addAction(tr(TR.CARD_TEMPLATES_FILL_EMPTY)) a = m.addAction(tr.card_templates_fill_empty())
a.setCheckable(True) a.setCheckable(True)
a.setChecked(self.fill_empty_action_toggled) a.setChecked(self.fill_empty_action_toggled)
qconnect(a.triggered, self.on_fill_empty_action_toggled) qconnect(a.triggered, self.on_fill_empty_action_toggled)
if not self.note_has_empty_field(): if not self.note_has_empty_field():
a.setVisible(False) a.setVisible(False)
a = m.addAction(tr(TR.CARD_TEMPLATES_NIGHT_MODE)) a = m.addAction(tr.card_templates_night_mode())
a.setCheckable(True) a.setCheckable(True)
a.setChecked(self.night_mode_is_enabled) a.setChecked(self.night_mode_is_enabled)
qconnect(a.triggered, self.on_night_mode_action_toggled) qconnect(a.triggered, self.on_night_mode_action_toggled)
a = m.addAction(tr(TR.CARD_TEMPLATES_ADD_MOBILE_CLASS)) a = m.addAction(tr.card_templates_add_mobile_class())
a.setCheckable(True) a.setCheckable(True)
a.setChecked(self.mobile_emulation_enabled) a.setChecked(self.mobile_emulation_enabled)
qconnect(a.toggled, self.on_mobile_class_action_toggled) qconnect(a.toggled, self.on_mobile_class_action_toggled)
@ -394,28 +394,28 @@ class CardLayout(QDialog):
def setupButtons(self) -> None: def setupButtons(self) -> None:
l = self.buttons = QHBoxLayout() l = self.buttons = QHBoxLayout()
help = QPushButton(tr(TR.ACTIONS_HELP)) help = QPushButton(tr.actions_help())
help.setAutoDefault(False) help.setAutoDefault(False)
l.addWidget(help) l.addWidget(help)
qconnect(help.clicked, self.onHelp) qconnect(help.clicked, self.onHelp)
l.addStretch() l.addStretch()
self.add_field_button = QPushButton(tr(TR.FIELDS_ADD_FIELD)) self.add_field_button = QPushButton(tr.fields_add_field())
self.add_field_button.setAutoDefault(False) self.add_field_button.setAutoDefault(False)
l.addWidget(self.add_field_button) l.addWidget(self.add_field_button)
qconnect(self.add_field_button.clicked, self.onAddField) qconnect(self.add_field_button.clicked, self.onAddField)
if not self._isCloze(): if not self._isCloze():
flip = QPushButton(tr(TR.CARD_TEMPLATES_FLIP)) flip = QPushButton(tr.card_templates_flip())
flip.setAutoDefault(False) flip.setAutoDefault(False)
l.addWidget(flip) l.addWidget(flip)
qconnect(flip.clicked, self.onFlip) qconnect(flip.clicked, self.onFlip)
l.addStretch() l.addStretch()
save = QPushButton(tr(TR.ACTIONS_SAVE)) save = QPushButton(tr.actions_save())
save.setAutoDefault(False) save.setAutoDefault(False)
save.setShortcut(QKeySequence("Ctrl+Return")) save.setShortcut(QKeySequence("Ctrl+Return"))
l.addWidget(save) l.addWidget(save)
qconnect(save.clicked, self.accept) qconnect(save.clicked, self.accept)
close = QPushButton(tr(TR.ACTIONS_CANCEL)) close = QPushButton(tr.actions_cancel())
close.setAutoDefault(False) close.setAutoDefault(False)
l.addWidget(close) l.addWidget(close)
qconnect(close.clicked, self.reject) qconnect(close.clicked, self.reject)
@ -548,7 +548,7 @@ class CardLayout(QDialog):
def onRemove(self) -> None: def onRemove(self) -> None:
if len(self.templates) < 2: if len(self.templates) < 2:
showInfo(tr(TR.CARD_TEMPLATES_AT_LEAST_ONE_CARD_TYPE_IS)) showInfo(tr.card_templates_at_least_one_card_type_is())
return return
def get_count() -> int: def get_count() -> int:
@ -586,7 +586,7 @@ class CardLayout(QDialog):
def onRename(self) -> None: def onRename(self) -> None:
template = self.current_template() template = self.current_template()
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=template["name"]).replace( name = getOnlyText(tr.actions_new_name(), default=template["name"]).replace(
'"', "" '"', ""
) )
if not name.strip(): if not name.strip():
@ -653,7 +653,7 @@ class CardLayout(QDialog):
def _flipQA(self, src: Dict, dst: Dict) -> None: def _flipQA(self, src: Dict, dst: Dict) -> None:
m = re.match("(?s)(.+)<hr id=answer>(.+)", src["afmt"]) m = re.match("(?s)(.+)<hr id=answer>(.+)", src["afmt"])
if not m: if not m:
showInfo(tr(TR.CARD_TEMPLATES_ANKI_COULDNT_FIND_THE_LINE_BETWEEN)) showInfo(tr.card_templates_anki_couldnt_find_the_line_between())
return return
self.change_tracker.mark_basic() self.change_tracker.mark_basic()
dst["afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n%s" % src["qfmt"] dst["afmt"] = "{{FrontSide}}\n\n<hr id=answer>\n\n%s" % src["qfmt"]
@ -663,29 +663,29 @@ class CardLayout(QDialog):
m = QMenu(self) m = QMenu(self)
if not self._isCloze(): if not self._isCloze():
a = m.addAction(tr(TR.CARD_TEMPLATES_ADD_CARD_TYPE)) a = m.addAction(tr.card_templates_add_card_type())
qconnect(a.triggered, self.onAddCard) qconnect(a.triggered, self.onAddCard)
a = m.addAction(tr(TR.CARD_TEMPLATES_REMOVE_CARD_TYPE)) a = m.addAction(tr.card_templates_remove_card_type())
qconnect(a.triggered, self.onRemove) qconnect(a.triggered, self.onRemove)
a = m.addAction(tr(TR.CARD_TEMPLATES_RENAME_CARD_TYPE)) a = m.addAction(tr.card_templates_rename_card_type())
qconnect(a.triggered, self.onRename) qconnect(a.triggered, self.onRename)
a = m.addAction(tr(TR.CARD_TEMPLATES_REPOSITION_CARD_TYPE)) a = m.addAction(tr.card_templates_reposition_card_type())
qconnect(a.triggered, self.onReorder) qconnect(a.triggered, self.onReorder)
m.addSeparator() m.addSeparator()
t = self.current_template() t = self.current_template()
if t["did"]: if t["did"]:
s = tr(TR.CARD_TEMPLATES_ON) s = tr.card_templates_on()
else: else:
s = tr(TR.CARD_TEMPLATES_OFF) s = tr.card_templates_off()
a = m.addAction(tr(TR.CARD_TEMPLATES_DECK_OVERRIDE) + s) a = m.addAction(tr.card_templates_deck_override() + s)
qconnect(a.triggered, self.onTargetDeck) qconnect(a.triggered, self.onTargetDeck)
a = m.addAction(tr(TR.CARD_TEMPLATES_BROWSER_APPEARANCE)) a = m.addAction(tr.card_templates_browser_appearance())
qconnect(a.triggered, self.onBrowserDisplay) qconnect(a.triggered, self.onBrowserDisplay)
m.exec_(self.topAreaForm.templateOptions.mapToGlobal(QPoint(0, 0))) m.exec_(self.topAreaForm.templateOptions.mapToGlobal(QPoint(0, 0)))
@ -795,7 +795,7 @@ class CardLayout(QDialog):
showWarning(str(e)) showWarning(str(e))
return return
self.mw.reset() self.mw.reset()
tooltip(tr(TR.CARD_TEMPLATES_CHANGES_SAVED), parent=self.parentWidget()) tooltip(tr.card_templates_changes_saved(), parent=self.parentWidget())
self.cleanup() self.cleanup()
gui_hooks.sidebar_should_refresh_notetypes() gui_hooks.sidebar_should_refresh_notetypes()
return QDialog.accept(self) return QDialog.accept(self)
@ -804,7 +804,7 @@ class CardLayout(QDialog):
def reject(self) -> None: def reject(self) -> None:
if self.change_tracker.changed(): if self.change_tracker.changed():
if not askUser(tr(TR.CARD_TEMPLATES_DISCARD_CHANGES)): if not askUser(tr.card_templates_discard_changes()):
return return
self.cleanup() self.cleanup()
return QDialog.reject(self) return QDialog.reject(self)

View File

@ -50,11 +50,11 @@ class CustomStudy(QDialog):
smin = 1 smin = 1
smax = DYN_MAX_SIZE smax = DYN_MAX_SIZE
sval = 1 sval = 1
post = tr(TR.CUSTOM_STUDY_CARDS) post = tr.custom_study_cards()
tit = "" tit = ""
spShow = True spShow = True
typeShow = False typeShow = False
ok = tr(TR.CUSTOM_STUDY_OK) ok = tr.custom_study_ok()
def plus(num: Union[int, str]) -> str: def plus(num: Union[int, str]) -> str:
if num == 1000: if num == 1000:
@ -71,7 +71,7 @@ class CustomStudy(QDialog):
tit = tr( tit = tr(
TR.CUSTOM_STUDY_NEW_CARDS_IN_DECK_OVER_TODAY, val=plus(newExceeding) TR.CUSTOM_STUDY_NEW_CARDS_IN_DECK_OVER_TODAY, val=plus(newExceeding)
) )
pre = tr(TR.CUSTOM_STUDY_INCREASE_TODAYS_NEW_CARD_LIMIT_BY) pre = tr.custom_study_increase_todays_new_card_limit_by()
sval = min(new, self.deck.get("extendNew", 10)) sval = min(new, self.deck.get("extendNew", 10))
smin = -DYN_MAX_SIZE smin = -DYN_MAX_SIZE
smax = newExceeding smax = newExceeding
@ -85,26 +85,26 @@ class CustomStudy(QDialog):
tit = tr( tit = tr(
TR.CUSTOM_STUDY_REVIEWS_DUE_IN_DECK_OVER_TODAY, val=plus(revExceeding) TR.CUSTOM_STUDY_REVIEWS_DUE_IN_DECK_OVER_TODAY, val=plus(revExceeding)
) )
pre = tr(TR.CUSTOM_STUDY_INCREASE_TODAYS_REVIEW_LIMIT_BY) pre = tr.custom_study_increase_todays_review_limit_by()
sval = min(rev, self.deck.get("extendRev", 10)) sval = min(rev, self.deck.get("extendRev", 10))
smin = -DYN_MAX_SIZE smin = -DYN_MAX_SIZE
smax = revExceeding smax = revExceeding
elif idx == RADIO_FORGOT: elif idx == RADIO_FORGOT:
pre = tr(TR.CUSTOM_STUDY_REVIEW_CARDS_FORGOTTEN_IN_LAST) pre = tr.custom_study_review_cards_forgotten_in_last()
post = tr(TR.SCHEDULING_DAYS) post = tr.scheduling_days()
smax = 30 smax = 30
elif idx == RADIO_AHEAD: elif idx == RADIO_AHEAD:
pre = tr(TR.CUSTOM_STUDY_REVIEW_AHEAD_BY) pre = tr.custom_study_review_ahead_by()
post = tr(TR.SCHEDULING_DAYS) post = tr.scheduling_days()
elif idx == RADIO_PREVIEW: elif idx == RADIO_PREVIEW:
pre = tr(TR.CUSTOM_STUDY_PREVIEW_NEW_CARDS_ADDED_IN_THE) pre = tr.custom_study_preview_new_cards_added_in_the()
post = tr(TR.SCHEDULING_DAYS) post = tr.scheduling_days()
sval = 1 sval = 1
elif idx == RADIO_CRAM: elif idx == RADIO_CRAM:
pre = tr(TR.CUSTOM_STUDY_SELECT) pre = tr.custom_study_select()
post = tr(TR.CUSTOM_STUDY_CARDS_FROM_THE_DECK) post = tr.custom_study_cards_from_the_deck()
# tit = _("After pressing OK, you can choose which tags to include.") # tit = _("After pressing OK, you can choose which tags to include.")
ok = tr(TR.CUSTOM_STUDY_CHOOSE_TAGS) ok = tr.custom_study_choose_tags()
sval = 100 sval = 100
typeShow = True typeShow = True
sp.setVisible(spShow) sp.setVisible(spShow)
@ -144,10 +144,10 @@ class CustomStudy(QDialog):
elif i == RADIO_CRAM: elif i == RADIO_CRAM:
tags = self._getTags() tags = self._getTags()
# the rest create a filtered deck # the rest create a filtered deck
cur = self.mw.col.decks.byName(tr(TR.CUSTOM_STUDY_CUSTOM_STUDY_SESSION)) cur = self.mw.col.decks.byName(tr.custom_study_custom_study_session())
if cur: if cur:
if not cur["dyn"]: if not cur["dyn"]:
showInfo(tr(TR.CUSTOM_STUDY_MUST_RENAME_DECK)) showInfo(tr.custom_study_must_rename_deck())
QDialog.accept(self) QDialog.accept(self)
return return
else: else:
@ -157,9 +157,7 @@ class CustomStudy(QDialog):
dyn = cur dyn = cur
self.mw.col.decks.select(cur["id"]) self.mw.col.decks.select(cur["id"])
else: else:
did = self.mw.col.decks.new_filtered( did = self.mw.col.decks.new_filtered(tr.custom_study_custom_study_session())
tr(TR.CUSTOM_STUDY_CUSTOM_STUDY_SESSION)
)
dyn = self.mw.col.decks.get(did) dyn = self.mw.col.decks.get(did)
# and then set various options # and then set various options
if i == RADIO_FORGOT: if i == RADIO_FORGOT:
@ -214,7 +212,7 @@ class CustomStudy(QDialog):
# generate cards # generate cards
self.created_custom_study = True self.created_custom_study = True
if not self.mw.col.sched.rebuild_filtered_deck(dyn["id"]): if not self.mw.col.sched.rebuild_filtered_deck(dyn["id"]):
showWarning(tr(TR.CUSTOM_STUDY_NO_CARDS_MATCHED_THE_CRITERIA_YOU)) showWarning(tr.custom_study_no_cards_matched_the_criteria_you())
return return
self.mw.moveToState("overview") self.mw.moveToState("overview")
QDialog.accept(self) QDialog.accept(self)

View File

@ -57,7 +57,7 @@ def add_deck_dialog(
success: PerformOpOptionalSuccessCallback = None, success: PerformOpOptionalSuccessCallback = None,
) -> None: ) -> None:
if name := getOnlyText( if name := getOnlyText(
tr(TR.DECKS_NEW_DECK_NAME), default=default_text, parent=parent tr.decks_new_deck_name(), default=default_text, parent=parent
).strip(): ).strip():
add_deck(mw=mw, name=name, success=success) add_deck(mw=mw, name=name, success=success)

View File

@ -169,9 +169,9 @@ class DeckBrowser:
buf = """ buf = """
<tr><th colspan=5 align=start>%s</th><th class=count>%s</th> <tr><th colspan=5 align=start>%s</th><th class=count>%s</th>
<th class=count>%s</th><th class=optscol></th></tr>""" % ( <th class=count>%s</th><th class=optscol></th></tr>""" % (
tr(TR.DECKS_DECK), tr.decks_deck(),
tr(TR.STATISTICS_DUE_COUNT), tr.statistics_due_count(),
tr(TR.ACTIONS_NEW), tr.actions_new(),
) )
buf += self._topLevelDragRow() buf += self._topLevelDragRow()
@ -250,13 +250,13 @@ class DeckBrowser:
def _showOptions(self, did: str) -> None: def _showOptions(self, did: str) -> None:
m = QMenu(self.mw) m = QMenu(self.mw)
a = m.addAction(tr(TR.ACTIONS_RENAME)) a = m.addAction(tr.actions_rename())
qconnect(a.triggered, lambda b, did=did: self._rename(DeckID(int(did)))) qconnect(a.triggered, lambda b, did=did: self._rename(DeckID(int(did))))
a = m.addAction(tr(TR.ACTIONS_OPTIONS)) a = m.addAction(tr.actions_options())
qconnect(a.triggered, lambda b, did=did: self._options(DeckID(int(did)))) qconnect(a.triggered, lambda b, did=did: self._options(DeckID(int(did))))
a = m.addAction(tr(TR.ACTIONS_EXPORT)) a = m.addAction(tr.actions_export())
qconnect(a.triggered, lambda b, did=did: self._export(DeckID(int(did)))) qconnect(a.triggered, lambda b, did=did: self._export(DeckID(int(did))))
a = m.addAction(tr(TR.ACTIONS_DELETE)) a = m.addAction(tr.actions_delete())
qconnect(a.triggered, lambda b, did=did: self._delete(DeckID(int(did)))) qconnect(a.triggered, lambda b, did=did: self._delete(DeckID(int(did))))
gui_hooks.deck_browser_will_show_options_menu(m, int(did)) gui_hooks.deck_browser_will_show_options_menu(m, int(did))
m.exec_(QCursor.pos()) m.exec_(QCursor.pos())
@ -267,7 +267,7 @@ class DeckBrowser:
def _rename(self, did: DeckID) -> None: def _rename(self, did: DeckID) -> None:
deck = self.mw.col.decks.get(did) deck = self.mw.col.decks.get(did)
current_name = deck["name"] current_name = deck["name"]
new_name = getOnlyText(tr(TR.DECKS_NEW_DECK_NAME), default=current_name) new_name = getOnlyText(tr.decks_new_deck_name(), default=current_name)
if not new_name or new_name == current_name: if not new_name or new_name == current_name:
return return
@ -296,9 +296,9 @@ class DeckBrowser:
###################################################################### ######################################################################
drawLinks = [ drawLinks = [
["", "shared", tr(TR.DECKS_GET_SHARED)], ["", "shared", tr.decks_get_shared()],
["", "create", tr(TR.DECKS_CREATE_DECK)], ["", "create", tr.decks_create_deck()],
["Ctrl+Shift+I", "import", tr(TR.DECKS_IMPORT_FILE)], ["Ctrl+Shift+I", "import", tr.decks_import_file()],
] ]
def _drawButtons(self) -> None: def _drawButtons(self) -> None:
@ -335,17 +335,17 @@ class DeckBrowser:
<center> <center>
<div class=callout> <div class=callout>
<div> <div>
{tr(TR.SCHEDULING_UPDATE_SOON)} {tr.scheduling_update_soon()}
</div> </div>
<div> <div>
<button onclick='pycmd("v2upgrade")'> <button onclick='pycmd("v2upgrade")'>
{tr(TR.SCHEDULING_UPDATE_BUTTON)} {tr.scheduling_update_button()}
</button> </button>
<button onclick='pycmd("v2upgradeinfo")'> <button onclick='pycmd("v2upgradeinfo")'>
{tr(TR.SCHEDULING_UPDATE_MORE_INFO_BUTTON)} {tr.scheduling_update_more_info_button()}
</button> </button>
<button onclick='pycmd("v2upgradelater")'> <button onclick='pycmd("v2upgradelater")'>
{tr(TR.SCHEDULING_UPDATE_LATER_BUTTON)} {tr.scheduling_update_later_button()}
</button> </button>
</div> </div>
</div> </div>
@ -365,5 +365,5 @@ class DeckBrowser:
prefs.scheduling.new_timezone = False prefs.scheduling.new_timezone = False
self.mw.col.set_preferences(prefs) self.mw.col.set_preferences(prefs)
showInfo(tr(TR.SCHEDULING_UPDATE_DONE)) showInfo(tr.scheduling_update_done())
self.refresh() self.refresh()

View File

@ -6,7 +6,7 @@ from typing import Optional
from anki.decks import DEFAULT_DECK_ID, DeckID from anki.decks import DEFAULT_DECK_ID, DeckID
from aqt import AnkiQt from aqt import AnkiQt
from aqt.qt import * from aqt.qt import *
from aqt.utils import TR, HelpPage, shortcut, tr from aqt.utils import HelpPage, shortcut, tr
class DeckChooser(QHBoxLayout): class DeckChooser(QHBoxLayout):
@ -34,14 +34,14 @@ class DeckChooser(QHBoxLayout):
# text label before button? # text label before button?
if show_label: if show_label:
self.deckLabel = QLabel(tr(TR.DECKS_DECK)) self.deckLabel = QLabel(tr.decks_deck())
self.addWidget(self.deckLabel) self.addWidget(self.deckLabel)
# decks box # decks box
self.deck = QPushButton() self.deck = QPushButton()
qconnect(self.deck.clicked, self.choose_deck) qconnect(self.deck.clicked, self.choose_deck)
self.deck.setAutoDefault(False) self.deck.setAutoDefault(False)
self.deck.setToolTip(shortcut(tr(TR.QT_MISC_TARGET_DECK_CTRLANDD))) self.deck.setToolTip(shortcut(tr.qt_misc_target_deck_ctrlandd()))
qconnect( qconnect(
QShortcut(QKeySequence("Ctrl+D"), self._widget).activated, self.choose_deck QShortcut(QKeySequence("Ctrl+D"), self._widget).activated, self.choose_deck
) )
@ -89,8 +89,8 @@ class DeckChooser(QHBoxLayout):
ret = StudyDeck( ret = StudyDeck(
self.mw, self.mw,
current=current, current=current,
accept=tr(TR.ACTIONS_CHOOSE), accept=tr.actions_choose(),
title=tr(TR.QT_MISC_CHOOSE_DECK), title=tr.qt_misc_choose_deck(),
help=HelpPage.EDITING, help=HelpPage.EDITING,
cancel=False, cancel=False,
parent=self._widget, parent=self._widget,

View File

@ -37,7 +37,7 @@ class DeckConf(QDialog):
self.form = aqt.forms.dconf.Ui_Dialog() self.form = aqt.forms.dconf.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
gui_hooks.deck_conf_did_setup_ui_form(self) gui_hooks.deck_conf_did_setup_ui_form(self)
self.mw.checkpoint(tr(TR.ACTIONS_OPTIONS)) self.mw.checkpoint(tr.actions_options())
self.setupCombos() self.setupCombos()
self.setupConfs() self.setupConfs()
self.setWindowModality(Qt.WindowModal) self.setWindowModality(Qt.WindowModal)
@ -94,13 +94,13 @@ class DeckConf(QDialog):
def confOpts(self) -> None: def confOpts(self) -> None:
m = QMenu(self.mw) m = QMenu(self.mw)
a = m.addAction(tr(TR.ACTIONS_ADD)) a = m.addAction(tr.actions_add())
qconnect(a.triggered, self.addGroup) qconnect(a.triggered, self.addGroup)
a = m.addAction(tr(TR.ACTIONS_DELETE)) a = m.addAction(tr.actions_delete())
qconnect(a.triggered, self.remGroup) qconnect(a.triggered, self.remGroup)
a = m.addAction(tr(TR.ACTIONS_RENAME)) a = m.addAction(tr.actions_rename())
qconnect(a.triggered, self.renameGroup) qconnect(a.triggered, self.renameGroup)
a = m.addAction(tr(TR.SCHEDULING_SET_FOR_ALL_SUBDECKS)) a = m.addAction(tr.scheduling_set_for_all_subdecks())
qconnect(a.triggered, self.setChildren) qconnect(a.triggered, self.setChildren)
if not self.childDids: if not self.childDids:
a.setEnabled(False) a.setEnabled(False)
@ -117,13 +117,13 @@ class DeckConf(QDialog):
self.loadConf() self.loadConf()
cnt = len(self.mw.col.decks.didsForConf(conf)) cnt = len(self.mw.col.decks.didsForConf(conf))
if cnt > 1: if cnt > 1:
txt = tr(TR.SCHEDULING_YOUR_CHANGES_WILL_AFFECT_MULTIPLE_DECKS) txt = tr.scheduling_your_changes_will_affect_multiple_decks()
else: else:
txt = "" txt = ""
self.form.count.setText(txt) self.form.count.setText(txt)
def addGroup(self) -> None: def addGroup(self) -> None:
name = getOnlyText(tr(TR.SCHEDULING_NEW_OPTIONS_GROUP_NAME)) name = getOnlyText(tr.scheduling_new_options_group_name())
if not name: if not name:
return return
@ -139,7 +139,7 @@ class DeckConf(QDialog):
def remGroup(self) -> None: def remGroup(self) -> None:
if int(self.conf["id"]) == 1: if int(self.conf["id"]) == 1:
showInfo(tr(TR.SCHEDULING_THE_DEFAULT_CONFIGURATION_CANT_BE_REMOVED), self) showInfo(tr.scheduling_the_default_configuration_cant_be_removed(), self)
else: else:
gui_hooks.deck_conf_will_remove_config(self, self.deck, self.conf) gui_hooks.deck_conf_will_remove_config(self, self.deck, self.conf)
self.mw.col.modSchema(check=True) self.mw.col.modSchema(check=True)
@ -150,7 +150,7 @@ class DeckConf(QDialog):
def renameGroup(self) -> None: def renameGroup(self) -> None:
old = self.conf["name"] old = self.conf["name"]
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=old) name = getOnlyText(tr.actions_new_name(), default=old)
if not name or name == old: if not name or name == old:
return return
@ -274,10 +274,10 @@ class DeckConf(QDialog):
ret.append(i) ret.append(i)
except: except:
# invalid, don't update # invalid, don't update
showWarning(tr(TR.SCHEDULING_STEPS_MUST_BE_NUMBERS)) showWarning(tr.scheduling_steps_must_be_numbers())
return return
if len(ret) < minSize: if len(ret) < minSize:
showWarning(tr(TR.SCHEDULING_AT_LEAST_ONE_STEP_IS_REQUIRED)) showWarning(tr.scheduling_at_least_one_step_is_required())
return return
conf[key] = ret conf[key] = ret

View File

@ -6,7 +6,7 @@ from anki.collection import OpChanges
from anki.errors import NotFoundError from anki.errors import NotFoundError
from aqt import gui_hooks from aqt import gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.utils import TR, disable_help_button, restoreGeom, saveGeom, tr from aqt.utils import disable_help_button, restoreGeom, saveGeom, tr
class EditCurrent(QDialog): class EditCurrent(QDialog):
@ -16,7 +16,7 @@ class EditCurrent(QDialog):
self.mw = mw self.mw = mw
self.form = aqt.forms.editcurrent.Ui_Dialog() self.form = aqt.forms.editcurrent.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
self.setWindowTitle(tr(TR.EDITING_EDIT_CURRENT)) self.setWindowTitle(tr.editing_edit_current())
disable_help_button(self) disable_help_button(self)
self.setMinimumHeight(400) self.setMinimumHeight(400)
self.setMinimumWidth(250) self.setMinimumWidth(250)

View File

@ -143,16 +143,16 @@ class Editor:
self._addButton( self._addButton(
None, None,
"fields", "fields",
tr(TR.EDITING_CUSTOMIZE_FIELDS), tr.editing_customize_fields(),
f"{tr(TR.EDITING_FIELDS)}...", f"{tr.editing_fields()}...",
disables=False, disables=False,
rightside=False, rightside=False,
), ),
self._addButton( self._addButton(
None, None,
"cards", "cards",
tr(TR.EDITING_CUSTOMIZE_CARD_TEMPLATES_CTRLANDL), tr.editing_customize_card_templates_ctrlandl(),
f"{tr(TR.EDITING_CARDS)}...", f"{tr.editing_cards()}...",
disables=False, disables=False,
rightside=False, rightside=False,
), ),
@ -162,36 +162,36 @@ class Editor:
righttopbtns: List[str] = [ righttopbtns: List[str] = [
self._addButton( self._addButton(
"text_bold", "bold", tr(TR.EDITING_BOLD_TEXT_CTRLANDB), id="bold" "text_bold", "bold", tr.editing_bold_text_ctrlandb(), id="bold"
), ),
self._addButton( self._addButton(
"text_italic", "text_italic",
"italic", "italic",
tr(TR.EDITING_ITALIC_TEXT_CTRLANDI), tr.editing_italic_text_ctrlandi(),
id="italic", id="italic",
), ),
self._addButton( self._addButton(
"text_under", "text_under",
"underline", "underline",
tr(TR.EDITING_UNDERLINE_TEXT_CTRLANDU), tr.editing_underline_text_ctrlandu(),
id="underline", id="underline",
), ),
self._addButton( self._addButton(
"text_super", "text_super",
"super", "super",
tr(TR.EDITING_SUPERSCRIPT_CTRLANDAND), tr.editing_superscript_ctrlandand(),
id="superscript", id="superscript",
), ),
self._addButton( self._addButton(
"text_sub", "sub", tr(TR.EDITING_SUBSCRIPT_CTRLAND), id="subscript" "text_sub", "sub", tr.editing_subscript_ctrland(), id="subscript"
), ),
self._addButton( self._addButton(
"text_clear", "clear", tr(TR.EDITING_REMOVE_FORMATTING_CTRLANDR) "text_clear", "clear", tr.editing_remove_formatting_ctrlandr()
), ),
self._addButton( self._addButton(
None, None,
"colour", "colour",
tr(TR.EDITING_SET_FOREGROUND_COLOUR_F7), tr.editing_set_foreground_colour_f7(),
""" """
<span id="forecolor" class="topbut rounded" style="background: #000"></span> <span id="forecolor" class="topbut rounded" style="background: #000"></span>
""", """,
@ -199,18 +199,18 @@ class Editor:
self._addButton( self._addButton(
None, None,
"changeCol", "changeCol",
tr(TR.EDITING_CHANGE_COLOUR_F8), tr.editing_change_colour_f8(),
""" """
<span class="topbut rounded rainbow"></span> <span class="topbut rounded rainbow"></span>
""", """,
), ),
self._addButton( self._addButton(
"text_cloze", "cloze", tr(TR.EDITING_CLOZE_DELETION_CTRLANDSHIFTANDC) "text_cloze", "cloze", tr.editing_cloze_deletion_ctrlandshiftandc()
), ),
self._addButton( self._addButton(
"paperclip", "attach", tr(TR.EDITING_ATTACH_PICTURESAUDIOVIDEO_F3) "paperclip", "attach", tr.editing_attach_picturesaudiovideo_f3()
), ),
self._addButton("media-record", "record", tr(TR.EDITING_RECORD_AUDIO_F5)), self._addButton("media-record", "record", tr.editing_record_audio_f5()),
self._addButton("more", "more"), self._addButton("more", "more"),
] ]
@ -232,7 +232,7 @@ class Editor:
bgcol = self.mw.app.palette().window().color().name() # type: ignore bgcol = self.mw.app.palette().window().color().name() # type: ignore
# then load page # then load page
self.web.stdHtml( self.web.stdHtml(
_html % (bgcol, topbuts, tr(TR.EDITING_SHOW_DUPLICATES)), _html % (bgcol, topbuts, tr.editing_show_duplicates()),
css=[ css=[
"css/vendor/bootstrap.min.css", "css/vendor/bootstrap.min.css",
"css/vendor/bootstrap-icons.css", "css/vendor/bootstrap-icons.css",
@ -696,13 +696,11 @@ class Editor:
tb.setSpacing(12) tb.setSpacing(12)
tb.setContentsMargins(2, 6, 2, 6) tb.setContentsMargins(2, 6, 2, 6)
# tags # tags
l = QLabel(tr(TR.EDITING_TAGS)) l = QLabel(tr.editing_tags())
tb.addWidget(l, 1, 0) tb.addWidget(l, 1, 0)
self.tags = aqt.tagedit.TagEdit(self.widget) self.tags = aqt.tagedit.TagEdit(self.widget)
qconnect(self.tags.lostFocus, self.on_tag_focus_lost) qconnect(self.tags.lostFocus, self.on_tag_focus_lost)
self.tags.setToolTip( self.tags.setToolTip(shortcut(tr.editing_jump_to_tags_with_ctrlandshiftandt()))
shortcut(tr(TR.EDITING_JUMP_TO_TAGS_WITH_CTRLANDSHIFTANDT))
)
border = theme_manager.color(colors.BORDER) border = theme_manager.color(colors.BORDER)
self.tags.setStyleSheet(f"border: 1px solid {border}") self.tags.setStyleSheet(f"border: 1px solid {border}")
tb.addWidget(self.tags, 1, 1) tb.addWidget(self.tags, 1, 1)
@ -768,9 +766,9 @@ class Editor:
# check that the model is set up for cloze deletion # check that the model is set up for cloze deletion
if self.note.model()["type"] != MODEL_CLOZE: if self.note.model()["type"] != MODEL_CLOZE:
if self.addMode: if self.addMode:
tooltip(tr(TR.EDITING_WARNING_CLOZE_DELETIONS_WILL_NOT_WORK)) tooltip(tr.editing_warning_cloze_deletions_will_not_work())
else: else:
showInfo(tr(TR.EDITING_TO_MAKE_A_CLOZE_DELETION_ON)) showInfo(tr.editing_to_make_a_cloze_deletion_on())
return return
# find the highest existing cloze # find the highest existing cloze
highest = 0 highest = 0
@ -828,14 +826,14 @@ class Editor:
extension_filter = " ".join( extension_filter = " ".join(
f"*.{extension}" for extension in sorted(itertools.chain(pics, audio)) f"*.{extension}" for extension in sorted(itertools.chain(pics, audio))
) )
filter = f"{tr(TR.EDITING_MEDIA)} ({extension_filter})" filter = f"{tr.editing_media()} ({extension_filter})"
def accept(file: str) -> None: def accept(file: str) -> None:
self.addMedia(file) self.addMedia(file)
file = getFile( file = getFile(
parent=self.widget, parent=self.widget,
title=tr(TR.EDITING_ADD_MEDIA), title=tr.editing_add_media(),
cb=cast(Callable[[Any], None], accept), cb=cast(Callable[[Any], None], accept),
filter=filter, filter=filter,
key="media", key="media",
@ -1062,17 +1060,17 @@ class Editor:
m = QMenu(self.mw) m = QMenu(self.mw)
for text, handler, shortcut in ( for text, handler, shortcut in (
(tr(TR.EDITING_MATHJAX_INLINE), self.insertMathjaxInline, "Ctrl+M, M"), (tr.editing_mathjax_inline(), self.insertMathjaxInline, "Ctrl+M, M"),
(tr(TR.EDITING_MATHJAX_BLOCK), self.insertMathjaxBlock, "Ctrl+M, E"), (tr.editing_mathjax_block(), self.insertMathjaxBlock, "Ctrl+M, E"),
( (
tr(TR.EDITING_MATHJAX_CHEMISTRY), tr.editing_mathjax_chemistry(),
self.insertMathjaxChemistry, self.insertMathjaxChemistry,
"Ctrl+M, C", "Ctrl+M, C",
), ),
(tr(TR.EDITING_LATEX), self.insertLatex, "Ctrl+T, T"), (tr.editing_latex(), self.insertLatex, "Ctrl+T, T"),
(tr(TR.EDITING_LATEX_EQUATION), self.insertLatexEqn, "Ctrl+T, E"), (tr.editing_latex_equation(), self.insertLatexEqn, "Ctrl+T, E"),
(tr(TR.EDITING_LATEX_MATH_ENV), self.insertLatexMathEnv, "Ctrl+T, M"), (tr.editing_latex_math_env(), self.insertLatexMathEnv, "Ctrl+T, M"),
(tr(TR.EDITING_EDIT_HTML), self.onHtmlEdit, "Ctrl+Shift+X"), (tr.editing_edit_html(), self.onHtmlEdit, "Ctrl+Shift+X"),
): ):
a = m.addAction(text) a = m.addAction(text)
qconnect(a.triggered, handler) qconnect(a.triggered, handler)
@ -1323,11 +1321,11 @@ class EditorWebView(AnkiWebView):
def contextMenuEvent(self, evt: QContextMenuEvent) -> None: def contextMenuEvent(self, evt: QContextMenuEvent) -> None:
m = QMenu(self) m = QMenu(self)
a = m.addAction(tr(TR.EDITING_CUT)) a = m.addAction(tr.editing_cut())
qconnect(a.triggered, self.onCut) qconnect(a.triggered, self.onCut)
a = m.addAction(tr(TR.ACTIONS_COPY)) a = m.addAction(tr.actions_copy())
qconnect(a.triggered, self.onCopy) qconnect(a.triggered, self.onCopy)
a = m.addAction(tr(TR.EDITING_PASTE)) a = m.addAction(tr.editing_paste())
qconnect(a.triggered, self.onPaste) qconnect(a.triggered, self.onPaste)
gui_hooks.editor_will_show_context_menu(self, m) gui_hooks.editor_will_show_context_menu(self, m)
m.popup(QCursor.pos()) m.popup(QCursor.pos())

View File

@ -22,7 +22,7 @@ def show_empty_cards(mw: aqt.main.AnkiQt) -> None:
mw.progress.finish() mw.progress.finish()
report: EmptyCardsReport = fut.result() report: EmptyCardsReport = fut.result()
if not report.notes: if not report.notes:
tooltip(tr(TR.EMPTY_CARDS_NOT_FOUND)) tooltip(tr.empty_cards_not_found())
return return
diag = EmptyCardsDialog(mw, report) diag = EmptyCardsDialog(mw, report)
diag.show() diag.show()
@ -40,9 +40,9 @@ class EmptyCardsDialog(QDialog):
self.form = aqt.forms.emptycards.Ui_Dialog() self.form = aqt.forms.emptycards.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
restoreGeom(self, "emptycards") restoreGeom(self, "emptycards")
self.setWindowTitle(tr(TR.EMPTY_CARDS_WINDOW_TITLE)) self.setWindowTitle(tr.empty_cards_window_title())
disable_help_button(self) disable_help_button(self)
self.form.keep_notes.setText(tr(TR.EMPTY_CARDS_PRESERVE_NOTES_CHECKBOX)) self.form.keep_notes.setText(tr.empty_cards_preserve_notes_checkbox())
self.form.webview.title = "empty cards" self.form.webview.title = "empty cards"
self.form.webview.set_bridge_command(self._on_note_link_clicked, self) self.form.webview.set_bridge_command(self._on_note_link_clicked, self)
@ -63,7 +63,7 @@ class EmptyCardsDialog(QDialog):
qconnect(self.finished, on_finished) qconnect(self.finished, on_finished)
self._delete_button = self.form.buttonBox.addButton( self._delete_button = self.form.buttonBox.addButton(
tr(TR.EMPTY_CARDS_DELETE_BUTTON), QDialogButtonBox.ActionRole tr.empty_cards_delete_button(), QDialogButtonBox.ActionRole
) )
self._delete_button.setAutoDefault(False) self._delete_button.setAutoDefault(False)
self._delete_button.clicked.connect(self._on_delete) self._delete_button.clicked.connect(self._on_delete)

View File

@ -65,7 +65,7 @@ class ErrorHandler(QObject):
self.timer.start() self.timer.start()
def tempFolderMsg(self) -> str: def tempFolderMsg(self) -> str:
return tr(TR.QT_MISC_UNABLE_TO_ACCESS_ANKI_MEDIA_FOLDER) return tr.qt_misc_unable_to_access_anki_media_folder()
def onTimeout(self) -> None: def onTimeout(self) -> None:
error = html.escape(self.pool) error = html.escape(self.pool)
@ -76,10 +76,10 @@ class ErrorHandler(QObject):
if "DeprecationWarning" in error: if "DeprecationWarning" in error:
return return
if "10013" in error: if "10013" in error:
showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS)) showWarning(tr.qt_misc_your_firewall_or_antivirus_program_is())
return return
if "no default input" in error.lower(): if "no default input" in error.lower():
showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE)) showWarning(tr.qt_misc_please_connect_a_microphone_and_ensure())
return return
if "invalidTempFolder" in error: if "invalidTempFolder" in error:
showWarning(self.tempFolderMsg()) showWarning(self.tempFolderMsg())
@ -87,17 +87,17 @@ class ErrorHandler(QObject):
if "Beautiful Soup is not an HTTP client" in error: if "Beautiful Soup is not an HTTP client" in error:
return return
if "database or disk is full" in error or "Errno 28" in error: if "database or disk is full" in error or "Errno 28" in error:
showWarning(tr(TR.QT_MISC_YOUR_COMPUTERS_STORAGE_MAY_BE_FULL)) showWarning(tr.qt_misc_your_computers_storage_may_be_full())
return return
if "disk I/O error" in error: if "disk I/O error" in error:
showWarning(markdown(tr(TR.ERRORS_ACCESSING_DB))) showWarning(markdown(tr.errors_accessing_db()))
return return
if self.mw.addonManager.dirty: if self.mw.addonManager.dirty:
txt = markdown(tr(TR.ERRORS_ADDONS_ACTIVE_POPUP)) txt = markdown(tr.errors_addons_active_popup())
error = f"{supportText() + self._addonText(error)}\n{error}" error = f"{supportText() + self._addonText(error)}\n{error}"
else: else:
txt = markdown(tr(TR.ERRORS_STANDARD_POPUP)) txt = markdown(tr.errors_standard_popup())
error = f"{supportText()}\n{error}" error = f"{supportText()}\n{error}"
# show dialog # show dialog

View File

@ -59,13 +59,13 @@ class ExportDialog(QDialog):
self.exporterChanged(idx) self.exporterChanged(idx)
# deck list # deck list
if self.cids is None: if self.cids is None:
self.decks = [tr(TR.EXPORTING_ALL_DECKS)] self.decks = [tr.exporting_all_decks()]
self.decks.extend(d.name for d in self.col.decks.all_names_and_ids()) self.decks.extend(d.name for d in self.col.decks.all_names_and_ids())
else: else:
self.decks = [tr(TR.EXPORTING_SELECTED_NOTES)] self.decks = [tr.exporting_selected_notes()]
self.frm.deck.addItems(self.decks) self.frm.deck.addItems(self.decks)
# save button # save button
b = QPushButton(tr(TR.EXPORTING_EXPORT)) b = QPushButton(tr.exporting_export())
self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole) self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole)
# set default option if accessed through deck button # set default option if accessed through deck button
if did: if did:
@ -117,7 +117,7 @@ class ExportDialog(QDialog):
self.exporter.did = self.col.decks.id(name) self.exporter.did = self.col.decks.id(name)
if self.isVerbatim: if self.isVerbatim:
name = time.strftime("-%Y-%m-%d@%H-%M-%S", time.localtime(time.time())) name = time.strftime("-%Y-%m-%d@%H-%M-%S", time.localtime(time.time()))
deck_name = tr(TR.EXPORTING_COLLECTION) + name deck_name = tr.exporting_collection() + name
else: else:
# Get deck name and remove invalid filename characters # Get deck name and remove invalid filename characters
deck_name = self.decks[self.frm.deck.currentIndex()] deck_name = self.decks[self.frm.deck.currentIndex()]
@ -131,7 +131,7 @@ class ExportDialog(QDialog):
while 1: while 1:
file = getSaveFile( file = getSaveFile(
self, self,
tr(TR.ACTIONS_EXPORT), tr.actions_export(),
"export", "export",
key_str, key_str,
self.exporter.ext, self.exporter.ext,
@ -181,7 +181,7 @@ class ExportDialog(QDialog):
def on_export_finished(self) -> None: def on_export_finished(self) -> None:
if self.isVerbatim: if self.isVerbatim:
msg = tr(TR.EXPORTING_COLLECTION_EXPORTED) msg = tr.exporting_collection_exported()
self.mw.reopen() self.mw.reopen()
else: else:
if self.isTextNote: if self.isTextNote:

View File

@ -34,7 +34,7 @@ class FieldDialog(QDialog):
self.mm = self.mw.col.models self.mm = self.mw.col.models
self.model = nt self.model = nt
self.mm._remove_from_cache(self.model["id"]) self.mm._remove_from_cache(self.model["id"])
self.mw.checkpoint(tr(TR.EDITING_FIELDS)) self.mw.checkpoint(tr.editing_fields())
self.change_tracker = ChangeTracker(self.mw) self.change_tracker = ChangeTracker(self.mw)
self.form = aqt.forms.fields.Ui_Dialog() self.form = aqt.forms.fields.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
@ -103,24 +103,24 @@ class FieldDialog(QDialog):
if not txt: if not txt:
return None return None
if txt[0] in "#^/": if txt[0] in "#^/":
showWarning(tr(TR.FIELDS_NAME_FIRST_LETTER_NOT_VALID)) showWarning(tr.fields_name_first_letter_not_valid())
return None return None
for letter in """:{"}""": for letter in """:{"}""":
if letter in txt: if letter in txt:
showWarning(tr(TR.FIELDS_NAME_INVALID_LETTER)) showWarning(tr.fields_name_invalid_letter())
return None return None
for f in self.model["flds"]: for f in self.model["flds"]:
if ignoreOrd is not None and f["ord"] == ignoreOrd: if ignoreOrd is not None and f["ord"] == ignoreOrd:
continue continue
if f["name"] == txt: if f["name"] == txt:
showWarning(tr(TR.FIELDS_THAT_FIELD_NAME_IS_ALREADY_USED)) showWarning(tr.fields_that_field_name_is_already_used())
return None return None
return txt return txt
def onRename(self) -> None: def onRename(self) -> None:
idx = self.currentIdx idx = self.currentIdx
f = self.model["flds"][idx] f = self.model["flds"][idx]
name = self._uniqueName(tr(TR.ACTIONS_NEW_NAME), self.currentIdx, f["name"]) name = self._uniqueName(tr.actions_new_name(), self.currentIdx, f["name"])
if not name: if not name:
return return
@ -134,7 +134,7 @@ class FieldDialog(QDialog):
self.form.fieldList.setCurrentRow(idx) self.form.fieldList.setCurrentRow(idx)
def onAdd(self) -> None: def onAdd(self) -> None:
name = self._uniqueName(tr(TR.FIELDS_FIELD_NAME)) name = self._uniqueName(tr.fields_field_name())
if not name: if not name:
return return
if not self.change_tracker.mark_schema(): if not self.change_tracker.mark_schema():
@ -147,7 +147,7 @@ class FieldDialog(QDialog):
def onDelete(self) -> None: def onDelete(self) -> None:
if len(self.model["flds"]) < 2: if len(self.model["flds"]) < 2:
showWarning(tr(TR.FIELDS_NOTES_REQUIRE_AT_LEAST_ONE_FIELD)) showWarning(tr.fields_notes_require_at_least_one_field())
return return
count = self.mm.useCount(self.model) count = self.mm.useCount(self.model)
c = tr(TR.BROWSING_NOTE_COUNT, count=count) c = tr(TR.BROWSING_NOTE_COUNT, count=count)

View File

@ -115,9 +115,9 @@ class FilteredDeckConfigDialog(QDialog):
existing = deck.id != 0 existing = deck.id != 0
if existing: if existing:
build_label = tr(TR.ACTIONS_REBUILD) build_label = tr.actions_rebuild()
else: else:
build_label = tr(TR.DECKS_BUILD) build_label = tr.decks_build()
self.form.buttonBox.button(QDialogButtonBox.Ok).setText(build_label) self.form.buttonBox.button(QDialogButtonBox.Ok).setText(build_label)
form.resched.setChecked(config.reschedule) form.resched.setChecked(config.reschedule)
@ -334,9 +334,9 @@ class FilteredDeckConfigDialog(QDialog):
ret.append(i) ret.append(i)
except: except:
# invalid, don't update # invalid, don't update
showWarning(tr(TR.SCHEDULING_STEPS_MUST_BE_NUMBERS)) showWarning(tr.scheduling_steps_must_be_numbers())
return None return None
if len(ret) < minSize: if len(ret) < minSize:
showWarning(tr(TR.SCHEDULING_AT_LEAST_ONE_STEP_IS_REQUIRED)) showWarning(tr.scheduling_at_least_one_step_is_required())
return None return None
return ret return ret

View File

@ -100,8 +100,8 @@ class FindAndReplaceDialog(QDialog):
def _show(self, field_names: Sequence[str]) -> None: def _show(self, field_names: Sequence[str]) -> None:
# add "all fields" and "tags" to the top of the list # add "all fields" and "tags" to the top of the list
self.field_names = [ self.field_names = [
tr(TR.BROWSING_ALL_FIELDS), tr.browsing_all_fields(),
tr(TR.EDITING_TAGS), tr.editing_tags(),
] + list(field_names) ] + list(field_names)
disable_help_button(self) disable_help_button(self)

View File

@ -50,8 +50,8 @@ class ChangeMap(QDialog):
setCurrent = True setCurrent = True
self.frm.fields.setCurrentRow(n) self.frm.fields.setCurrentRow(n)
n += 1 n += 1
self.frm.fields.addItem(QListWidgetItem(tr(TR.IMPORTING_MAP_TO_TAGS))) self.frm.fields.addItem(QListWidgetItem(tr.importing_map_to_tags()))
self.frm.fields.addItem(QListWidgetItem(tr(TR.IMPORTING_IGNORE_FIELD))) self.frm.fields.addItem(QListWidgetItem(tr.importing_ignore_field()))
if not setCurrent: if not setCurrent:
if current == "_tags": if current == "_tags":
self.frm.fields.setCurrentRow(n) self.frm.fields.setCurrentRow(n)
@ -107,7 +107,7 @@ class ImportDialog(QDialog):
self.frm.tagModified.setText(self.mw.pm.profile.get("tagModified", "")) self.frm.tagModified.setText(self.mw.pm.profile.get("tagModified", ""))
self.frm.tagModified.setCol(self.mw.col) self.frm.tagModified.setCol(self.mw.col)
# import button # import button
b = QPushButton(tr(TR.ACTIONS_IMPORT)) b = QPushButton(tr.actions_import())
self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole) self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole)
self.exec_() self.exec_()
@ -128,7 +128,7 @@ class ImportDialog(QDialog):
# Open a modal dialog to enter an delimiter # Open a modal dialog to enter an delimiter
# Todo/Idea Constrain the maximum width, so it doesnt take up that much screen space # Todo/Idea Constrain the maximum width, so it doesnt take up that much screen space
delim, ok = getText( delim, ok = getText(
tr(TR.IMPORTING_BY_DEFAULT_ANKI_WILL_DETECT_THE), tr.importing_by_default_anki_will_detect_the(),
self, self,
help=HelpPage.IMPORTING, help=HelpPage.IMPORTING,
) )
@ -142,7 +142,7 @@ class ImportDialog(QDialog):
delim = delim.replace("\\t", "\t") # un-escape it delim = delim.replace("\\t", "\t") # un-escape it
if len(delim) > 1: if len(delim) > 1:
showWarning( showWarning(
tr(TR.IMPORTING_MULTICHARACTER_SEPARATORS_ARE_NOT_SUPPORTED_PLEASE) tr.importing_multicharacter_separators_are_not_supported_please()
) )
return return
self.hideMapping() self.hideMapping()
@ -166,15 +166,15 @@ class ImportDialog(QDialog):
else: else:
d = self.importer.dialect.delimiter d = self.importer.dialect.delimiter
if d == "\t": if d == "\t":
d = tr(TR.IMPORTING_TAB) d = tr.importing_tab()
elif d == ",": elif d == ",":
d = tr(TR.IMPORTING_COMMA) d = tr.importing_comma()
elif d == " ": elif d == " ":
d = tr(TR.STUDYING_SPACE) d = tr.studying_space()
elif d == ";": elif d == ";":
d = tr(TR.IMPORTING_SEMICOLON) d = tr.importing_semicolon()
elif d == ":": elif d == ":":
d = tr(TR.IMPORTING_COLON) d = tr.importing_colon()
else: else:
d = repr(d) d = repr(d)
txt = tr(TR.IMPORTING_FIELDS_SEPARATED_BY, val=d) txt = tr(TR.IMPORTING_FIELDS_SEPARATED_BY, val=d)
@ -183,7 +183,7 @@ class ImportDialog(QDialog):
def accept(self) -> None: def accept(self) -> None:
self.importer.mapping = self.mapping self.importer.mapping = self.mapping
if not self.importer.mappingOk(): if not self.importer.mappingOk():
showWarning(tr(TR.IMPORTING_THE_FIRST_FIELD_OF_THE_NOTE)) showWarning(tr.importing_the_first_field_of_the_note())
return return
self.importer.importMode = self.frm.importMode.currentIndex() self.importer.importMode = self.frm.importMode.currentIndex()
self.mw.pm.profile["importMode"] = self.importer.importMode self.mw.pm.profile["importMode"] = self.importer.importMode
@ -196,7 +196,7 @@ class ImportDialog(QDialog):
self.mw.col.models.save(self.importer.model, updateReqs=False) self.mw.col.models.save(self.importer.model, updateReqs=False)
self.mw.col.decks.select(did) self.mw.col.decks.select(did)
self.mw.progress.start() self.mw.progress.start()
self.mw.checkpoint(tr(TR.ACTIONS_IMPORT)) self.mw.checkpoint(tr.actions_import())
def on_done(future: Future) -> None: def on_done(future: Future) -> None:
self.mw.progress.finish() self.mw.progress.finish()
@ -207,7 +207,7 @@ class ImportDialog(QDialog):
showUnicodeWarning() showUnicodeWarning()
return return
except Exception as e: except Exception as e:
msg = f"{tr(TR.IMPORTING_FAILED_DEBUG_INFO)}\n" msg = f"{tr.importing_failed_debug_info()}\n"
err = repr(str(e)) err = repr(str(e))
if "1-character string" in err: if "1-character string" in err:
msg += err msg += err
@ -218,7 +218,7 @@ class ImportDialog(QDialog):
showText(msg) showText(msg)
return return
else: else:
txt = f"{tr(TR.IMPORTING_IMPORTING_COMPLETE)}\n" txt = f"{tr.importing_importing_complete()}\n"
if self.importer.log: if self.importer.log:
txt += "\n".join(self.importer.log) txt += "\n".join(self.importer.log)
self.close() self.close()
@ -263,13 +263,13 @@ class ImportDialog(QDialog):
text = tr(TR.IMPORTING_FIELD_OF_FILE_IS, val=num + 1) text = tr(TR.IMPORTING_FIELD_OF_FILE_IS, val=num + 1)
self.grid.addWidget(QLabel(text), num, 0) self.grid.addWidget(QLabel(text), num, 0)
if self.mapping[num] == "_tags": if self.mapping[num] == "_tags":
text = tr(TR.IMPORTING_MAPPED_TO_TAGS) text = tr.importing_mapped_to_tags()
elif self.mapping[num]: elif self.mapping[num]:
text = tr(TR.IMPORTING_MAPPED_TO, val=self.mapping[num]) text = tr(TR.IMPORTING_MAPPED_TO, val=self.mapping[num])
else: else:
text = tr(TR.IMPORTING_IGNORED) text = tr.importing_ignored()
self.grid.addWidget(QLabel(text), num, 1) self.grid.addWidget(QLabel(text), num, 1)
button = QPushButton(tr(TR.IMPORTING_CHANGE)) button = QPushButton(tr.importing_change())
self.grid.addWidget(button, num, 2) self.grid.addWidget(button, num, 2)
qconnect(button.clicked, lambda _, s=self, n=num: s.changeMappingNum(n)) qconnect(button.clicked, lambda _, s=self, n=num: s.changeMappingNum(n))
@ -310,12 +310,12 @@ class ImportDialog(QDialog):
def showUnicodeWarning() -> None: def showUnicodeWarning() -> None:
"""Shorthand to show a standard warning.""" """Shorthand to show a standard warning."""
showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8)) showWarning(tr.importing_selected_file_was_not_in_utf8())
def onImport(mw: AnkiQt) -> None: def onImport(mw: AnkiQt) -> None:
filt = ";;".join([x[0] for x in importing.importers(mw.col)]) filt = ";;".join([x[0] for x in importing.importers(mw.col)])
file = getFile(mw, tr(TR.ACTIONS_IMPORT), None, key="import", filter=filt) file = getFile(mw, tr.actions_import(), None, key="import", filter=filt)
if not file: if not file:
return return
file = str(file) file = str(file)
@ -323,10 +323,10 @@ def onImport(mw: AnkiQt) -> None:
head, ext = os.path.splitext(file) head, ext = os.path.splitext(file)
ext = ext.lower() ext = ext.lower()
if ext == ".anki": if ext == ".anki":
showInfo(tr(TR.IMPORTING_ANKI_FILES_ARE_FROM_A_VERY)) showInfo(tr.importing_anki_files_are_from_a_very())
return return
elif ext == ".anki2": elif ext == ".anki2":
showInfo(tr(TR.IMPORTING_ANKI2_FILES_ARE_NOT_DIRECTLY_IMPORTABLE)) showInfo(tr.importing_anki2_files_are_not_directly_importable())
return return
importFile(mw, file) importFile(mw, file)
@ -363,9 +363,9 @@ def importFile(mw: AnkiQt, file: str) -> None:
mw.progress.finish() mw.progress.finish()
msg = repr(str(e)) msg = repr(str(e))
if msg == "'unknownFormat'": if msg == "'unknownFormat'":
showWarning(tr(TR.IMPORTING_UNKNOWN_FILE_FORMAT)) showWarning(tr.importing_unknown_file_format())
else: else:
msg = f"{tr(TR.IMPORTING_FAILED_DEBUG_INFO)}\n" msg = f"{tr.importing_failed_debug_info()}\n"
msg += str(traceback.format_exc()) msg += str(traceback.format_exc())
showText(msg) showText(msg)
return return
@ -398,14 +398,14 @@ def importFile(mw: AnkiQt, file: str) -> None:
except Exception as e: except Exception as e:
err = repr(str(e)) err = repr(str(e))
if "invalidFile" in err: if "invalidFile" in err:
msg = tr(TR.IMPORTING_INVALID_FILE_PLEASE_RESTORE_FROM_BACKUP) msg = tr.importing_invalid_file_please_restore_from_backup()
showWarning(msg) showWarning(msg)
elif "invalidTempFolder" in err: elif "invalidTempFolder" in err:
showWarning(mw.errorHandler.tempFolderMsg()) showWarning(mw.errorHandler.tempFolderMsg())
elif "readonly" in err: elif "readonly" in err:
showWarning(tr(TR.IMPORTING_UNABLE_TO_IMPORT_FROM_A_READONLY)) showWarning(tr.importing_unable_to_import_from_a_readonly())
else: else:
msg = f"{tr(TR.IMPORTING_FAILED_DEBUG_INFO)}\n" msg = f"{tr.importing_failed_debug_info()}\n"
msg += str(traceback.format_exc()) msg += str(traceback.format_exc())
showText(msg) showText(msg)
else: else:
@ -421,7 +421,7 @@ def importFile(mw: AnkiQt, file: str) -> None:
def invalidZipMsg() -> str: def invalidZipMsg() -> str:
return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO) return tr.importing_this_file_does_not_appear_to()
def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool: def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool:
@ -435,7 +435,7 @@ def setupApkgImport(mw: AnkiQt, importer: AnkiPackageImporter) -> bool:
# adding # adding
return True return True
if not mw.restoringBackup and not askUser( if not mw.restoringBackup and not askUser(
tr(TR.IMPORTING_THIS_WILL_DELETE_YOUR_EXISTING_COLLECTION), tr.importing_this_will_delete_your_existing_collection(),
msgfunc=QMessageBox.warning, msgfunc=QMessageBox.warning,
defaultno=True, defaultno=True,
): ):
@ -494,7 +494,7 @@ def _replaceWithApkg(mw: aqt.AnkiQt, filename: str, backup: bool) -> None:
future.result() future.result()
except Exception as e: except Exception as e:
print(e) print(e)
showWarning(tr(TR.IMPORTING_THE_PROVIDED_FILE_IS_NOT_A)) showWarning(tr.importing_the_provided_file_is_not_a())
return return
if not mw.loadCollection(): if not mw.loadCollection():
@ -502,6 +502,6 @@ def _replaceWithApkg(mw: aqt.AnkiQt, filename: str, backup: bool) -> None:
if backup: if backup:
mw.col.modSchema(check=False) mw.col.modSchema(check=False)
tooltip(tr(TR.IMPORTING_IMPORTING_COMPLETE)) tooltip(tr.importing_importing_complete())
mw.taskman.run_in_background(do_import, on_done) mw.taskman.run_in_background(do_import, on_done)

View File

@ -155,7 +155,7 @@ class AnkiQt(QMainWindow):
sys.exit(1) sys.exit(1)
# must call this after ui set up # must call this after ui set up
if self.safeMode: if self.safeMode:
tooltip(tr(TR.QT_MISC_SHIFT_KEY_WAS_HELD_DOWN_SKIPPING)) tooltip(tr.qt_misc_shift_key_was_held_down_skipping())
# were we given a file to import? # were we given a file to import?
if args and args[0] and not self._isAddon(args[0]): if args and args[0] and not self._isAddon(args[0]):
self.onAppMsg(args[0]) self.onAppMsg(args[0])
@ -282,7 +282,7 @@ class AnkiQt(QMainWindow):
qconnect(f.profiles.currentRowChanged, self.onProfileRowChange) qconnect(f.profiles.currentRowChanged, self.onProfileRowChange)
f.statusbar.setVisible(False) f.statusbar.setVisible(False)
qconnect(f.downgrade_button.clicked, self._on_downgrade) qconnect(f.downgrade_button.clicked, self._on_downgrade)
f.downgrade_button.setText(tr(TR.PROFILES_DOWNGRADE_AND_QUIT)) f.downgrade_button.setText(tr.profiles_downgrade_and_quit())
# enter key opens profile # enter key opens profile
QShortcut(QKeySequence("Return"), d, activated=self.onOpenProfile) # type: ignore QShortcut(QKeySequence("Return"), d, activated=self.onOpenProfile) # type: ignore
self.refreshProfilesList() self.refreshProfilesList()
@ -324,10 +324,10 @@ class AnkiQt(QMainWindow):
return not checkInvalidFilename(name) and name != "addons21" return not checkInvalidFilename(name) and name != "addons21"
def onAddProfile(self) -> None: def onAddProfile(self) -> None:
name = getOnlyText(tr(TR.ACTIONS_NAME)).strip() name = getOnlyText(tr.actions_name()).strip()
if name: if name:
if name in self.pm.profiles(): if name in self.pm.profiles():
showWarning(tr(TR.QT_MISC_NAME_EXISTS)) showWarning(tr.qt_misc_name_exists())
return return
if not self.profileNameOk(name): if not self.profileNameOk(name):
return return
@ -336,13 +336,13 @@ class AnkiQt(QMainWindow):
self.refreshProfilesList() self.refreshProfilesList()
def onRenameProfile(self) -> None: def onRenameProfile(self) -> None:
name = getOnlyText(tr(TR.ACTIONS_NEW_NAME), default=self.pm.name).strip() name = getOnlyText(tr.actions_new_name(), default=self.pm.name).strip()
if not name: if not name:
return return
if name == self.pm.name: if name == self.pm.name:
return return
if name in self.pm.profiles(): if name in self.pm.profiles():
showWarning(tr(TR.QT_MISC_NAME_EXISTS)) showWarning(tr.qt_misc_name_exists())
return return
if not self.profileNameOk(name): if not self.profileNameOk(name):
return return
@ -352,11 +352,11 @@ class AnkiQt(QMainWindow):
def onRemProfile(self) -> None: def onRemProfile(self) -> None:
profs = self.pm.profiles() profs = self.pm.profiles()
if len(profs) < 2: if len(profs) < 2:
showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE)) showWarning(tr.qt_misc_there_must_be_at_least_one())
return return
# sure? # sure?
if not askUser( if not askUser(
tr(TR.QT_MISC_ALL_CARDS_NOTES_AND_MEDIA_FOR), tr.qt_misc_all_cards_notes_and_media_for(),
msgfunc=QMessageBox.warning, msgfunc=QMessageBox.warning,
defaultno=True, defaultno=True,
): ):
@ -366,7 +366,7 @@ class AnkiQt(QMainWindow):
def onOpenBackup(self) -> None: def onOpenBackup(self) -> None:
if not askUser( if not askUser(
tr(TR.QT_MISC_REPLACE_YOUR_COLLECTION_WITH_AN_EARLIER), tr.qt_misc_replace_your_collection_with_an_earlier(),
msgfunc=QMessageBox.warning, msgfunc=QMessageBox.warning,
defaultno=True, defaultno=True,
): ):
@ -377,7 +377,7 @@ class AnkiQt(QMainWindow):
getFile( getFile(
self.profileDiag, self.profileDiag,
tr(TR.QT_MISC_REVERT_TO_BACKUP), tr.qt_misc_revert_to_backup(),
cb=doOpen, # type: ignore cb=doOpen, # type: ignore
filter="*.colpkg", filter="*.colpkg",
dir=self.pm.backupFolder(), dir=self.pm.backupFolder(),
@ -388,13 +388,13 @@ class AnkiQt(QMainWindow):
# move the existing collection to the trash, as it may not open # move the existing collection to the trash, as it may not open
self.pm.trashCollection() self.pm.trashCollection()
except: except:
showWarning(tr(TR.QT_MISC_UNABLE_TO_MOVE_EXISTING_FILE_TO)) showWarning(tr.qt_misc_unable_to_move_existing_file_to())
return return
self.pendingImport = path self.pendingImport = path
self.restoringBackup = True self.restoringBackup = True
showInfo(tr(TR.QT_MISC_AUTOMATIC_SYNCING_AND_BACKUPS_HAVE_BEEN)) showInfo(tr.qt_misc_automatic_syncing_and_backups_have_been())
self.onOpenProfile() self.onOpenProfile()
@ -522,7 +522,7 @@ class AnkiQt(QMainWindow):
) )
else: else:
showWarning( showWarning(
f"{tr(TR.ERRORS_UNABLE_OPEN_COLLECTION)}\n{traceback.format_exc()}" f"{tr.errors_unable_open_collection()}\n{traceback.format_exc()}"
) )
# clean up open collection if possible # clean up open collection if possible
try: try:
@ -574,9 +574,9 @@ class AnkiQt(QMainWindow):
if not self.col: if not self.col:
return return
if self.restoringBackup: if self.restoringBackup:
label = tr(TR.QT_MISC_CLOSING) label = tr.qt_misc_closing()
else: else:
label = tr(TR.QT_MISC_BACKING_UP) label = tr.qt_misc_backing_up()
self.progress.start(label=label) self.progress.start(label=label)
corrupt = False corrupt = False
try: try:
@ -594,7 +594,7 @@ class AnkiQt(QMainWindow):
self.col = None self.col = None
self.progress.finish() self.progress.finish()
if corrupt: if corrupt:
showWarning(tr(TR.QT_MISC_YOUR_COLLECTION_FILE_APPEARS_TO_BE)) showWarning(tr.qt_misc_your_collection_file_appears_to_be())
if not corrupt and not self.restoringBackup: if not corrupt and not self.restoringBackup:
self.backup() self.backup()
@ -671,7 +671,7 @@ class AnkiQt(QMainWindow):
# have two weeks passed? # have two weeks passed?
if (intTime() - self.pm.profile["lastOptimize"]) < 86400 * 14: if (intTime() - self.pm.profile["lastOptimize"]) < 86400 * 14:
return return
self.progress.start(label=tr(TR.QT_MISC_OPTIMIZING)) self.progress.start(label=tr.qt_misc_optimizing())
self.col.optimize() self.col.optimize()
self.pm.profile["lastOptimize"] = intTime() self.pm.profile["lastOptimize"] = intTime()
self.pm.save() self.pm.save()
@ -702,7 +702,7 @@ class AnkiQt(QMainWindow):
def _selectedDeck(self) -> Optional[DeckDict]: def _selectedDeck(self) -> Optional[DeckDict]:
did = self.col.decks.selected() did = self.col.decks.selected()
if not self.col.decks.name_if_exists(did): if not self.col.decks.name_if_exists(did):
showInfo(tr(TR.QT_MISC_PLEASE_SELECT_A_DECK)) showInfo(tr.qt_misc_please_select_a_deck())
return None return None
return self.col.decks.get(did) return self.col.decks.get(did)
@ -1222,7 +1222,7 @@ title="%s" %s>%s</button>""" % (
return return
elif isinstance(result, ReviewUndo): elif isinstance(result, ReviewUndo):
name = tr(TR.SCHEDULING_REVIEW) name = tr.scheduling_review()
if reviewing: if reviewing:
# push the undone card to the top of the queue # push the undone card to the top of the queue
@ -1279,7 +1279,7 @@ title="%s" %s>%s</button>""" % (
self.form.actionUndo.setEnabled(True) self.form.actionUndo.setEnabled(True)
gui_hooks.undo_state_did_change(True) gui_hooks.undo_state_did_change(True)
else: else:
self.form.actionUndo.setText(tr(TR.UNDO_UNDO)) self.form.actionUndo.setText(tr.undo_undo())
self.form.actionUndo.setEnabled(False) self.form.actionUndo.setEnabled(False)
gui_hooks.undo_state_did_change(False) gui_hooks.undo_state_did_change(False)
@ -1294,7 +1294,7 @@ title="%s" %s>%s</button>""" % (
self.form.actionUndo.setEnabled(True) self.form.actionUndo.setEnabled(True)
gui_hooks.undo_state_did_change(True) gui_hooks.undo_state_did_change(True)
else: else:
self.form.actionUndo.setText(tr(TR.UNDO_UNDO)) self.form.actionUndo.setText(tr.undo_undo())
self.form.actionUndo.setEnabled(False) self.form.actionUndo.setEnabled(False)
gui_hooks.undo_state_did_change(False) gui_hooks.undo_state_did_change(False)
@ -1371,7 +1371,7 @@ title="%s" %s>%s</button>""" % (
import aqt.importing import aqt.importing
if not os.path.exists(path): if not os.path.exists(path):
showInfo(tr(TR.QT_MISC_PLEASE_USE_FILEIMPORT_TO_IMPORT_THIS)) showInfo(tr.qt_misc_please_use_fileimport_to_import_this())
return None return None
aqt.importing.importFile(self, path) aqt.importing.importFile(self, path)
@ -1508,7 +1508,7 @@ title="%s" %s>%s</button>""" % (
self._activeWindowOnPlay: Optional[QWidget] = None self._activeWindowOnPlay: Optional[QWidget] = None
def onOdueInvalid(self) -> None: def onOdueInvalid(self) -> None:
showWarning(tr(TR.QT_MISC_INVALID_PROPERTY_FOUND_ON_CARD_PLEASE)) showWarning(tr.qt_misc_invalid_property_found_on_card_please())
def _isVideo(self, tag: AVTag) -> bool: def _isVideo(self, tag: AVTag) -> bool:
if isinstance(tag, SoundOrVideoTag): if isinstance(tag, SoundOrVideoTag):
@ -1557,7 +1557,7 @@ title="%s" %s>%s</button>""" % (
progress_shown = self.progress.busy() progress_shown = self.progress.busy()
if progress_shown: if progress_shown:
self.progress.finish() self.progress.finish()
ret = askUser(tr(TR.QT_MISC_THE_REQUESTED_CHANGE_WILL_REQUIRE_A)) ret = askUser(tr.qt_misc_the_requested_change_will_require_a())
if progress_shown: if progress_shown:
self.progress.start() self.progress.start()
return ret return ret
@ -1568,7 +1568,7 @@ title="%s" %s>%s</button>""" % (
True if confirmed or already modified.""" True if confirmed or already modified."""
if self.col.schemaChanged(): if self.col.schemaChanged():
return True return True
return askUser(tr(TR.QT_MISC_THE_REQUESTED_CHANGE_WILL_REQUIRE_A)) return askUser(tr.qt_misc_the_requested_change_will_require_a())
# Advanced features # Advanced features
########################################################################## ##########################################################################
@ -1739,7 +1739,7 @@ title="%s" %s>%s</button>""" % (
) )
frm.log.appendPlainText(to_append) frm.log.appendPlainText(to_append)
except UnicodeDecodeError: except UnicodeDecodeError:
to_append = tr(TR.QT_MISC_NON_UNICODE_TEXT) to_append = tr.qt_misc_non_unicode_text()
to_append = gui_hooks.debug_console_did_evaluate_python( to_append = gui_hooks.debug_console_did_evaluate_python(
to_append, text, frm to_append, text, frm
) )
@ -1804,16 +1804,16 @@ title="%s" %s>%s</button>""" % (
return None return None
self.pendingImport = buf self.pendingImport = buf
if is_addon: if is_addon:
msg = tr(TR.QT_MISC_ADDON_WILL_BE_INSTALLED_WHEN_A) msg = tr.qt_misc_addon_will_be_installed_when_a()
else: else:
msg = tr(TR.QT_MISC_DECK_WILL_BE_IMPORTED_WHEN_A) msg = tr.qt_misc_deck_will_be_imported_when_a()
tooltip(msg) tooltip(msg)
return return
if not self.interactiveState() or self.progress.busy(): if not self.interactiveState() or self.progress.busy():
# we can't raise the main window while in profile dialog, syncing, etc # we can't raise the main window while in profile dialog, syncing, etc
if buf != "raise": if buf != "raise":
showInfo( showInfo(
tr(TR.QT_MISC_PLEASE_ENSURE_A_PROFILE_IS_OPEN), tr.qt_misc_please_ensure_a_profile_is_open(),
parent=None, parent=None,
) )
return None return None

View File

@ -99,7 +99,7 @@ class MediaChecker:
# show report and offer to delete # show report and offer to delete
diag = QDialog(self.mw) diag = QDialog(self.mw)
diag.setWindowTitle(tr(TR.MEDIA_CHECK_WINDOW_TITLE)) diag.setWindowTitle(tr.media_check_window_title())
disable_help_button(diag) disable_help_button(diag)
layout = QVBoxLayout(diag) layout = QVBoxLayout(diag)
diag.setLayout(layout) diag.setLayout(layout)
@ -112,25 +112,25 @@ class MediaChecker:
layout.addWidget(box) layout.addWidget(box)
if output.unused: if output.unused:
b = QPushButton(tr(TR.MEDIA_CHECK_DELETE_UNUSED)) b = QPushButton(tr.media_check_delete_unused())
b.setAutoDefault(False) b.setAutoDefault(False)
box.addButton(b, QDialogButtonBox.RejectRole) box.addButton(b, QDialogButtonBox.RejectRole)
qconnect(b.clicked, lambda c: self._on_trash_files(output.unused)) qconnect(b.clicked, lambda c: self._on_trash_files(output.unused))
if output.missing: if output.missing:
if any(map(lambda x: x.startswith("latex-"), output.missing)): if any(map(lambda x: x.startswith("latex-"), output.missing)):
b = QPushButton(tr(TR.MEDIA_CHECK_RENDER_LATEX)) b = QPushButton(tr.media_check_render_latex())
b.setAutoDefault(False) b.setAutoDefault(False)
box.addButton(b, QDialogButtonBox.RejectRole) box.addButton(b, QDialogButtonBox.RejectRole)
qconnect(b.clicked, self._on_render_latex) qconnect(b.clicked, self._on_render_latex)
if output.have_trash: if output.have_trash:
b = QPushButton(tr(TR.MEDIA_CHECK_EMPTY_TRASH)) b = QPushButton(tr.media_check_empty_trash())
b.setAutoDefault(False) b.setAutoDefault(False)
box.addButton(b, QDialogButtonBox.RejectRole) box.addButton(b, QDialogButtonBox.RejectRole)
qconnect(b.clicked, lambda c: self._on_empty_trash()) qconnect(b.clicked, lambda c: self._on_empty_trash())
b = QPushButton(tr(TR.MEDIA_CHECK_RESTORE_TRASH)) b = QPushButton(tr.media_check_restore_trash())
b.setAutoDefault(False) b.setAutoDefault(False)
box.addButton(b, QDialogButtonBox.RejectRole) box.addButton(b, QDialogButtonBox.RejectRole)
qconnect(b.clicked, lambda c: self._on_restore_trash()) qconnect(b.clicked, lambda c: self._on_restore_trash())
@ -157,7 +157,7 @@ class MediaChecker:
aqt.dialogs.open("Browser", self.mw, search=(SearchNode(nid=nid),)) aqt.dialogs.open("Browser", self.mw, search=(SearchNode(nid=nid),))
showText(err, type="html") showText(err, type="html")
else: else:
tooltip(tr(TR.MEDIA_CHECK_ALL_LATEX_RENDERED)) tooltip(tr.media_check_all_latex_rendered())
def _on_render_latex_progress(self, count: int) -> bool: def _on_render_latex_progress(self, count: int) -> bool:
if self.progress_dialog.wantCancel: if self.progress_dialog.wantCancel:
@ -167,7 +167,7 @@ class MediaChecker:
return True return True
def _on_trash_files(self, fnames: Sequence[str]) -> None: def _on_trash_files(self, fnames: Sequence[str]) -> None:
if not askUser(tr(TR.MEDIA_CHECK_DELETE_UNUSED_CONFIRM)): if not askUser(tr.media_check_delete_unused_confirm()):
return return
self.progress_dialog = self.mw.progress.start() self.progress_dialog = self.mw.progress.start()
@ -202,7 +202,7 @@ class MediaChecker:
# check for errors # check for errors
fut.result() fut.result()
tooltip(tr(TR.MEDIA_CHECK_TRASH_EMPTIED)) tooltip(tr.media_check_trash_emptied())
self.mw.taskman.run_in_background(empty_trash, on_done) self.mw.taskman.run_in_background(empty_trash, on_done)
@ -219,6 +219,6 @@ class MediaChecker:
# check for errors # check for errors
fut.result() fut.result()
tooltip(tr(TR.MEDIA_CHECK_TRASH_RESTORED)) tooltip(tr.media_check_trash_restored())
self.mw.taskman.run_in_background(restore_trash, on_done) self.mw.taskman.run_in_background(restore_trash, on_done)

View File

@ -11,7 +11,6 @@ from typing import Any, Callable, List, Optional, Union
import aqt import aqt
from anki.collection import Progress from anki.collection import Progress
from anki.errors import Interrupted, NetworkError from anki.errors import Interrupted, NetworkError
from anki.lang import TR
from anki.types import assert_exhaustive from anki.types import assert_exhaustive
from anki.utils import intTime from anki.utils import intTime
from aqt import gui_hooks from aqt import gui_hooks
@ -48,14 +47,14 @@ class MediaSyncer:
return return
if not self.mw.pm.media_syncing_enabled(): if not self.mw.pm.media_syncing_enabled():
self._log_and_notify(tr(TR.SYNC_MEDIA_DISABLED)) self._log_and_notify(tr.sync_media_disabled())
return return
auth = self.mw.pm.sync_auth() auth = self.mw.pm.sync_auth()
if auth is None: if auth is None:
return return
self._log_and_notify(tr(TR.SYNC_MEDIA_STARTING)) self._log_and_notify(tr.sync_media_starting())
self._syncing = True self._syncing = True
self._progress_timer = self.mw.progress.timer( self._progress_timer = self.mw.progress.timer(
1000, self._on_progress, True, True 1000, self._on_progress, True, True
@ -85,18 +84,18 @@ class MediaSyncer:
if exc is not None: if exc is not None:
self._handle_sync_error(exc) self._handle_sync_error(exc)
else: else:
self._log_and_notify(tr(TR.SYNC_MEDIA_COMPLETE)) self._log_and_notify(tr.sync_media_complete())
def _handle_sync_error(self, exc: BaseException) -> None: def _handle_sync_error(self, exc: BaseException) -> None:
if isinstance(exc, Interrupted): if isinstance(exc, Interrupted):
self._log_and_notify(tr(TR.SYNC_MEDIA_ABORTED)) self._log_and_notify(tr.sync_media_aborted())
return return
elif isinstance(exc, NetworkError): elif isinstance(exc, NetworkError):
# avoid popups for network errors # avoid popups for network errors
self._log_and_notify(str(exc)) self._log_and_notify(str(exc))
return return
self._log_and_notify(tr(TR.SYNC_MEDIA_FAILED)) self._log_and_notify(tr.sync_media_failed())
showWarning(str(exc)) showWarning(str(exc))
def entries(self) -> List[LogEntryWithTime]: def entries(self) -> List[LogEntryWithTime]:
@ -105,7 +104,7 @@ class MediaSyncer:
def abort(self) -> None: def abort(self) -> None:
if not self.is_syncing(): if not self.is_syncing():
return return
self._log_and_notify(tr(TR.SYNC_MEDIA_ABORTING)) self._log_and_notify(tr.sync_media_aborting())
self.mw.col.set_wants_abort() self.mw.col.set_wants_abort()
self.mw.col.abort_media_sync() self.mw.col.abort_media_sync()
@ -158,9 +157,9 @@ class MediaSyncDialog(QDialog):
self._close_when_done = close_when_done self._close_when_done = close_when_done
self.form = aqt.forms.synclog.Ui_Dialog() self.form = aqt.forms.synclog.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
self.setWindowTitle(tr(TR.SYNC_MEDIA_LOG_TITLE)) self.setWindowTitle(tr.sync_media_log_title())
disable_help_button(self) disable_help_button(self)
self.abort_button = QPushButton(tr(TR.SYNC_ABORT_BUTTON)) self.abort_button = QPushButton(tr.sync_abort_button())
qconnect(self.abort_button.clicked, self._on_abort) qconnect(self.abort_button.clicked, self._on_abort)
self.abort_button.setAutoDefault(False) self.abort_button.setAutoDefault(False)
self.form.buttonBox.addButton(self.abort_button, QDialogButtonBox.ActionRole) self.form.buttonBox.addButton(self.abort_button, QDialogButtonBox.ActionRole)

View File

@ -4,7 +4,7 @@ from typing import List, Optional
from aqt import AnkiQt, gui_hooks from aqt import AnkiQt, gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.utils import TR, HelpPage, shortcut, tr from aqt.utils import HelpPage, shortcut, tr
class ModelChooser(QHBoxLayout): class ModelChooser(QHBoxLayout):
@ -37,11 +37,11 @@ class ModelChooser(QHBoxLayout):
def setupModels(self) -> None: def setupModels(self) -> None:
if self.label: if self.label:
self.modelLabel = QLabel(tr(TR.NOTETYPES_TYPE)) self.modelLabel = QLabel(tr.notetypes_type())
self.addWidget(self.modelLabel) self.addWidget(self.modelLabel)
# models box # models box
self.models = QPushButton() self.models = QPushButton()
self.models.setToolTip(shortcut(tr(TR.QT_MISC_CHANGE_NOTE_TYPE_CTRLANDN))) self.models.setToolTip(shortcut(tr.qt_misc_change_note_type_ctrlandn()))
QShortcut(QKeySequence("Ctrl+N"), self._widget, activated=self.on_activated) # type: ignore QShortcut(QKeySequence("Ctrl+N"), self._widget, activated=self.on_activated) # type: ignore
self.models.setAutoDefault(False) self.models.setAutoDefault(False)
self.addWidget(self.models) self.addWidget(self.models)
@ -73,7 +73,7 @@ class ModelChooser(QHBoxLayout):
current = self.deck.models.current()["name"] current = self.deck.models.current()["name"]
# edit button # edit button
edit = QPushButton(tr(TR.QT_MISC_MANAGE), clicked=self.onEdit) # type: ignore edit = QPushButton(tr.qt_misc_manage(), clicked=self.onEdit) # type: ignore
def nameFunc() -> List[str]: def nameFunc() -> List[str]:
return sorted(self.deck.models.allNames()) return sorted(self.deck.models.allNames())
@ -81,8 +81,8 @@ class ModelChooser(QHBoxLayout):
ret = StudyDeck( ret = StudyDeck(
self.mw, self.mw,
names=nameFunc, names=nameFunc,
accept=tr(TR.ACTIONS_CHOOSE), accept=tr.actions_choose(),
title=tr(TR.QT_MISC_CHOOSE_NOTE_TYPE), title=tr.qt_misc_choose_note_type(),
help=HelpPage.NOTE_TYPE, help=HelpPage.NOTE_TYPE,
current=current, current=current,
parent=self._widget, parent=self._widget,

View File

@ -43,7 +43,7 @@ class Models(QDialog):
self.col = mw.col.weakref() self.col = mw.col.weakref()
assert self.col assert self.col
self.mm = self.col.models self.mm = self.col.models
self.mw.checkpoint(tr(TR.NOTETYPES_NOTE_TYPES)) self.mw.checkpoint(tr.notetypes_note_types())
self.form = aqt.forms.models.Ui_Dialog() self.form = aqt.forms.models.Ui_Dialog()
self.form.setupUi(self) self.form.setupUi(self)
qconnect( qconnect(
@ -73,20 +73,20 @@ class Models(QDialog):
box = f.buttonBox box = f.buttonBox
default_buttons = [ default_buttons = [
(tr(TR.ACTIONS_ADD), self.onAdd), (tr.actions_add(), self.onAdd),
(tr(TR.ACTIONS_RENAME), self.onRename), (tr.actions_rename(), self.onRename),
(tr(TR.ACTIONS_DELETE), self.onDelete), (tr.actions_delete(), self.onDelete),
] ]
if self.fromMain: if self.fromMain:
default_buttons.extend( default_buttons.extend(
[ [
(tr(TR.NOTETYPES_FIELDS), self.onFields), (tr.notetypes_fields(), self.onFields),
(tr(TR.NOTETYPES_CARDS), self.onCards), (tr.notetypes_cards(), self.onCards),
] ]
) )
default_buttons.append((tr(TR.NOTETYPES_OPTIONS), self.onAdvanced)) default_buttons.append((tr.notetypes_options(), self.onAdvanced))
for label, func in gui_hooks.models_did_init_buttons(default_buttons, self): for label, func in gui_hooks.models_did_init_buttons(default_buttons, self):
button = box.addButton(label, QDialogButtonBox.ActionRole) button = box.addButton(label, QDialogButtonBox.ActionRole)
@ -103,7 +103,7 @@ class Models(QDialog):
def onRename(self) -> None: def onRename(self) -> None:
nt = self.current_notetype() nt = self.current_notetype()
txt = getText(tr(TR.ACTIONS_NEW_NAME), default=nt["name"]) txt = getText(tr.actions_new_name(), default=nt["name"])
name = txt[0].replace('"', "") name = txt[0].replace('"', "")
if txt[1] and name: if txt[1] and name:
nt["name"] = name nt["name"] = name
@ -139,20 +139,20 @@ class Models(QDialog):
def onAdd(self) -> None: def onAdd(self) -> None:
m = AddModel(self.mw, self).get() m = AddModel(self.mw, self).get()
if m: if m:
txt = getText(tr(TR.ACTIONS_NAME), default=m["name"])[0].replace('"', "") txt = getText(tr.actions_name(), default=m["name"])[0].replace('"', "")
if txt: if txt:
m["name"] = txt m["name"] = txt
self.saveAndRefresh(m) self.saveAndRefresh(m)
def onDelete(self) -> None: def onDelete(self) -> None:
if len(self.models) < 2: if len(self.models) < 2:
showInfo(tr(TR.NOTETYPES_PLEASE_ADD_ANOTHER_NOTE_TYPE_FIRST), parent=self) showInfo(tr.notetypes_please_add_another_note_type_first(), parent=self)
return return
idx = self.form.modelsList.currentRow() idx = self.form.modelsList.currentRow()
if self.models[idx].use_count: if self.models[idx].use_count:
msg = tr(TR.NOTETYPES_DELETE_THIS_NOTE_TYPE_AND_ALL) msg = tr.notetypes_delete_this_note_type_and_all()
else: else:
msg = tr(TR.NOTETYPES_DELETE_THIS_UNUSED_NOTE_TYPE) msg = tr.notetypes_delete_this_unused_note_type()
if not askUser(msg, parent=self): if not askUser(msg, parent=self):
return return

View File

@ -5,7 +5,7 @@ from typing import List, Optional
from anki.models import NoteTypeID from anki.models import NoteTypeID
from aqt import AnkiQt, gui_hooks from aqt import AnkiQt, gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.utils import TR, HelpPage, shortcut, tr from aqt.utils import HelpPage, shortcut, tr
class NoteTypeChooser(QHBoxLayout): class NoteTypeChooser(QHBoxLayout):
@ -55,12 +55,12 @@ class NoteTypeChooser(QHBoxLayout):
self.setSpacing(8) self.setSpacing(8)
if show_label: if show_label:
self.label = QLabel(tr(TR.NOTETYPES_TYPE)) self.label = QLabel(tr.notetypes_type())
self.addWidget(self.label) self.addWidget(self.label)
# button # button
self.button = QPushButton() self.button = QPushButton()
self.button.setToolTip(shortcut(tr(TR.QT_MISC_CHANGE_NOTE_TYPE_CTRLANDN))) self.button.setToolTip(shortcut(tr.qt_misc_change_note_type_ctrlandn()))
qconnect( qconnect(
QShortcut(QKeySequence("Ctrl+N"), self._widget).activated, QShortcut(QKeySequence("Ctrl+N"), self._widget).activated,
self.on_button_activated, self.on_button_activated,
@ -95,7 +95,7 @@ class NoteTypeChooser(QHBoxLayout):
current = self.selected_notetype_name() current = self.selected_notetype_name()
# edit button # edit button
edit = QPushButton(tr(TR.QT_MISC_MANAGE)) edit = QPushButton(tr.qt_misc_manage())
qconnect(edit.clicked, self.onEdit) qconnect(edit.clicked, self.onEdit)
def nameFunc() -> List[str]: def nameFunc() -> List[str]:
@ -104,8 +104,8 @@ class NoteTypeChooser(QHBoxLayout):
ret = StudyDeck( ret = StudyDeck(
self.mw, self.mw,
names=nameFunc, names=nameFunc,
accept=tr(TR.ACTIONS_CHOOSE), accept=tr.actions_choose(),
title=tr(TR.QT_MISC_CHOOSE_NOTE_TYPE), title=tr.qt_misc_choose_note_type(),
help=HelpPage.NOTE_TYPE, help=HelpPage.NOTE_TYPE,
current=current, current=current,
parent=self._widget, parent=self._widget,

View File

@ -81,7 +81,7 @@ class Overview:
self.mw.col.startTimebox() self.mw.col.startTimebox()
self.mw.moveToState("review") self.mw.moveToState("review")
if self.mw.state == "overview": if self.mw.state == "overview":
tooltip(tr(TR.STUDYING_NO_CARDS_ARE_DUE_YET)) tooltip(tr.studying_no_cards_are_due_yet())
elif url == "anki": elif url == "anki":
print("anki menu") print("anki menu")
elif url == "opts": elif url == "opts":
@ -137,13 +137,13 @@ class Overview:
info = self.mw.col.sched.congratulations_info() info = self.mw.col.sched.congratulations_info()
if info.have_sched_buried and info.have_user_buried: if info.have_sched_buried and info.have_user_buried:
opts = [ opts = [
tr(TR.STUDYING_MANUALLY_BURIED_CARDS), tr.studying_manually_buried_cards(),
tr(TR.STUDYING_BURIED_SIBLINGS), tr.studying_buried_siblings(),
tr(TR.STUDYING_ALL_BURIED_CARDS), tr.studying_all_buried_cards(),
tr(TR.ACTIONS_CANCEL), tr.actions_cancel(),
] ]
diag = askUserDialog(tr(TR.STUDYING_WHAT_WOULD_YOU_LIKE_TO_UNBURY), opts) diag = askUserDialog(tr.studying_what_would_you_like_to_unbury(), opts)
diag.setDefault(0) diag.setDefault(0)
ret = diag.run() ret = diag.run()
if ret == opts[0]: if ret == opts[0]:
@ -192,9 +192,9 @@ class Overview:
def _desc(self, deck: Dict[str, Any]) -> str: def _desc(self, deck: Dict[str, Any]) -> str:
if deck["dyn"]: if deck["dyn"]:
desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR) desc = tr.studying_this_is_a_special_deck_for()
desc += f" {tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO)}" desc += f" {tr.studying_cards_will_be_automatically_returned_to()}"
desc += f" {tr(TR.STUDYING_DELETING_THIS_DECK_FROM_THE_DECK)}" desc += f" {tr.studying_deleting_this_deck_from_the_deck()}"
else: else:
desc = deck.get("desc", "") desc = deck.get("desc", "")
if deck.get("md", False): if deck.get("md", False):
@ -220,13 +220,13 @@ class Overview:
</table> </table>
</td><td align=center> </td><td align=center>
%s</td></tr></table>""" % ( %s</td></tr></table>""" % (
tr(TR.ACTIONS_NEW), tr.actions_new(),
counts[0], counts[0],
tr(TR.SCHEDULING_LEARNING), tr.scheduling_learning(),
counts[1], counts[1],
tr(TR.STUDYING_TO_REVIEW), tr.studying_to_review(),
counts[2], counts[2],
but("study", tr(TR.STUDYING_STUDY_NOW), id="study", extra=" autofocus"), but("study", tr.studying_study_now(), id="study", extra=" autofocus"),
) )
_body = """ _body = """
@ -243,16 +243,16 @@ class Overview:
def _renderBottom(self) -> None: def _renderBottom(self) -> None:
links = [ links = [
["O", "opts", tr(TR.ACTIONS_OPTIONS)], ["O", "opts", tr.actions_options()],
] ]
if self.mw.col.decks.current()["dyn"]: if self.mw.col.decks.current()["dyn"]:
links.append(["R", "refresh", tr(TR.ACTIONS_REBUILD)]) links.append(["R", "refresh", tr.actions_rebuild()])
links.append(["E", "empty", tr(TR.STUDYING_EMPTY)]) links.append(["E", "empty", tr.studying_empty()])
else: else:
links.append(["C", "studymore", tr(TR.ACTIONS_CUSTOM_STUDY)]) links.append(["C", "studymore", tr.actions_custom_study()])
# links.append(["F", "cram", _("Filter/Cram")]) # links.append(["F", "cram", _("Filter/Cram")])
if self.mw.col.sched.haveBuried(): if self.mw.col.sched.haveBuried():
links.append(["U", "unbury", tr(TR.STUDYING_UNBURY)]) links.append(["U", "unbury", tr.studying_unbury()])
buf = "" buf = ""
for b in links: for b in links:
if b[0]: if b[0]:

View File

@ -162,7 +162,7 @@ for you than the default driver, please let us know on the Anki forums."""
###################################################################### ######################################################################
def setup_network(self) -> None: def setup_network(self) -> None:
self.form.media_log.setText(tr(TR.SYNC_MEDIA_LOG_BUTTON)) self.form.media_log.setText(tr.sync_media_log_button())
qconnect(self.form.media_log.clicked, self.on_media_log) qconnect(self.form.media_log.clicked, self.on_media_log)
self.form.syncOnProgramOpen.setChecked(self.prof["autoSync"]) self.form.syncOnProgramOpen.setChecked(self.prof["autoSync"])
self.form.syncMedia.setChecked(self.prof["syncMedia"]) self.form.syncMedia.setChecked(self.prof["syncMedia"])
@ -172,7 +172,7 @@ for you than the default driver, please let us know on the Anki forums."""
else: else:
self.form.syncUser.setText(self.prof.get("syncUser", "")) self.form.syncUser.setText(self.prof.get("syncUser", ""))
qconnect(self.form.syncDeauth.clicked, self.sync_logout) qconnect(self.form.syncDeauth.clicked, self.sync_logout)
self.form.syncDeauth.setText(tr(TR.SYNC_LOG_OUT_BUTTON)) self.form.syncDeauth.setText(tr.sync_log_out_button())
def on_media_log(self) -> None: def on_media_log(self) -> None:
self.mw.media_syncer.show_sync_log() self.mw.media_syncer.show_sync_log()
@ -181,7 +181,7 @@ for you than the default driver, please let us know on the Anki forums."""
self.form.syncDeauth.setVisible(False) self.form.syncDeauth.setVisible(False)
self.form.syncUser.setText("") self.form.syncUser.setText("")
self.form.syncLabel.setText( self.form.syncLabel.setText(
tr(TR.PREFERENCES_SYNCHRONIZATIONNOT_CURRENTLY_ENABLED_CLICK_THE_SYNC) tr.preferences_synchronizationnot_currently_enabled_click_the_sync()
) )
def sync_logout(self) -> None: def sync_logout(self) -> None:
@ -238,7 +238,7 @@ for you than the default driver, please let us know on the Anki forums."""
restart_required = True restart_required = True
if restart_required: if restart_required:
showInfo(tr(TR.PREFERENCES_CHANGES_WILL_TAKE_EFFECT_WHEN_YOU)) showInfo(tr.preferences_changes_will_take_effect_when_you())
self.updateOptions() self.updateOptions()
@ -274,9 +274,7 @@ for you than the default driver, please let us know on the Anki forums."""
def on_language_index_changed(self, idx: int) -> None: def on_language_index_changed(self, idx: int) -> None:
code = anki.lang.langs[idx][1] code = anki.lang.langs[idx][1]
self.mw.pm.setLang(code) self.mw.pm.setLang(code)
showInfo( showInfo(tr.preferences_please_restart_anki_to_complete_language(), parent=self)
tr(TR.PREFERENCES_PLEASE_RESTART_ANKI_TO_COMPLETE_LANGUAGE), parent=self
)
# Global: video driver # Global: video driver
###################################################################### ######################################################################
@ -296,19 +294,19 @@ for you than the default driver, please let us know on the Anki forums."""
new_driver = self.video_drivers[self.form.video_driver.currentIndex()] new_driver = self.video_drivers[self.form.video_driver.currentIndex()]
if new_driver != self.mw.pm.video_driver(): if new_driver != self.mw.pm.video_driver():
self.mw.pm.set_video_driver(new_driver) self.mw.pm.set_video_driver(new_driver)
showInfo(tr(TR.PREFERENCES_CHANGES_WILL_TAKE_EFFECT_WHEN_YOU)) showInfo(tr.preferences_changes_will_take_effect_when_you())
def video_driver_name_for_platform(driver: VideoDriver) -> str: def video_driver_name_for_platform(driver: VideoDriver) -> str:
if driver == VideoDriver.ANGLE: if driver == VideoDriver.ANGLE:
return tr(TR.PREFERENCES_VIDEO_DRIVER_ANGLE) return tr.preferences_video_driver_angle()
elif driver == VideoDriver.Software: elif driver == VideoDriver.Software:
if isMac: if isMac:
return tr(TR.PREFERENCES_VIDEO_DRIVER_SOFTWARE_MAC) return tr.preferences_video_driver_software_mac()
else: else:
return tr(TR.PREFERENCES_VIDEO_DRIVER_SOFTWARE_OTHER) return tr.preferences_video_driver_software_other()
else: else:
if isMac: if isMac:
return tr(TR.PREFERENCES_VIDEO_DRIVER_OPENGL_MAC) return tr.preferences_video_driver_opengl_mac()
else: else:
return tr(TR.PREFERENCES_VIDEO_DRIVER_OPENGL_OTHER) return tr.preferences_video_driver_opengl_other()

View File

@ -71,7 +71,7 @@ class Previewer(QDialog):
self.show() self.show()
def _create_gui(self) -> None: def _create_gui(self) -> None:
self.setWindowTitle(tr(TR.ACTIONS_PREVIEW)) self.setWindowTitle(tr.actions_preview())
self.close_shortcut = QShortcut(QKeySequence("Ctrl+Shift+P"), self) self.close_shortcut = QShortcut(QKeySequence("Ctrl+Shift+P"), self)
qconnect(self.close_shortcut.activated, self.close) qconnect(self.close_shortcut.activated, self.close)
@ -85,14 +85,14 @@ class Previewer(QDialog):
self.bbox = QDialogButtonBox() self.bbox = QDialogButtonBox()
self._replay = self.bbox.addButton( self._replay = self.bbox.addButton(
tr(TR.ACTIONS_REPLAY_AUDIO), QDialogButtonBox.ActionRole tr.actions_replay_audio(), QDialogButtonBox.ActionRole
) )
self._replay.setAutoDefault(False) self._replay.setAutoDefault(False)
self._replay.setShortcut(QKeySequence("R")) self._replay.setShortcut(QKeySequence("R"))
self._replay.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="R")) self._replay.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="R"))
qconnect(self._replay.clicked, self._on_replay_audio) qconnect(self._replay.clicked, self._on_replay_audio)
both_sides_button = QCheckBox(tr(TR.QT_MISC_BACK_SIDE_ONLY)) both_sides_button = QCheckBox(tr.qt_misc_back_side_only())
both_sides_button.setShortcut(QKeySequence("B")) both_sides_button.setShortcut(QKeySequence("B"))
both_sides_button.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="B")) both_sides_button.setToolTip(tr(TR.ACTIONS_SHORTCUT_KEY, val="B"))
self.bbox.addButton(both_sides_button, QDialogButtonBox.ActionRole) self.bbox.addButton(both_sides_button, QDialogButtonBox.ActionRole)
@ -173,7 +173,7 @@ class Previewer(QDialog):
c = self.card() c = self.card()
func = "_showQuestion" func = "_showQuestion"
if not c: if not c:
txt = tr(TR.QT_MISC_PLEASE_SELECT_1_CARD) txt = tr.qt_misc_please_select_1_card()
bodyclass = "" bodyclass = ""
self._last_state = None self._last_state = None
else: else:
@ -253,12 +253,12 @@ class MultiCardPreviewer(Previewer):
self._prev = self.bbox.addButton("<", QDialogButtonBox.ActionRole) self._prev = self.bbox.addButton("<", QDialogButtonBox.ActionRole)
self._prev.setAutoDefault(False) self._prev.setAutoDefault(False)
self._prev.setShortcut(QKeySequence("Left")) self._prev.setShortcut(QKeySequence("Left"))
self._prev.setToolTip(tr(TR.QT_MISC_SHORTCUT_KEY_LEFT_ARROW)) self._prev.setToolTip(tr.qt_misc_shortcut_key_left_arrow())
self._next = self.bbox.addButton(">", QDialogButtonBox.ActionRole) self._next = self.bbox.addButton(">", QDialogButtonBox.ActionRole)
self._next.setAutoDefault(True) self._next.setAutoDefault(True)
self._next.setShortcut(QKeySequence("Right")) self._next.setShortcut(QKeySequence("Right"))
self._next.setToolTip(tr(TR.QT_MISC_SHORTCUT_KEY_RIGHT_ARROW_OR_ENTER)) self._next.setToolTip(tr.qt_misc_shortcut_key_right_arrow_or_enter())
qconnect(self._prev.clicked, self._on_prev) qconnect(self._prev.clicked, self._on_prev)
qconnect(self._next.clicked, self._on_next) qconnect(self._next.clicked, self._on_next)

View File

@ -138,7 +138,7 @@ class ProfileManager:
if profile: if profile:
if profile not in self.profiles(): if profile not in self.profiles():
QMessageBox.critical( QMessageBox.critical(
None, tr(TR.QT_MISC_ERROR), tr(TR.PROFILES_PROFILE_DOES_NOT_EXIST) None, tr.qt_misc_error(), tr.profiles_profile_does_not_exist()
) )
sys.exit(1) sys.exit(1)
try: try:
@ -299,8 +299,8 @@ class ProfileManager:
except: except:
QMessageBox.warning( QMessageBox.warning(
None, None,
tr(TR.PROFILES_PROFILE_CORRUPT), tr.profiles_profile_corrupt(),
tr(TR.PROFILES_ANKI_COULD_NOT_READ_YOUR_PROFILE), tr.profiles_anki_could_not_read_your_profile(),
) )
traceback.print_stack() traceback.print_stack()
print("resetting corrupt profile") print("resetting corrupt profile")
@ -353,7 +353,7 @@ class ProfileManager:
self.name = oldName self.name = oldName
return return
else: else:
showWarning(tr(TR.PROFILES_FOLDER_ALREADY_EXISTS)) showWarning(tr.profiles_folder_already_exists())
self.name = oldName self.name = oldName
return return
@ -365,7 +365,7 @@ class ProfileManager:
except Exception as e: except Exception as e:
self.db.rollback() self.db.rollback()
if "WinError 5" in str(e): if "WinError 5" in str(e):
showWarning(tr(TR.PROFILES_ANKI_COULD_NOT_RENAME_YOUR_PROFILE)) showWarning(tr.profiles_anki_could_not_rename_your_profile())
else: else:
raise raise
except: except:
@ -513,7 +513,7 @@ create table if not exists profiles
def _ensureProfile(self) -> None: def _ensureProfile(self) -> None:
"Create a new profile if none exists." "Create a new profile if none exists."
self.create(tr(TR.PROFILES_USER_1)) self.create(tr.profiles_user_1())
p = os.path.join(self.base, "README.txt") p = os.path.join(self.base, "README.txt")
with open(p, "w", encoding="utf8") as file: with open(p, "w", encoding="utf8") as file:
file.write( file.write(

View File

@ -7,7 +7,7 @@ from typing import Callable, Optional
import aqt.forms import aqt.forms
from aqt.qt import * from aqt.qt import *
from aqt.utils import TR, disable_help_button, tr from aqt.utils import disable_help_button, tr
# Progress info # Progress info
########################################################################## ##########################################################################
@ -86,7 +86,7 @@ class ProgressManager:
if not parent and self.mw.isVisible(): if not parent and self.mw.isVisible():
parent = self.mw parent = self.mw
label = label or tr(TR.QT_MISC_PROCESSING) label = label or tr.qt_misc_processing()
self._win = ProgressDialog(parent) self._win = ProgressDialog(parent)
self._win.form.progressBar.setMinimum(min) self._win.form.progressBar.setMinimum(min)
self._win.form.progressBar.setMaximum(max) self._win.form.progressBar.setMaximum(max)

View File

@ -150,8 +150,8 @@ class Reviewer:
part1 = tr(TR.STUDYING_CARD_STUDIED_IN, count=elapsed[1]) part1 = tr(TR.STUDYING_CARD_STUDIED_IN, count=elapsed[1])
mins = int(round(elapsed[0] / 60)) mins = int(round(elapsed[0] / 60))
part2 = tr(TR.STUDYING_MINUTE, count=mins) part2 = tr(TR.STUDYING_MINUTE, count=mins)
fin = tr(TR.STUDYING_FINISH) fin = tr.studying_finish()
diag = askUserDialog(f"{part1} {part2}", [tr(TR.STUDYING_CONTINUE), fin]) diag = askUserDialog(f"{part1} {part2}", [tr.studying_continue(), fin])
diag.setIcon(QMessageBox.Information) diag.setIcon(QMessageBox.Information)
if diag.run() == fin: if diag.run() == fin:
return self.mw.moveToState("deckBrowser") return self.mw.moveToState("deckBrowser")
@ -443,7 +443,7 @@ class Reviewer:
if not self.typeCorrect: if not self.typeCorrect:
if self.typeCorrect is None: if self.typeCorrect is None:
if clozeIdx: if clozeIdx:
warn = tr(TR.STUDYING_PLEASE_RUN_TOOLSEMPTY_CARDS) warn = tr.studying_please_run_toolsempty_cards()
else: else:
warn = tr(TR.STUDYING_TYPE_ANSWER_UNKNOWN_FIELD, val=fld) warn = tr(TR.STUDYING_TYPE_ANSWER_UNKNOWN_FIELD, val=fld)
return re.sub(self.typeAnsPat, warn, buf) return re.sub(self.typeAnsPat, warn, buf)
@ -625,9 +625,9 @@ time = %(time)d;
</script> </script>
""" % dict( """ % dict(
rem=self._remaining(), rem=self._remaining(),
edit=tr(TR.STUDYING_EDIT), edit=tr.studying_edit(),
editkey=tr(TR.ACTIONS_SHORTCUT_KEY, val="E"), editkey=tr(TR.ACTIONS_SHORTCUT_KEY, val="E"),
more=tr(TR.STUDYING_MORE), more=tr.studying_more(),
downArrow=downArrow(), downArrow=downArrow(),
time=self.card.timeTaken() // 1000, time=self.card.timeTaken() // 1000,
) )
@ -637,8 +637,8 @@ time = %(time)d;
<span class=stattxt>%s</span><br> <span class=stattxt>%s</span><br>
<button title="%s" id="ansbut" class="focus" onclick='pycmd("ans");'>%s</button>""" % ( <button title="%s" id="ansbut" class="focus" onclick='pycmd("ans");'>%s</button>""" % (
self._remaining(), self._remaining(),
tr(TR.ACTIONS_SHORTCUT_KEY, val=tr(TR.STUDYING_SPACE)), tr(TR.ACTIONS_SHORTCUT_KEY, val=tr.studying_space()),
tr(TR.STUDYING_SHOW_ANSWER), tr.studying_show_answer(),
) )
# wrap it in a table so it has the same top margin as the ease buttons # wrap it in a table so it has the same top margin as the ease buttons
middle = ( middle = (
@ -682,21 +682,21 @@ time = %(time)d;
button_count = self.mw.col.sched.answerButtons(self.card) button_count = self.mw.col.sched.answerButtons(self.card)
if button_count == 2: if button_count == 2:
buttons_tuple: Tuple[Tuple[int, str], ...] = ( buttons_tuple: Tuple[Tuple[int, str], ...] = (
(1, tr(TR.STUDYING_AGAIN)), (1, tr.studying_again()),
(2, tr(TR.STUDYING_GOOD)), (2, tr.studying_good()),
) )
elif button_count == 3: elif button_count == 3:
buttons_tuple = ( buttons_tuple = (
(1, tr(TR.STUDYING_AGAIN)), (1, tr.studying_again()),
(2, tr(TR.STUDYING_GOOD)), (2, tr.studying_good()),
(3, tr(TR.STUDYING_EASY)), (3, tr.studying_easy()),
) )
else: else:
buttons_tuple = ( buttons_tuple = (
(1, tr(TR.STUDYING_AGAIN)), (1, tr.studying_again()),
(2, tr(TR.STUDYING_HARD)), (2, tr.studying_hard()),
(3, tr(TR.STUDYING_GOOD)), (3, tr.studying_good()),
(4, tr(TR.STUDYING_EASY)), (4, tr.studying_easy()),
) )
buttons_tuple = gui_hooks.reviewer_will_init_answer_buttons( buttons_tuple = gui_hooks.reviewer_will_init_answer_buttons(
buttons_tuple, self, self.card buttons_tuple, self, self.card
@ -742,9 +742,9 @@ time = %(time)d;
def onLeech(self, card: Card) -> None: def onLeech(self, card: Card) -> None:
# for now # for now
s = tr(TR.STUDYING_CARD_WAS_A_LEECH) s = tr.studying_card_was_a_leech()
if card.queue < 0: if card.queue < 0:
s += f" {tr(TR.STUDYING_IT_HAS_BEEN_SUSPENDED)}" s += f" {tr.studying_it_has_been_suspended()}"
tooltip(s) tooltip(s)
# Context menu # Context menu
@ -755,49 +755,49 @@ time = %(time)d;
currentFlag = self.card and self.card.user_flag() currentFlag = self.card and self.card.user_flag()
opts = [ opts = [
[ [
tr(TR.STUDYING_FLAG_CARD), tr.studying_flag_card(),
[ [
[ [
tr(TR.ACTIONS_RED_FLAG), tr.actions_red_flag(),
"Ctrl+1", "Ctrl+1",
lambda: self.set_flag_on_current_card(1), lambda: self.set_flag_on_current_card(1),
dict(checked=currentFlag == 1), dict(checked=currentFlag == 1),
], ],
[ [
tr(TR.ACTIONS_ORANGE_FLAG), tr.actions_orange_flag(),
"Ctrl+2", "Ctrl+2",
lambda: self.set_flag_on_current_card(2), lambda: self.set_flag_on_current_card(2),
dict(checked=currentFlag == 2), dict(checked=currentFlag == 2),
], ],
[ [
tr(TR.ACTIONS_GREEN_FLAG), tr.actions_green_flag(),
"Ctrl+3", "Ctrl+3",
lambda: self.set_flag_on_current_card(3), lambda: self.set_flag_on_current_card(3),
dict(checked=currentFlag == 3), dict(checked=currentFlag == 3),
], ],
[ [
tr(TR.ACTIONS_BLUE_FLAG), tr.actions_blue_flag(),
"Ctrl+4", "Ctrl+4",
lambda: self.set_flag_on_current_card(4), lambda: self.set_flag_on_current_card(4),
dict(checked=currentFlag == 4), dict(checked=currentFlag == 4),
], ],
], ],
], ],
[tr(TR.STUDYING_MARK_NOTE), "*", self.toggle_mark_on_current_note], [tr.studying_mark_note(), "*", self.toggle_mark_on_current_note],
[tr(TR.STUDYING_BURY_CARD), "-", self.bury_current_card], [tr.studying_bury_card(), "-", self.bury_current_card],
[tr(TR.STUDYING_BURY_NOTE), "=", self.bury_current_note], [tr.studying_bury_note(), "=", self.bury_current_note],
[tr(TR.ACTIONS_SET_DUE_DATE), "Ctrl+Shift+D", self.on_set_due], [tr.actions_set_due_date(), "Ctrl+Shift+D", self.on_set_due],
[tr(TR.ACTIONS_SUSPEND_CARD), "@", self.suspend_current_card], [tr.actions_suspend_card(), "@", self.suspend_current_card],
[tr(TR.STUDYING_SUSPEND_NOTE), "!", self.suspend_current_note], [tr.studying_suspend_note(), "!", self.suspend_current_note],
[tr(TR.STUDYING_DELETE_NOTE), "Ctrl+Delete", self.delete_current_note], [tr.studying_delete_note(), "Ctrl+Delete", self.delete_current_note],
[tr(TR.ACTIONS_OPTIONS), "O", self.onOptions], [tr.actions_options(), "O", self.onOptions],
None, None,
[tr(TR.ACTIONS_REPLAY_AUDIO), "R", self.replayAudio], [tr.actions_replay_audio(), "R", self.replayAudio],
[tr(TR.STUDYING_PAUSE_AUDIO), "5", self.on_pause_audio], [tr.studying_pause_audio(), "5", self.on_pause_audio],
[tr(TR.STUDYING_AUDIO_5S), "6", self.on_seek_backward], [tr.studying_audio_5s(), "6", self.on_seek_backward],
[tr(TR.STUDYING_AUDIO_AND5S), "7", self.on_seek_forward], [tr.studying_audio_and5s(), "7", self.on_seek_forward],
[tr(TR.STUDYING_RECORD_OWN_VOICE), "Shift+V", self.onRecordVoice], [tr.studying_record_own_voice(), "Shift+V", self.onRecordVoice],
[tr(TR.STUDYING_REPLAY_OWN_VOICE), "V", self.onReplayRecorded], [tr.studying_replay_own_voice(), "V", self.onReplayRecorded],
] ]
return opts return opts
@ -869,28 +869,28 @@ time = %(time)d;
suspend_note( suspend_note(
mw=self.mw, mw=self.mw,
note_id=self.card.nid, note_id=self.card.nid,
success=lambda _: tooltip(tr(TR.STUDYING_NOTE_SUSPENDED)), success=lambda _: tooltip(tr.studying_note_suspended()),
) )
def suspend_current_card(self) -> None: def suspend_current_card(self) -> None:
suspend_cards( suspend_cards(
mw=self.mw, mw=self.mw,
card_ids=[self.card.id], card_ids=[self.card.id],
success=lambda _: tooltip(tr(TR.STUDYING_CARD_SUSPENDED)), success=lambda _: tooltip(tr.studying_card_suspended()),
) )
def bury_current_note(self) -> None: def bury_current_note(self) -> None:
bury_note( bury_note(
mw=self.mw, mw=self.mw,
note_id=self.card.nid, note_id=self.card.nid,
success=lambda _: tooltip(tr(TR.STUDYING_NOTE_BURIED)), success=lambda _: tooltip(tr.studying_note_buried()),
) )
def bury_current_card(self) -> None: def bury_current_card(self) -> None:
bury_cards( bury_cards(
mw=self.mw, mw=self.mw,
card_ids=[self.card.id], card_ids=[self.card.id],
success=lambda _: tooltip(tr(TR.STUDYING_CARD_BURIED)), success=lambda _: tooltip(tr.studying_card_buried()),
) )
def delete_current_note(self) -> None: def delete_current_note(self) -> None:
@ -919,7 +919,7 @@ time = %(time)d;
def onReplayRecorded(self) -> None: def onReplayRecorded(self) -> None:
if not self._recordedAudio: if not self._recordedAudio:
tooltip(tr(TR.STUDYING_YOU_HAVENT_RECORDED_YOUR_VOICE_YET)) tooltip(tr.studying_you_havent_recorded_your_voice_yet())
return return
av_player.play_file(self._recordedAudio) av_player.play_file(self._recordedAudio)

View File

@ -34,14 +34,14 @@ def set_due_date_dialog(
prompt = "\n".join( prompt = "\n".join(
[ [
tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT, cards=len(card_ids)), tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT, cards=len(card_ids)),
tr(TR.SCHEDULING_SET_DUE_DATE_PROMPT_HINT), tr.scheduling_set_due_date_prompt_hint(),
] ]
) )
(days, success) = getText( (days, success) = getText(
prompt=prompt, prompt=prompt,
parent=parent, parent=parent,
default=default_text, default=default_text,
title=tr(TR.ACTIONS_SET_DUE_DATE), title=tr.actions_set_due_date(),
) )
if not success or not days.strip(): if not success or not days.strip():
return return

View File

@ -957,7 +957,7 @@ class SidebarTreeView(QTreeView):
) )
root.search_node = SearchNode(negated=SearchNode(tag="none")) root.search_node = SearchNode(negated=SearchNode(tag="none"))
root.add_simple( root.add_simple(
name=tr(TR.BROWSING_SIDEBAR_UNTAGGED), name=tr.browsing_sidebar_untagged(),
icon=icon, icon=icon,
type=SidebarItemType.TAG_NONE, type=SidebarItemType.TAG_NONE,
search_node=SearchNode(tag="none"), search_node=SearchNode(tag="none"),
@ -1004,7 +1004,7 @@ class SidebarTreeView(QTreeView):
) )
root.search_node = SearchNode(deck="*") root.search_node = SearchNode(deck="*")
current = root.add_simple( current = root.add_simple(
name=tr(TR.BROWSING_CURRENT_DECK), name=tr.browsing_current_deck(),
icon=icon, icon=icon,
type=SidebarItemType.DECK_CURRENT, type=SidebarItemType.DECK_CURRENT,
search_node=SearchNode(deck="current"), search_node=SearchNode(deck="current"),
@ -1072,17 +1072,17 @@ class SidebarTreeView(QTreeView):
def _maybe_add_type_specific_actions(self, menu: QMenu, item: SidebarItem) -> None: def _maybe_add_type_specific_actions(self, menu: QMenu, item: SidebarItem) -> None:
if item.item_type in (SidebarItemType.NOTETYPE, SidebarItemType.NOTETYPE_ROOT): if item.item_type in (SidebarItemType.NOTETYPE, SidebarItemType.NOTETYPE_ROOT):
menu.addAction( menu.addAction(
tr(TR.BROWSING_MANAGE_NOTE_TYPES), lambda: self.manage_notetype(item) tr.browsing_manage_note_types(), lambda: self.manage_notetype(item)
) )
elif item.item_type == SidebarItemType.NOTETYPE_TEMPLATE: elif item.item_type == SidebarItemType.NOTETYPE_TEMPLATE:
menu.addAction(tr(TR.NOTETYPES_CARDS), lambda: self.manage_template(item)) menu.addAction(tr.notetypes_cards(), lambda: self.manage_template(item))
elif item.item_type == SidebarItemType.SAVED_SEARCH_ROOT: elif item.item_type == SidebarItemType.SAVED_SEARCH_ROOT:
menu.addAction( menu.addAction(
tr(TR.BROWSING_SIDEBAR_SAVE_CURRENT_SEARCH), self.save_current_search tr.browsing_sidebar_save_current_search(), self.save_current_search
) )
elif item.item_type == SidebarItemType.SAVED_SEARCH: elif item.item_type == SidebarItemType.SAVED_SEARCH:
menu.addAction( menu.addAction(
tr(TR.BROWSING_UPDATE_SAVED_SEARCH), tr.browsing_update_saved_search(),
lambda: self.update_saved_search(item), lambda: self.update_saved_search(item),
) )
@ -1090,13 +1090,13 @@ class SidebarTreeView(QTreeView):
self, menu: QMenu, item: SidebarItem, index: QModelIndex self, menu: QMenu, item: SidebarItem, index: QModelIndex
) -> None: ) -> None:
if self._enable_delete(item): if self._enable_delete(item):
menu.addAction(tr(TR.ACTIONS_DELETE), lambda: self._on_delete(item)) menu.addAction(tr.actions_delete(), lambda: self._on_delete(item))
def _maybe_add_rename_action( def _maybe_add_rename_action(
self, menu: QMenu, item: SidebarItem, index: QModelIndex self, menu: QMenu, item: SidebarItem, index: QModelIndex
) -> None: ) -> None:
if item.item_type.is_editable() and len(self._selected_items()) == 1: if item.item_type.is_editable() and len(self._selected_items()) == 1:
menu.addAction(tr(TR.ACTIONS_RENAME), lambda: self.edit(index)) menu.addAction(tr.actions_rename(), lambda: self.edit(index))
def _maybe_add_search_actions(self, menu: QMenu) -> None: def _maybe_add_search_actions(self, menu: QMenu) -> None:
nodes = [ nodes = [
@ -1106,14 +1106,14 @@ class SidebarTreeView(QTreeView):
return return
menu.addSeparator() menu.addSeparator()
if len(nodes) == 1: if len(nodes) == 1:
menu.addAction(tr(TR.ACTIONS_SEARCH), lambda: self.update_search(*nodes)) menu.addAction(tr.actions_search(), lambda: self.update_search(*nodes))
return return
sub_menu = menu.addMenu(tr(TR.ACTIONS_SEARCH)) sub_menu = menu.addMenu(tr.actions_search())
sub_menu.addAction( sub_menu.addAction(
tr(TR.ACTIONS_ALL_SELECTED), lambda: self.update_search(*nodes) tr.actions_all_selected(), lambda: self.update_search(*nodes)
) )
sub_menu.addAction( sub_menu.addAction(
tr(TR.ACTIONS_ANY_SELECTED), tr.actions_any_selected(),
lambda: self.update_search(*nodes, joiner="OR"), lambda: self.update_search(*nodes, joiner="OR"),
) )
@ -1137,21 +1137,19 @@ class SidebarTreeView(QTreeView):
menu.addSeparator() menu.addSeparator()
if any(not item.expanded for item in selected_items if item.children): if any(not item.expanded for item in selected_items if item.children):
menu.addAction(tr(TR.BROWSING_SIDEBAR_EXPAND), lambda: set_expanded(True)) menu.addAction(tr.browsing_sidebar_expand(), lambda: set_expanded(True))
if any(item.expanded for item in selected_items if item.children): if any(item.expanded for item in selected_items if item.children):
menu.addAction( menu.addAction(tr.browsing_sidebar_collapse(), lambda: set_expanded(False))
tr(TR.BROWSING_SIDEBAR_COLLAPSE), lambda: set_expanded(False)
)
if any( if any(
not c.expanded for i in selected_items for c in i.children if c.children not c.expanded for i in selected_items for c in i.children if c.children
): ):
menu.addAction( menu.addAction(
tr(TR.BROWSING_SIDEBAR_EXPAND_CHILDREN), tr.browsing_sidebar_expand_children(),
lambda: set_children_expanded(True), lambda: set_children_expanded(True),
) )
if any(c.expanded for i in selected_items for c in i.children if c.children): if any(c.expanded for i in selected_items for c in i.children if c.children):
menu.addAction( menu.addAction(
tr(TR.BROWSING_SIDEBAR_COLLAPSE_CHILDREN), tr.browsing_sidebar_collapse_children(),
lambda: set_children_expanded(False), lambda: set_children_expanded(False),
) )
@ -1277,7 +1275,7 @@ class SidebarTreeView(QTreeView):
def save_current_search(self) -> None: def save_current_search(self) -> None:
if (search := self._get_current_search()) is None: if (search := self._get_current_search()) is None:
return return
name = getOnlyText(tr(TR.BROWSING_PLEASE_GIVE_YOUR_FILTER_A_NAME)) name = getOnlyText(tr.browsing_please_give_your_filter_a_name())
if not name: if not name:
return return
self._save_search(name, search) self._save_search(name, search)

View File

@ -329,7 +329,7 @@ class SimpleProcessPlayer(Player): # pylint: disable=abstract-method
try: try:
ret.result() ret.result()
except FileNotFoundError: except FileNotFoundError:
showWarning(tr(TR.MEDIA_SOUND_AND_VIDEO_ON_CARDS_WILL)) showWarning(tr.media_sound_and_video_on_cards_will())
# must call cb() here, as we don't currently have another way # must call cb() here, as we don't currently have another way
# to flag to av_player that we've stopped # to flag to av_player that we've stopped
cb() cb()

View File

@ -10,7 +10,6 @@ from aqt import gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.theme import theme_manager from aqt.theme import theme_manager
from aqt.utils import ( from aqt.utils import (
TR,
addCloseShortcut, addCloseShortcut,
disable_help_button, disable_help_button,
getSaveFile, getSaveFile,
@ -41,9 +40,7 @@ class NewDeckStats(QDialog):
f.groupBox.setVisible(False) f.groupBox.setVisible(False)
f.groupBox_2.setVisible(False) f.groupBox_2.setVisible(False)
restoreGeom(self, self.name) restoreGeom(self, self.name)
b = f.buttonBox.addButton( b = f.buttonBox.addButton(tr.statistics_save_pdf(), QDialogButtonBox.ActionRole)
tr(TR.STATISTICS_SAVE_PDF), QDialogButtonBox.ActionRole
)
qconnect(b.clicked, self.saveImage) qconnect(b.clicked, self.saveImage)
b.setAutoDefault(False) b.setAutoDefault(False)
maybeHideClose(self.form.buttonBox) maybeHideClose(self.form.buttonBox)
@ -66,10 +63,10 @@ class NewDeckStats(QDialog):
def _imagePath(self) -> str: def _imagePath(self) -> str:
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time())) name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
name = f"anki-{tr(TR.STATISTICS_STATS)}{name}" name = f"anki-{tr.statistics_stats()}{name}"
file = getSaveFile( file = getSaveFile(
self, self,
title=tr(TR.STATISTICS_SAVE_PDF), title=tr.statistics_save_pdf(),
dir_description="stats", dir_description="stats",
key="stats", key="stats",
ext=".pdf", ext=".pdf",
@ -82,7 +79,7 @@ class NewDeckStats(QDialog):
if not path: if not path:
return return
self.form.web.page().printToPdf(path) self.form.web.page().printToPdf(path)
tooltip(tr(TR.STATISTICS_SAVED)) tooltip(tr.statistics_saved())
# legacy add-ons # legacy add-ons
def changePeriod(self, n: Any) -> None: def changePeriod(self, n: Any) -> None:
@ -126,9 +123,7 @@ class DeckStats(QDialog):
self.setStyleSheet("QGroupBox { border: 0; }") self.setStyleSheet("QGroupBox { border: 0; }")
f.setupUi(self) f.setupUi(self)
restoreGeom(self, self.name) restoreGeom(self, self.name)
b = f.buttonBox.addButton( b = f.buttonBox.addButton(tr.statistics_save_pdf(), QDialogButtonBox.ActionRole)
tr(TR.STATISTICS_SAVE_PDF), QDialogButtonBox.ActionRole
)
qconnect(b.clicked, self.saveImage) qconnect(b.clicked, self.saveImage)
b.setAutoDefault(False) b.setAutoDefault(False)
qconnect(f.groups.clicked, lambda: self.changeScope("deck")) qconnect(f.groups.clicked, lambda: self.changeScope("deck"))
@ -156,10 +151,10 @@ class DeckStats(QDialog):
def _imagePath(self) -> str: def _imagePath(self) -> str:
name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time())) name = time.strftime("-%Y-%m-%d@%H-%M-%S.pdf", time.localtime(time.time()))
name = f"anki-{tr(TR.STATISTICS_STATS)}{name}" name = f"anki-{tr.statistics_stats()}{name}"
file = getSaveFile( file = getSaveFile(
self, self,
title=tr(TR.STATISTICS_SAVE_PDF), title=tr.statistics_save_pdf(),
dir_description="stats", dir_description="stats",
key="stats", key="stats",
ext=".pdf", ext=".pdf",
@ -172,7 +167,7 @@ class DeckStats(QDialog):
if not path: if not path:
return return
self.form.web.page().printToPdf(path) self.form.web.page().printToPdf(path)
tooltip(tr(TR.STATISTICS_SAVED)) tooltip(tr.statistics_saved())
def changePeriod(self, n: int) -> None: def changePeriod(self, n: int) -> None:
self.period = n self.period = n

View File

@ -10,7 +10,6 @@ from aqt import gui_hooks
from aqt.deck_ops import add_deck_dialog from aqt.deck_ops import add_deck_dialog
from aqt.qt import * from aqt.qt import *
from aqt.utils import ( from aqt.utils import (
TR,
HelpPage, HelpPage,
HelpPageArgument, HelpPageArgument,
disable_help_button, disable_help_button,
@ -58,9 +57,9 @@ class StudyDeck(QDialog):
button_or_label, QDialogButtonBox.ActionRole button_or_label, QDialogButtonBox.ActionRole
) )
else: else:
b = QPushButton(tr(TR.ACTIONS_ADD)) b = QPushButton(tr.actions_add())
b.setShortcut(QKeySequence("Ctrl+N")) b.setShortcut(QKeySequence("Ctrl+N"))
b.setToolTip(shortcut(tr(TR.DECKS_ADD_NEW_DECK_CTRLANDN))) b.setToolTip(shortcut(tr.decks_add_new_deck_ctrlandn()))
self.form.buttonBox.addButton(b, QDialogButtonBox.ActionRole) self.form.buttonBox.addButton(b, QDialogButtonBox.ActionRole)
qconnect(b.clicked, self.onAddDeck) qconnect(b.clicked, self.onAddDeck)
if title: if title:
@ -79,7 +78,7 @@ class StudyDeck(QDialog):
self.origNames = names() self.origNames = names()
self.name: Optional[str] = None self.name: Optional[str] = None
self.ok = self.form.buttonBox.addButton( self.ok = self.form.buttonBox.addButton(
accept or tr(TR.DECKS_STUDY), QDialogButtonBox.AcceptRole accept or tr.decks_study(), QDialogButtonBox.AcceptRole
) )
self.setWindowModality(Qt.WindowModal) self.setWindowModality(Qt.WindowModal)
qconnect(self.form.buttonBox.helpRequested, lambda: openHelp(help)) qconnect(self.form.buttonBox.helpRequested, lambda: openHelp(help))
@ -150,7 +149,7 @@ class StudyDeck(QDialog):
gui_hooks.state_did_reset.remove(self.onReset) gui_hooks.state_did_reset.remove(self.onReset)
row = self.form.list.currentRow() row = self.form.list.currentRow()
if row < 0: if row < 0:
showInfo(tr(TR.DECKS_PLEASE_SELECT_SOMETHING)) showInfo(tr.decks_please_select_something())
return return
self.name = self.names[self.form.list.currentRow()] self.name = self.names[self.form.list.currentRow()]
QDialog.accept(self) QDialog.accept(self)

View File

@ -119,7 +119,7 @@ def sync_collection(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
mw.taskman.with_progress( mw.taskman.with_progress(
lambda: mw.col.sync_collection(auth), lambda: mw.col.sync_collection(auth),
on_future_done, on_future_done,
label=tr(TR.SYNC_CHECKING), label=tr.sync_checking(),
immediate=True, immediate=True,
) )
@ -144,7 +144,7 @@ def full_sync(
def confirm_full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None: def confirm_full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
# confirmation step required, as some users customize their notetypes # confirmation step required, as some users customize their notetypes
# in an empty collection, then want to upload them # in an empty collection, then want to upload them
if not askUser(tr(TR.SYNC_CONFIRM_EMPTY_DOWNLOAD)): if not askUser(tr.sync_confirm_empty_download()):
return on_done() return on_done()
else: else:
mw.closeAllWindows(lambda: full_download(mw, on_done)) mw.closeAllWindows(lambda: full_download(mw, on_done))
@ -157,7 +157,7 @@ def on_full_sync_timer(mw: aqt.main.AnkiQt) -> None:
sync_progress = progress.full_sync sync_progress = progress.full_sync
if sync_progress.transferred == sync_progress.total: if sync_progress.transferred == sync_progress.total:
label = tr(TR.SYNC_CHECKING) label = tr.sync_checking()
else: else:
label = None label = None
mw.progress.update( mw.progress.update(
@ -197,7 +197,7 @@ def full_download(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
mw.taskman.with_progress( mw.taskman.with_progress(
download, download,
on_future_done, on_future_done,
label=tr(TR.SYNC_DOWNLOADING_FROM_ANKIWEB), label=tr.sync_downloading_from_ankiweb(),
) )
@ -226,7 +226,7 @@ def full_upload(mw: aqt.main.AnkiQt, on_done: Callable[[], None]) -> None:
mw.taskman.with_progress( mw.taskman.with_progress(
lambda: mw.col.full_upload(mw.pm.sync_auth()), lambda: mw.col.full_upload(mw.pm.sync_auth()),
on_future_done, on_future_done,
label=tr(TR.SYNC_UPLOADING_TO_ANKIWEB), label=tr.sync_uploading_to_ankiweb(),
) )
@ -271,11 +271,11 @@ def sync_login(
def ask_user_to_decide_direction() -> FullSyncChoice: def ask_user_to_decide_direction() -> FullSyncChoice:
button_labels = [ button_labels = [
tr(TR.SYNC_UPLOAD_TO_ANKIWEB), tr.sync_upload_to_ankiweb(),
tr(TR.SYNC_DOWNLOAD_FROM_ANKIWEB), tr.sync_download_from_ankiweb(),
tr(TR.SYNC_CANCEL_BUTTON), tr.sync_cancel_button(),
] ]
diag = askUserDialog(tr(TR.SYNC_CONFLICT_EXPLANATION), button_labels) diag = askUserDialog(tr.sync_conflict_explanation(), button_labels)
diag.setDefault(2) diag.setDefault(2)
ret = diag.run() ret = diag.run()
if ret == button_labels[0]: if ret == button_labels[0]:
@ -304,12 +304,12 @@ def get_id_and_pass_from_user(
vbox.addWidget(info_label) vbox.addWidget(info_label)
vbox.addSpacing(20) vbox.addSpacing(20)
g = QGridLayout() g = QGridLayout()
l1 = QLabel(tr(TR.SYNC_ANKIWEB_ID_LABEL)) l1 = QLabel(tr.sync_ankiweb_id_label())
g.addWidget(l1, 0, 0) g.addWidget(l1, 0, 0)
user = QLineEdit() user = QLineEdit()
user.setText(username) user.setText(username)
g.addWidget(user, 0, 1) g.addWidget(user, 0, 1)
l2 = QLabel(tr(TR.SYNC_PASSWORD_LABEL)) l2 = QLabel(tr.sync_password_label())
g.addWidget(l2, 1, 0) g.addWidget(l2, 1, 0)
passwd = QLineEdit() passwd = QLineEdit()
passwd.setText(password) passwd.setText(password)

View File

@ -58,7 +58,7 @@ def rename_tag(
if out.count: if out.count:
tooltip(tr(TR.BROWSING_NOTES_UPDATED, count=out.count), parent=parent) tooltip(tr(TR.BROWSING_NOTES_UPDATED, count=out.count), parent=parent)
else: else:
showInfo(tr(TR.BROWSING_TAG_RENAME_WARNING_EMPTY), parent=parent) showInfo(tr.browsing_tag_rename_warning_empty(), parent=parent)
mw.perform_op( mw.perform_op(
lambda: mw.col.tags.rename(old=current_name, new=new_name), lambda: mw.col.tags.rename(old=current_name, new=new_name),

View File

@ -100,28 +100,28 @@ class Toolbar:
links = [ links = [
self.create_link( self.create_link(
"decks", "decks",
tr(TR.ACTIONS_DECKS), tr.actions_decks(),
self._deckLinkHandler, self._deckLinkHandler,
tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="D"), tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="D"),
id="decks", id="decks",
), ),
self.create_link( self.create_link(
"add", "add",
tr(TR.ACTIONS_ADD), tr.actions_add(),
self._addLinkHandler, self._addLinkHandler,
tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="A"), tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="A"),
id="add", id="add",
), ),
self.create_link( self.create_link(
"browse", "browse",
tr(TR.QT_MISC_BROWSE), tr.qt_misc_browse(),
self._browseLinkHandler, self._browseLinkHandler,
tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="B"), tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="B"),
id="browse", id="browse",
), ),
self.create_link( self.create_link(
"stats", "stats",
tr(TR.QT_MISC_STATS), tr.qt_misc_stats(),
self._statsLinkHandler, self._statsLinkHandler,
tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="T"), tip=tr(TR.ACTIONS_SHORTCUT_KEY, val="T"),
id="stats", id="stats",
@ -138,7 +138,7 @@ class Toolbar:
###################################################################### ######################################################################
def _create_sync_link(self) -> str: def _create_sync_link(self) -> str:
name = tr(TR.QT_MISC_SYNC) name = tr.qt_misc_sync()
title = tr(TR.ACTIONS_SHORTCUT_KEY, val="Y") title = tr(TR.ACTIONS_SHORTCUT_KEY, val="Y")
label = "sync" label = "sync"
self.link_handlers[label] = self._syncLinkHandler self.link_handlers[label] = self._syncLinkHandler

View File

@ -61,8 +61,8 @@ def askAndUpdate(mw: aqt.AnkiQt, ver: str) -> None:
msg = QMessageBox(mw) msg = QMessageBox(mw)
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # type: ignore msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # type: ignore
msg.setIcon(QMessageBox.Information) msg.setIcon(QMessageBox.Information)
msg.setText(baseStr + tr(TR.QT_MISC_WOULD_YOU_LIKE_TO_DOWNLOAD_IT)) msg.setText(baseStr + tr.qt_misc_would_you_like_to_download_it())
button = QPushButton(tr(TR.QT_MISC_IGNORE_THIS_UPDATE)) button = QPushButton(tr.qt_misc_ignore_this_update())
msg.addButton(button, QMessageBox.RejectRole) msg.addButton(button, QMessageBox.RejectRole)
msg.setDefaultButton(QMessageBox.Yes) msg.setDefaultButton(QMessageBox.Yes)
ret = msg.exec_() ret = msg.exec_()

View File

@ -33,10 +33,9 @@ from PyQt5.QtWidgets import (
QWidget, QWidget,
) )
import anki
import aqt import aqt
from anki import Collection from anki import Collection
from anki.lang import TR # pylint: disable=unused-import from anki.lang import TR, tr_legacyglobal # pylint: disable=unused-import
from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild
from aqt.qt import * from aqt.qt import *
from aqt.theme import theme_manager from aqt.theme import theme_manager
@ -67,9 +66,8 @@ def locale_dir() -> str:
return os.path.join(aqt_data_folder(), "locale") return os.path.join(aqt_data_folder(), "locale")
def tr(key: TR, **kwargs: Union[str, int, float]) -> str: # shortcut to access Fluent translations; set as
"Shortcut to access Fluent translations." tr = tr_legacyglobal
return anki.lang.current_i18n.translate(key, **kwargs)
class HelpPage(Enum): class HelpPage(Enum):
@ -110,7 +108,7 @@ def openHelp(section: HelpPageArgument) -> None:
def openLink(link: Union[str, QUrl]) -> None: def openLink(link: Union[str, QUrl]) -> None:
tooltip(tr(TR.QT_MISC_LOADING), period=1000) tooltip(tr.qt_misc_loading(), period=1000)
with noBundledLibs(): with noBundledLibs():
QDesktopServices.openUrl(QUrl(link)) QDesktopServices.openUrl(QUrl(link))
@ -226,7 +224,7 @@ def showText(
def onCopy() -> None: def onCopy() -> None:
QApplication.clipboard().setText(text.toPlainText()) QApplication.clipboard().setText(text.toPlainText())
btn = QPushButton(tr(TR.QT_MISC_COPY_TO_CLIPBOARD)) btn = QPushButton(tr.qt_misc_copy_to_clipboard())
qconnect(btn.clicked, onCopy) qconnect(btn.clicked, onCopy)
box.addButton(btn, QDialogButtonBox.ActionRole) box.addButton(btn, QDialogButtonBox.ActionRole)
@ -301,8 +299,8 @@ class ButtonedDialog(QMessageBox):
for b in buttons: for b in buttons:
self._buttons.append(self.addButton(b, QMessageBox.AcceptRole)) self._buttons.append(self.addButton(b, QMessageBox.AcceptRole))
if help: if help:
self.addButton(tr(TR.ACTIONS_HELP), QMessageBox.HelpRole) self.addButton(tr.actions_help(), QMessageBox.HelpRole)
buttons.append(tr(TR.ACTIONS_HELP)) buttons.append(tr.actions_help())
def run(self) -> str: def run(self) -> str:
self.exec_() self.exec_()
@ -536,7 +534,7 @@ def getSaveFile(
aqt.mw.pm.profile[config_key] = dir aqt.mw.pm.profile[config_key] = dir
# check if it exists # check if it exists
if os.path.exists(file): if os.path.exists(file):
if not askUser(tr(TR.QT_MISC_THIS_FILE_EXISTS_ARE_YOU_SURE), parent): if not askUser(tr.qt_misc_this_file_exists_are_you_sure(), parent):
return None return None
return file return file

View File

@ -13,7 +13,7 @@ from anki.utils import isLin, isMac, isWin
from aqt import colors, gui_hooks from aqt import colors, gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.theme import theme_manager from aqt.theme import theme_manager
from aqt.utils import TR, openLink, showInfo, tr from aqt.utils import openLink, showInfo, tr
serverbaseurl = re.compile(r"^.+:\/\/[^\/]+") serverbaseurl = re.compile(r"^.+:\/\/[^\/]+")
@ -305,7 +305,7 @@ class AnkiWebView(QWebEngineView):
def contextMenuEvent(self, evt: QContextMenuEvent) -> None: def contextMenuEvent(self, evt: QContextMenuEvent) -> None:
m = QMenu(self) m = QMenu(self)
a = m.addAction(tr(TR.ACTIONS_COPY)) a = m.addAction(tr.actions_copy())
qconnect(a.triggered, self.onCopy) qconnect(a.triggered, self.onCopy)
gui_hooks.webview_will_show_context_menu(self, m) gui_hooks.webview_will_show_context_menu(self, m)
m.popup(QCursor.pos()) m.popup(QCursor.pos())
@ -396,7 +396,7 @@ class AnkiWebView(QWebEngineView):
if isWin: if isWin:
# T: include a font for your language on Windows, eg: "Segoe UI", "MS Mincho" # T: include a font for your language on Windows, eg: "Segoe UI", "MS Mincho"
family = tr(TR.QT_MISC_SEGOE_UI) family = tr.qt_misc_segoe_ui()
button_style = "button { font-family:%s; }" % family button_style = "button { font-family:%s; }" % family
button_style += "\n:focus { outline: 1px solid %s; }" % color_hl button_style += "\n:focus { outline: 1px solid %s; }" % color_hl
font = f"font-size:12px;font-family:{family};" font = f"font-size:12px;font-family:{family};"