diff --git a/qt/aqt/about.py b/qt/aqt/about.py
index 79fee400e..f2470ccc4 100644
--- a/qt/aqt/about.py
+++ b/qt/aqt/about.py
@@ -93,14 +93,8 @@ def show(mw):
# WebView contents
######################################################################
abouttext = "
"
- abouttext += "" + _(
- "Anki is a friendly, intelligent spaced learning \
-system. It's free and open source."
- )
- abouttext += "
" + _(
- "Anki is licensed under the AGPL3 license. Please see "
- "the license file in the source distribution for more information."
- )
+ abouttext += "
" + tr(TR.ABOUT_ANKI_IS_A_FRIENDLY_INTELLIGENT_SPACED)
+ abouttext += "
" + tr(TR.ABOUT_ANKI_IS_LICENSED_UNDER_THE_AGPL3)
abouttext += "
" + tr(TR.ABOUT_VERSION, val=versionWithBuild()) + "
"
abouttext += ("Python %s Qt %s PyQt %s
") % (
platform.python_version(),
@@ -209,22 +203,11 @@ system. It's free and open source."
)
)
- abouttext += (
- "
"
- + _(
- "Written by Damien Elmes, with patches, translation,\
- testing and design from:
%(cont)s"
- )
- % {"cont": ", ".join(allusers)}
- )
- abouttext += "
" + _(
- "If you have contributed and are not on this list, \
-please get in touch."
- )
- abouttext += "
" + _(
- "A big thanks to all the people who have provided \
-suggestions, bug reports and donations."
- )
+ abouttext += "
" + tr(TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES) % {
+ "cont": ", ".join(allusers)
+ }
+ abouttext += "
" + tr(TR.ABOUT_IF_YOU_HAVE_CONTRIBUTED_AND_ARE)
+ abouttext += "
" + tr(TR.ABOUT_A_BIG_THANKS_TO_ALL_THE)
abt.label.setMinimumWidth(800)
abt.label.setMinimumHeight(600)
dialog.show()
diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py
index 757c08f8a..bd2492757 100644
--- a/qt/aqt/addcards.py
+++ b/qt/aqt/addcards.py
@@ -175,12 +175,7 @@ class AddCards(QDialog):
return None
if note.model()["type"] == MODEL_CLOZE:
if not note.cloze_numbers_in_fields():
- if not askUser(
- _(
- "You have a cloze deletion note type "
- "but have not made any cloze deletions. Proceed?"
- )
- ):
+ if not askUser(tr(TR.ADDING_YOU_HAVE_A_CLOZE_DELETION_NOTE)):
return None
self.mw.col.add_note(note, self.deckChooser.selectedId())
self.mw.col.clearUndo()
diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py
index c4ea1392e..8053278be 100644
--- a/qt/aqt/addons.py
+++ b/qt/aqt/addons.py
@@ -836,12 +836,7 @@ class AddonsDialog(QDialog):
if not selected:
return
if not askUser(
- ngettext(
- "Delete the %(num)d selected add-on?",
- "Delete the %(num)d selected add-ons?",
- len(selected),
- )
- % dict(num=len(selected))
+ tr(TR.ADDONS_DELETE_THE_NUMD_SELECTED_ADDON, count=len(selected))
):
return
for dir in selected:
diff --git a/qt/aqt/browser.py b/qt/aqt/browser.py
index 1ab4b6347..e4bec4192 100644
--- a/qt/aqt/browser.py
+++ b/qt/aqt/browser.py
@@ -17,7 +17,6 @@ import aqt.forms
from anki.cards import Card
from anki.collection import Collection
from anki.consts import *
-from anki.lang import _, ngettext
from anki.models import NoteType
from anki.notes import Note
from anki.rsbackend import TR, DeckTreeNode, InvalidInput
@@ -821,16 +820,10 @@ class Browser(QMainWindow):
def updateTitle(self):
selected = len(self.form.tableView.selectionModel().selectedRows())
cur = len(self.model.cards)
+ print("fixme: browser updateTitle()")
self.setWindowTitle(
- ngettext(
- "Browse (%(cur)d card shown; %(sel)s)",
- "Browse (%(cur)d cards shown; %(sel)s)",
- cur,
- )
- % {
- "cur": cur,
- "sel": ngettext("%d selected", "%d selected", selected) % selected,
- }
+ "Browse (%(cur)d cards shown; %(sel)s)"
+ % {"cur": cur, "sel": self.col.tr(TR.BROWSING_SELECTED, count=selected)}
)
return selected
@@ -2266,14 +2259,7 @@ class ChangeModel(QDialog):
fmap = self.getFieldMap()
cmap = self.getTemplateMap()
if any(True for c in list(cmap.values()) if c is None):
- if not askUser(
- _(
- """\
-Any cards mapped to nothing will be deleted. \
-If a note has no remaining cards, it will be lost. \
-Are you sure you want to continue?"""
- )
- ):
+ if not askUser(tr(TR.BROWSING_ANY_CARDS_MAPPED_TO_NOTHING_WILL)):
return
self.browser.mw.checkpoint(tr(TR.BROWSING_CHANGE_NOTE_TYPE))
b = self.browser
diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py
index 55a26d7ed..9bd1c467c 100644
--- a/qt/aqt/clayout.py
+++ b/qt/aqt/clayout.py
@@ -9,7 +9,6 @@ from typing import Any, Dict, List, Optional
import aqt
from anki.cards import Card
from anki.consts import *
-from anki.lang import _, ngettext
from anki.notes import Note
from anki.rsbackend import TemplateError
from anki.template import TemplateRenderContext
@@ -656,13 +655,7 @@ class CardLayout(QDialog):
def _flipQA(self, src, dst):
m = re.match("(?s)(.+)
(.+)", src["afmt"])
if not m:
- showInfo(
- _(
- """\
-Anki couldn't find the line between the question and answer. Please \
-adjust the template manually to switch the question and answer."""
- )
- )
+ showInfo(tr(TR.CARD_TEMPLATES_ANKI_COULDNT_FIND_THE_LINE_BETWEEN))
return
self.change_tracker.mark_basic()
dst["afmt"] = "{{FrontSide}}\n\n
\n\n%s" % src["qfmt"]
@@ -736,10 +729,7 @@ adjust the template manually to switch the question and answer."""
d.setMinimumWidth(400)
l = QVBoxLayout()
lab = QLabel(
- _(
- """\
-Enter deck to place new %s cards in, or leave blank:"""
- )
+ tr(TR.CARD_TEMPLATES_ENTER_DECK_TO_PLACE_NEW, val="%s")
% self.current_template()["name"]
)
lab.setWordWrap(True)
diff --git a/qt/aqt/deckbrowser.py b/qt/aqt/deckbrowser.py
index eaf899ff6..00f63f2e0 100644
--- a/qt/aqt/deckbrowser.py
+++ b/qt/aqt/deckbrowser.py
@@ -8,7 +8,6 @@ from dataclasses import dataclass
import aqt
from anki.errors import DeckRenameError
-from anki.lang import _, ngettext
from anki.rsbackend import TR, DeckTreeNode
from anki.utils import ids2str
from aqt import AnkiQt, gui_hooks
diff --git a/qt/aqt/deckconf.py b/qt/aqt/deckconf.py
index 8c3af16f6..24fa1dfe2 100644
--- a/qt/aqt/deckconf.py
+++ b/qt/aqt/deckconf.py
@@ -8,7 +8,6 @@ from PyQt5.QtWidgets import QLineEdit
import aqt
from anki.consts import NEW_CARDS_RANDOM
-from anki.lang import _, ngettext
from aqt import gui_hooks
from aqt.qt import *
from aqt.utils import (
@@ -110,10 +109,7 @@ class DeckConf(QDialog):
self.loadConf()
cnt = len(self.mw.col.decks.didsForConf(conf))
if cnt > 1:
- txt = _(
- "Your changes will affect multiple decks. If you wish to "
- "change only the current deck, please add a new options group first."
- )
+ txt = tr(TR.SCHEDULING_YOUR_CHANGES_WILL_AFFECT_MULTIPLE_DECKS)
else:
txt = ""
self.form.count.setText(txt)
diff --git a/qt/aqt/dyndeckconf.py b/qt/aqt/dyndeckconf.py
index 43b134be9..3389ebb84 100644
--- a/qt/aqt/dyndeckconf.py
+++ b/qt/aqt/dyndeckconf.py
@@ -123,13 +123,7 @@ class DeckConf(QDialog):
if not self.saveConf():
return
if not self.mw.col.sched.rebuild_filtered_deck(self.deck["id"]):
- if askUser(
- _(
- """\
-The provided search did not match any cards. Would you like to revise \
-it?"""
- )
- ):
+ if askUser(tr(TR.DECKS_THE_PROVIDED_SEARCH_DID_NOT_MATCH)):
return
self.mw.reset()
QDialog.accept(self)
diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py
index 4b221c1bd..e55f5f2a1 100644
--- a/qt/aqt/editor.py
+++ b/qt/aqt/editor.py
@@ -658,20 +658,9 @@ class Editor:
# check that the model is set up for cloze deletion
if not re.search("{{(.*:)*cloze:", self.note.model()["tmpls"][0]["qfmt"]):
if self.addMode:
- tooltip(
- _(
- "Warning, cloze deletions will not work until "
- "you switch the type at the top to Cloze."
- )
- )
+ tooltip(tr(TR.EDITING_WARNING_CLOZE_DELETIONS_WILL_NOT_WORK))
else:
- showInfo(
- _(
- """\
-To make a cloze deletion on an existing note, you need to change it \
-to a cloze type first, via 'Notes>Change Note Type'"""
- )
- )
+ showInfo(tr(TR.EDITING_TO_MAKE_A_CLOZE_DELETION_ON))
return
# find the highest existing cloze
highest = 0
diff --git a/qt/aqt/errors.py b/qt/aqt/errors.py
index 94b606e34..c78f527cb 100644
--- a/qt/aqt/errors.py
+++ b/qt/aqt/errors.py
@@ -65,10 +65,7 @@ class ErrorHandler(QObject):
self.timer.start()
def tempFolderMsg(self):
- return _(
- """Unable to access Anki media folder. The permissions on \
-your system's temporary folder may be incorrect."""
- )
+ return tr(TR.QT_MISC_UNABLE_TO_ACCESS_ANKI_MEDIA_FOLDER)
def onTimeout(self):
error = html.escape(self.pool)
@@ -79,12 +76,7 @@ your system's temporary folder may be incorrect."""
if "10013" in error:
return showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS))
if "no default input" in error.lower():
- return showWarning(
- _(
- "Please connect a microphone, and ensure "
- "other programs are not using the audio device."
- )
- )
+ return showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE))
if "invalidTempFolder" in error:
return showWarning(self.tempFolderMsg())
if "Beautiful Soup is not an HTTP client" in error:
diff --git a/qt/aqt/exporting.py b/qt/aqt/exporting.py
index a4c0d0b3c..2d9b5c909 100644
--- a/qt/aqt/exporting.py
+++ b/qt/aqt/exporting.py
@@ -12,7 +12,6 @@ from typing import List, Optional
import aqt
from anki import hooks
from anki.exporting import Exporter, exporters
-from anki.lang import _, ngettext
from aqt.qt import *
from aqt.utils import TR, checkInvalidFilename, getSaveFile, showWarning, tooltip, tr
diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py
index 173a7edb4..f326228bc 100644
--- a/qt/aqt/fields.py
+++ b/qt/aqt/fields.py
@@ -3,7 +3,6 @@
import aqt
from anki.consts import *
-from anki.lang import _, ngettext
from anki.models import NoteType
from anki.rsbackend import TemplateError
from aqt import AnkiQt, gui_hooks
diff --git a/qt/aqt/importing.py b/qt/aqt/importing.py
index 176a9e78e..4116673e5 100644
--- a/qt/aqt/importing.py
+++ b/qt/aqt/importing.py
@@ -15,7 +15,6 @@ import anki.importing as importing
import aqt.deckchooser
import aqt.forms
import aqt.modelchooser
-from anki.lang import _, ngettext
from aqt import AnkiQt, gui_hooks
from aqt.qt import *
from aqt.utils import (
@@ -118,12 +117,7 @@ class ImportDialog(QDialog):
def onDelimiter(self):
str = (
getOnlyText(
- _(
- """\
-By default, Anki will detect the character between fields, such as
-a tab, comma, and so on. If Anki is detecting the character incorrectly,
-you can enter it here. Use \\t to represent tab."""
- ),
+ tr(TR.IMPORTING_BY_DEFAULT_ANKI_WILL_DETECT_THE),
self,
help="importing",
)
@@ -132,10 +126,7 @@ you can enter it here. Use \\t to represent tab."""
str = str.replace("\\t", "\t")
if len(str) > 1:
showWarning(
- _(
- "Multi-character separators are not supported. "
- "Please enter one character only."
- )
+ tr(TR.IMPORTING_MULTICHARACTER_SEPARATORS_ARE_NOT_SUPPORTED_PLEASE)
)
return
self.hideMapping()
@@ -297,12 +288,7 @@ you can enter it here. Use \\t to represent tab."""
def showUnicodeWarning():
"""Shorthand to show a standard warning."""
- showWarning(
- _(
- "Selected file was not in UTF-8 format. Please see the "
- "importing section of the manual."
- )
- )
+ showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8))
def onImport(mw):
@@ -390,20 +376,12 @@ def importFile(mw, file):
except Exception as e:
err = repr(str(e))
if "invalidFile" in err:
- msg = _(
- """\
-Invalid file. Please restore from backup."""
- )
+ msg = tr(TR.IMPORTING_INVALID_FILE_PLEASE_RESTORE_FROM_BACKUP)
showWarning(msg)
elif "invalidTempFolder" in err:
showWarning(mw.errorHandler.tempFolderMsg())
elif "readonly" in err:
- showWarning(
- _(
- """\
-Unable to import from a read-only file."""
- )
- )
+ showWarning(tr(TR.IMPORTING_UNABLE_TO_IMPORT_FROM_A_READONLY))
else:
msg = tr(TR.IMPORTING_FAILED_DEBUG_INFO) + "\n"
msg += str(traceback.format_exc())
@@ -421,13 +399,7 @@ Unable to import from a read-only file."""
def invalidZipMsg():
- return _(
- """\
-This file does not appear to be a valid .apkg file. If you're getting this \
-error from a file downloaded from AnkiWeb, chances are that your download \
-failed. Please try again, and if the problem persists, please try again \
-with a different browser."""
- )
+ return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO)
def setupApkgImport(mw, importer):
@@ -441,11 +413,7 @@ def setupApkgImport(mw, importer):
# adding
return True
if not mw.restoringBackup and not askUser(
- _(
- """\
-This will delete your existing collection and replace it with the data in \
-the file you're importing. Are you sure?"""
- ),
+ tr(TR.IMPORTING_THIS_WILL_DELETE_YOUR_EXISTING_COLLECTION),
msgfunc=QMessageBox.warning,
defaultno=True,
):
diff --git a/qt/aqt/main.py b/qt/aqt/main.py
index a15a8b617..670c7687a 100644
--- a/qt/aqt/main.py
+++ b/qt/aqt/main.py
@@ -29,7 +29,6 @@ from anki import hooks
from anki.collection import Collection
from anki.decks import Deck
from anki.hooks import runHook
-from anki.lang import _, ngettext
from anki.rsbackend import RustBackend
from anki.sound import AVTag, SoundOrVideoTag
from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields
@@ -123,12 +122,7 @@ class AnkiQt(QMainWindow):
sys.exit(1)
# must call this after ui set up
if self.safeMode:
- tooltip(
- _(
- "Shift key was held down. Skipping automatic "
- "syncing and add-on loading."
- )
- )
+ tooltip(tr(TR.QT_MISC_SHIFT_KEY_WAS_HELD_DOWN_SKIPPING))
# were we given a file to import?
if args and args[0] and not self._isAddon(args[0]):
self.onAppMsg(args[0])
@@ -319,11 +313,7 @@ class AnkiQt(QMainWindow):
return showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE))
# sure?
if not askUser(
- _(
- """\
-All cards, notes, and media for this profile will be deleted. \
-Are you sure?"""
- ),
+ tr(TR.QT_MISC_ALL_CARDS_NOTES_AND_MEDIA_FOR),
msgfunc=QMessageBox.warning,
defaultno=True,
):
@@ -333,10 +323,7 @@ Are you sure?"""
def onOpenBackup(self):
if not askUser(
- _(
- """\
-Replace your collection with an earlier backup?"""
- ),
+ tr(TR.QT_MISC_REPLACE_YOUR_COLLECTION_WITH_AN_EARLIER),
msgfunc=QMessageBox.warning,
defaultno=True,
):
@@ -364,13 +351,7 @@ Replace your collection with an earlier backup?"""
self.pendingImport = path
self.restoringBackup = True
- showInfo(
- _(
- """\
-Automatic syncing and backups have been disabled while restoring. To enable them again, \
-close the profile or restart Anki."""
- )
- )
+ showInfo(tr(TR.QT_MISC_AUTOMATIC_SYNCING_AND_BACKUPS_HAVE_BEEN))
self.onOpenProfile()
@@ -568,15 +549,7 @@ close the profile or restart Anki."""
self.col = None
self.progress.finish()
if corrupt:
- showWarning(
- _(
- "Your collection file appears to be corrupt. \
-This can happen when the file is copied or moved while Anki is open, or \
-when the collection is stored on a network or cloud drive. If problems \
-persist after restarting your computer, please open an automatic backup \
-from the profile screen."
- )
- )
+ showWarning(tr(TR.QT_MISC_YOUR_COLLECTION_FILE_APPEARS_TO_BE))
if not corrupt and not self.restoringBackup:
self.backup()
@@ -1218,26 +1191,7 @@ title="%s" %s>%s""" % (
print("clock is off; ignoring")
return
diffText = tr(TR.QT_MISC_SECOND, count=diff)
- warn = (
- _(
- """\
-In order to ensure your collection works correctly when moved between \
-devices, Anki requires your computer's internal clock to be set correctly. \
-The internal clock can be wrong even if your system is showing the correct \
-local time.
-
-Please go to the time settings on your computer and check the following:
-
-- AM/PM
-- Clock drift
-- Day, month and year
-- Timezone
-- Daylight savings
-
-Difference to correct time: %s."""
- )
- % diffText
- )
+ warn = tr(TR.QT_MISC_IN_ORDER_TO_ENSURE_YOUR_COLLECTION, val="%s") % diffText
showWarning(warn)
self.app.closeAllWindows()
@@ -1281,13 +1235,7 @@ Difference to correct time: %s."""
self._activeWindowOnPlay: Optional[QWidget] = None
def onOdueInvalid(self):
- showWarning(
- _(
- """\
-Invalid property found on card. Please use Tools>Check Database, \
-and if the problem comes up again, please ask on the support site."""
- )
- )
+ showWarning(tr(TR.QT_MISC_INVALID_PROPERTY_FOUND_ON_CARD_PLEASE))
def _isVideo(self, tag: AVTag) -> bool:
if isinstance(tag, SoundOrVideoTag):
@@ -1336,15 +1284,7 @@ and if the problem comes up again, please ask on the support site."""
progress_shown = self.progress.busy()
if progress_shown:
self.progress.finish()
- ret = askUser(
- _(
- """\
-The requested change will require a full upload of the database when \
-you next synchronize your collection. If you have reviews or other changes \
-waiting on another device that haven't been synchronized here yet, they \
-will be lost. Continue?"""
- )
- )
+ ret = askUser(tr(TR.QT_MISC_THE_REQUESTED_CHANGE_WILL_REQUIRE_A))
if progress_shown:
self.progress.start()
return ret
@@ -1355,15 +1295,7 @@ will be lost. Continue?"""
True if confirmed or already modified."""
if self.col.schemaChanged():
return True
- return askUser(
- _(
- """\
-The requested change will require a full upload of the database when \
-you next synchronize your collection. If you have reviews or other changes \
-waiting on another device that haven't been synchronized here yet, they \
-will be lost. Continue?"""
- )
- )
+ return askUser(tr(TR.QT_MISC_THE_REQUESTED_CHANGE_WILL_REQUIRE_A))
# Advanced features
##########################################################################
@@ -1603,10 +1535,7 @@ will be lost. Continue?"""
# we can't raise the main window while in profile dialog, syncing, etc
if buf != "raise":
showInfo(
- _(
- """\
-Please ensure a profile is open and Anki is not busy, then try again."""
- ),
+ tr(TR.QT_MISC_PLEASE_ENSURE_A_PROFILE_IS_OPEN),
parent=None,
)
return None
diff --git a/qt/aqt/models.py b/qt/aqt/models.py
index 12d7f05f4..9c07f876c 100644
--- a/qt/aqt/models.py
+++ b/qt/aqt/models.py
@@ -7,7 +7,6 @@ from typing import Any, List, Optional, Sequence
import aqt.clayout
from anki import stdmodels
from anki.backend_pb2 import NoteTypeNameIDUseCount
-from anki.lang import _, ngettext
from anki.models import NoteType
from anki.notes import Note
from anki.rsbackend import pb
diff --git a/qt/aqt/overview.py b/qt/aqt/overview.py
index b11cddf53..6c635087c 100644
--- a/qt/aqt/overview.py
+++ b/qt/aqt/overview.py
@@ -183,20 +183,9 @@ class Overview:
def _desc(self, deck):
if deck["dyn"]:
- desc = _(
- """\
-This is a special deck for studying outside of the normal schedule."""
- )
- desc += " " + _(
- """\
-Cards will be automatically returned to their original decks after you review \
-them."""
- )
- desc += " " + _(
- """\
-Deleting this deck from the deck list will return all remaining cards \
-to their original deck."""
- )
+ desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR)
+ desc += " " + tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO)
+ desc += " " + tr(TR.STUDYING_DELETING_THIS_DECK_FROM_THE_DECK)
else:
desc = deck.get("desc", "")
if not desc:
diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py
index fb49246db..a1e2f2090 100644
--- a/qt/aqt/preferences.py
+++ b/qt/aqt/preferences.py
@@ -181,11 +181,7 @@ class Preferences(QDialog):
self.form.syncDeauth.setVisible(False)
self.form.syncUser.setText("")
self.form.syncLabel.setText(
- _(
- """\
-Synchronization
-Not currently enabled; click the sync button in the main window to enable."""
- )
+ tr(TR.PREFERENCES_SYNCHRONIZATIONNOT_CURRENTLY_ENABLED_CLICK_THE_SYNC)
)
def onSyncDeauth(self) -> None:
diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py
index e9e87d152..8b8e2f31d 100644
--- a/qt/aqt/profiles.py
+++ b/qt/aqt/profiles.py
@@ -253,11 +253,7 @@ class ProfileManager:
QMessageBox.warning(
None,
tr(TR.PROFILES_PROFILE_CORRUPT),
- _(
- """\
-Anki could not read your profile data. Window sizes and your sync login \
-details have been forgotten."""
- ),
+ tr(TR.PROFILES_ANKI_COULD_NOT_READ_YOUR_PROFILE),
)
traceback.print_stack()
print("resetting corrupt profile")
@@ -322,14 +318,7 @@ details have been forgotten."""
except Exception as e:
self.db.rollback()
if "WinError 5" in str(e):
- showWarning(
- _(
- """\
-Anki could not rename your profile because it could not rename the profile \
-folder on disk. Please ensure you have permission to write to Documents/Anki \
-and no other programs are accessing your profile folders, then try again."""
- )
- )
+ showWarning(tr(TR.PROFILES_ANKI_COULD_NOT_RENAME_YOUR_PROFILE))
else:
raise
except:
diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py
index 7b81e92ed..87d64d9a6 100644
--- a/qt/aqt/reviewer.py
+++ b/qt/aqt/reviewer.py
@@ -14,7 +14,6 @@ from PyQt5.QtCore import Qt
from anki import hooks
from anki.cards import Card
-from anki.lang import _, ngettext
from anki.utils import stripHTML
from aqt import AnkiQt, gui_hooks
from aqt.qt import *
@@ -388,10 +387,7 @@ class Reviewer:
if not self.typeCorrect:
if self.typeCorrect is None:
if clozeIdx:
- warn = _(
- """\
-Please run Tools>Empty Cards"""
- )
+ warn = tr(TR.STUDYING_PLEASE_RUN_TOOLSEMPTY_CARDS)
else:
warn = tr(TR.STUDYING_TYPE_ANSWER_UNKNOWN_FIELD, val=fld)
return re.sub(self.typeAnsPat, warn, buf)
diff --git a/qt/po/scripts/rewrite-refs.py b/qt/po/scripts/rewrite-refs.py
index 5bcfce179..e8a6c06f7 100644
--- a/qt/po/scripts/rewrite-refs.py
+++ b/qt/po/scripts/rewrite-refs.py
@@ -3,13 +3,10 @@
import glob, re, json, stringcase
files = (
- # glob.glob("../../pylib/**/*.py", recursive=True)
+ # glob.glob("../../pylib/**/*.py", recursive=True) +
glob.glob("../../qt/**/*.py", recursive=True)
- # glob.glob("../../qt/**/forms/*.ui", recursive=True)
-)
-string_re = re.compile(
- r'ngettext\(\s*"(.+?)",\s+".+?",\s+(.+?)\s*,?\s*\)\s+%\s+\2', re.DOTALL
)
+string_re = re.compile(r'_\(\s*(".*?")\s*\)', re.DOTALL)
map = json.load(open("keys_by_text.json"))
@@ -18,67 +15,29 @@ blacklist = {
"Label1",
"After pressing OK, you can choose which tags to include.",
"Filter/Cram",
- "Show %s",
- "~",
- "about:blank",
- "%d card imported.",
- # need to update manually
- "Browse (%(cur)d card shown; %(sel)s)",
# previewer.py needs updating to fix these
"Shortcut key: R",
"Shortcut key: B",
}
-from html.entities import name2codepoint
-
-reEnts = re.compile(r"?\w+;")
-
-
-def decode_ents(html):
- def fixup(m):
- text = m.group(0)
- if text[:2] == "":
- # character reference
- try:
- if text[:3] == "":
- return chr(int(text[3:-1], 16))
- else:
- return chr(int(text[2:-1]))
- except ValueError:
- pass
- else:
- # named entity
- try:
- text = chr(name2codepoint[text[1:-1]])
- except KeyError:
- pass
- return text # leave as is
-
- return reEnts.sub(fixup, html)
-
-
-def munge_key(key):
- if key == "browsing-note":
- return "browsing-note-count"
- if key == "card-templates-card":
- return "card-templates-card-count"
- return key
-
def repl(m):
- print(m.group(0))
- text = decode_ents(m.group(1))
+ # the argument may consistent of multiple strings that need merging together
+ text = eval("(" + m.group(1) + ")")
+ print(f"text is `{text}`")
+
if text in blacklist:
return m.group(0)
(module, key) = map[text]
- key = munge_key(key)
-
screaming = stringcase.constcase(key)
+ print(screaming)
- ret = f"tr(TR.{screaming}, count={m.group(2)})"
- print(ret)
- return ret
+ if "%d" in text or "%s" in text:
+ # replace { $val } with %s for compat with old code
+ return f'tr(TR.{screaming}, val="%s")'
+
+ return f"tr(TR.{screaming})"
for file in files: