update multi-line _() references

This commit is contained in:
Damien Elmes 2020-11-18 11:32:22 +10:00
parent b49805fef5
commit ba336d5de3
20 changed files with 57 additions and 315 deletions

View file

@ -93,14 +93,8 @@ def show(mw):
# 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 += "<p>" + _( abouttext += "<p>" + tr(TR.ABOUT_ANKI_IS_A_FRIENDLY_INTELLIGENT_SPACED)
"Anki is a friendly, intelligent spaced learning \ abouttext += "<p>" + tr(TR.ABOUT_ANKI_IS_LICENSED_UNDER_THE_AGPL3)
system. It's free and open source."
)
abouttext += "<p>" + _(
"Anki is licensed under the AGPL3 license. Please see "
"the license file in the source distribution for more information."
)
abouttext += "<p>" + tr(TR.ABOUT_VERSION, val=versionWithBuild()) + "<br>" abouttext += "<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(),
@ -209,22 +203,11 @@ system. It's free and open source."
) )
) )
abouttext += ( abouttext += "<p>" + tr(TR.ABOUT_WRITTEN_BY_DAMIEN_ELMES_WITH_PATCHES) % {
"<p>" "cont": ", ".join(allusers)
+ _( }
"Written by Damien Elmes, with patches, translation,\ abouttext += "<p>" + tr(TR.ABOUT_IF_YOU_HAVE_CONTRIBUTED_AND_ARE)
testing and design from:<p>%(cont)s" abouttext += "<p>" + tr(TR.ABOUT_A_BIG_THANKS_TO_ALL_THE)
)
% {"cont": ", ".join(allusers)}
)
abouttext += "<p>" + _(
"If you have contributed and are not on this list, \
please get in touch."
)
abouttext += "<p>" + _(
"A big thanks to all the people who have provided \
suggestions, bug reports and donations."
)
abt.label.setMinimumWidth(800) abt.label.setMinimumWidth(800)
abt.label.setMinimumHeight(600) abt.label.setMinimumHeight(600)
dialog.show() dialog.show()

View file

@ -175,12 +175,7 @@ class AddCards(QDialog):
return None return None
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( if not askUser(tr(TR.ADDING_YOU_HAVE_A_CLOZE_DELETION_NOTE)):
_(
"You have a cloze deletion note type "
"but have not made any cloze deletions. Proceed?"
)
):
return None return None
self.mw.col.add_note(note, self.deckChooser.selectedId()) self.mw.col.add_note(note, self.deckChooser.selectedId())
self.mw.col.clearUndo() self.mw.col.clearUndo()

View file

@ -836,12 +836,7 @@ class AddonsDialog(QDialog):
if not selected: if not selected:
return return
if not askUser( if not askUser(
ngettext( tr(TR.ADDONS_DELETE_THE_NUMD_SELECTED_ADDON, count=len(selected))
"Delete the %(num)d selected add-on?",
"Delete the %(num)d selected add-ons?",
len(selected),
)
% dict(num=len(selected))
): ):
return return
for dir in selected: for dir in selected:

View file

@ -17,7 +17,6 @@ import aqt.forms
from anki.cards import Card from anki.cards import Card
from anki.collection import Collection from anki.collection import Collection
from anki.consts import * from anki.consts import *
from anki.lang import _, ngettext
from anki.models import NoteType from anki.models import NoteType
from anki.notes import Note from anki.notes import Note
from anki.rsbackend import TR, DeckTreeNode, InvalidInput from anki.rsbackend import TR, DeckTreeNode, InvalidInput
@ -821,16 +820,10 @@ class Browser(QMainWindow):
def updateTitle(self): def updateTitle(self):
selected = len(self.form.tableView.selectionModel().selectedRows()) selected = len(self.form.tableView.selectionModel().selectedRows())
cur = len(self.model.cards) cur = len(self.model.cards)
print("fixme: browser updateTitle()")
self.setWindowTitle( self.setWindowTitle(
ngettext( "Browse (%(cur)d cards shown; %(sel)s)"
"Browse (%(cur)d card shown; %(sel)s)", % {"cur": cur, "sel": self.col.tr(TR.BROWSING_SELECTED, count=selected)}
"Browse (%(cur)d cards shown; %(sel)s)",
cur,
)
% {
"cur": cur,
"sel": ngettext("%d selected", "%d selected", selected) % selected,
}
) )
return selected return selected
@ -2266,14 +2259,7 @@ 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( if not askUser(tr(TR.BROWSING_ANY_CARDS_MAPPED_TO_NOTHING_WILL)):
_(
"""\
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?"""
)
):
return return
self.browser.mw.checkpoint(tr(TR.BROWSING_CHANGE_NOTE_TYPE)) self.browser.mw.checkpoint(tr(TR.BROWSING_CHANGE_NOTE_TYPE))
b = self.browser b = self.browser

View file

@ -9,7 +9,6 @@ from typing import Any, Dict, List, Optional
import aqt import aqt
from anki.cards import Card from anki.cards import Card
from anki.consts import * from anki.consts import *
from anki.lang import _, ngettext
from anki.notes import Note from anki.notes import Note
from anki.rsbackend import TemplateError from anki.rsbackend import TemplateError
from anki.template import TemplateRenderContext from anki.template import TemplateRenderContext
@ -656,13 +655,7 @@ class CardLayout(QDialog):
def _flipQA(self, src, dst): def _flipQA(self, src, dst):
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( showInfo(tr(TR.CARD_TEMPLATES_ANKI_COULDNT_FIND_THE_LINE_BETWEEN))
_(
"""\
Anki couldn't find the line between the question and answer. Please \
adjust the template manually to switch the question and answer."""
)
)
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"]
@ -736,10 +729,7 @@ adjust the template manually to switch the question and answer."""
d.setMinimumWidth(400) d.setMinimumWidth(400)
l = QVBoxLayout() l = QVBoxLayout()
lab = QLabel( lab = QLabel(
_( tr(TR.CARD_TEMPLATES_ENTER_DECK_TO_PLACE_NEW, val="%s")
"""\
Enter deck to place new %s cards in, or leave blank:"""
)
% self.current_template()["name"] % self.current_template()["name"]
) )
lab.setWordWrap(True) lab.setWordWrap(True)

View file

@ -8,7 +8,6 @@ from dataclasses import dataclass
import aqt import aqt
from anki.errors import DeckRenameError from anki.errors import DeckRenameError
from anki.lang import _, ngettext
from anki.rsbackend import TR, DeckTreeNode from anki.rsbackend import TR, DeckTreeNode
from anki.utils import ids2str from anki.utils import ids2str
from aqt import AnkiQt, gui_hooks from aqt import AnkiQt, gui_hooks

View file

@ -8,7 +8,6 @@ from PyQt5.QtWidgets import QLineEdit
import aqt import aqt
from anki.consts import NEW_CARDS_RANDOM from anki.consts import NEW_CARDS_RANDOM
from anki.lang import _, ngettext
from aqt import gui_hooks from aqt import gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.utils import ( from aqt.utils import (
@ -110,10 +109,7 @@ 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 = _( txt = tr(TR.SCHEDULING_YOUR_CHANGES_WILL_AFFECT_MULTIPLE_DECKS)
"Your changes will affect multiple decks. If you wish to "
"change only the current deck, please add a new options group first."
)
else: else:
txt = "" txt = ""
self.form.count.setText(txt) self.form.count.setText(txt)

View file

@ -123,13 +123,7 @@ class DeckConf(QDialog):
if not self.saveConf(): if not self.saveConf():
return return
if not self.mw.col.sched.rebuild_filtered_deck(self.deck["id"]): if not self.mw.col.sched.rebuild_filtered_deck(self.deck["id"]):
if askUser( if askUser(tr(TR.DECKS_THE_PROVIDED_SEARCH_DID_NOT_MATCH)):
_(
"""\
The provided search did not match any cards. Would you like to revise \
it?"""
)
):
return return
self.mw.reset() self.mw.reset()
QDialog.accept(self) QDialog.accept(self)

View file

@ -658,20 +658,9 @@ class Editor:
# check that the model is set up for cloze deletion # check that the model is set up for cloze deletion
if not re.search("{{(.*:)*cloze:", self.note.model()["tmpls"][0]["qfmt"]): if not re.search("{{(.*:)*cloze:", self.note.model()["tmpls"][0]["qfmt"]):
if self.addMode: if self.addMode:
tooltip( tooltip(tr(TR.EDITING_WARNING_CLOZE_DELETIONS_WILL_NOT_WORK))
_(
"Warning, cloze deletions will not work until "
"you switch the type at the top to Cloze."
)
)
else: else:
showInfo( showInfo(tr(TR.EDITING_TO_MAKE_A_CLOZE_DELETION_ON))
_(
"""\
To make a cloze deletion on an existing note, you need to change it \
to a cloze type first, via 'Notes>Change Note Type'"""
)
)
return return
# find the highest existing cloze # find the highest existing cloze
highest = 0 highest = 0

View file

@ -65,10 +65,7 @@ class ErrorHandler(QObject):
self.timer.start() self.timer.start()
def tempFolderMsg(self): def tempFolderMsg(self):
return _( return tr(TR.QT_MISC_UNABLE_TO_ACCESS_ANKI_MEDIA_FOLDER)
"""Unable to access Anki media folder. The permissions on \
your system's temporary folder may be incorrect."""
)
def onTimeout(self): def onTimeout(self):
error = html.escape(self.pool) error = html.escape(self.pool)
@ -79,12 +76,7 @@ your system's temporary folder may be incorrect."""
if "10013" in error: if "10013" in error:
return showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS)) return showWarning(tr(TR.QT_MISC_YOUR_FIREWALL_OR_ANTIVIRUS_PROGRAM_IS))
if "no default input" in error.lower(): if "no default input" in error.lower():
return showWarning( return showWarning(tr(TR.QT_MISC_PLEASE_CONNECT_A_MICROPHONE_AND_ENSURE))
_(
"Please connect a microphone, and ensure "
"other programs are not using the audio device."
)
)
if "invalidTempFolder" in error: if "invalidTempFolder" in error:
return showWarning(self.tempFolderMsg()) return showWarning(self.tempFolderMsg())
if "Beautiful Soup is not an HTTP client" in error: if "Beautiful Soup is not an HTTP client" in error:

View file

@ -12,7 +12,6 @@ from typing import List, Optional
import aqt import aqt
from anki import hooks from anki import hooks
from anki.exporting import Exporter, exporters from anki.exporting import Exporter, exporters
from anki.lang import _, ngettext
from aqt.qt import * from aqt.qt import *
from aqt.utils import TR, checkInvalidFilename, getSaveFile, showWarning, tooltip, tr from aqt.utils import TR, checkInvalidFilename, getSaveFile, showWarning, tooltip, tr

View file

@ -3,7 +3,6 @@
import aqt import aqt
from anki.consts import * from anki.consts import *
from anki.lang import _, ngettext
from anki.models import NoteType from anki.models import NoteType
from anki.rsbackend import TemplateError from anki.rsbackend import TemplateError
from aqt import AnkiQt, gui_hooks from aqt import AnkiQt, gui_hooks

View file

@ -15,7 +15,6 @@ import anki.importing as importing
import aqt.deckchooser import aqt.deckchooser
import aqt.forms import aqt.forms
import aqt.modelchooser import aqt.modelchooser
from anki.lang import _, ngettext
from aqt import AnkiQt, gui_hooks from aqt import AnkiQt, gui_hooks
from aqt.qt import * from aqt.qt import *
from aqt.utils import ( from aqt.utils import (
@ -118,12 +117,7 @@ class ImportDialog(QDialog):
def onDelimiter(self): def onDelimiter(self):
str = ( str = (
getOnlyText( getOnlyText(
_( tr(TR.IMPORTING_BY_DEFAULT_ANKI_WILL_DETECT_THE),
"""\
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."""
),
self, self,
help="importing", help="importing",
) )
@ -132,10 +126,7 @@ you can enter it here. Use \\t to represent tab."""
str = str.replace("\\t", "\t") str = str.replace("\\t", "\t")
if len(str) > 1: if len(str) > 1:
showWarning( showWarning(
_( tr(TR.IMPORTING_MULTICHARACTER_SEPARATORS_ARE_NOT_SUPPORTED_PLEASE)
"Multi-character separators are not supported. "
"Please enter one character only."
)
) )
return return
self.hideMapping() self.hideMapping()
@ -297,12 +288,7 @@ you can enter it here. Use \\t to represent tab."""
def showUnicodeWarning(): def showUnicodeWarning():
"""Shorthand to show a standard warning.""" """Shorthand to show a standard warning."""
showWarning( showWarning(tr(TR.IMPORTING_SELECTED_FILE_WAS_NOT_IN_UTF8))
_(
"Selected file was not in UTF-8 format. Please see the "
"importing section of the manual."
)
)
def onImport(mw): def onImport(mw):
@ -390,20 +376,12 @@ def importFile(mw, file):
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 = _( msg = tr(TR.IMPORTING_INVALID_FILE_PLEASE_RESTORE_FROM_BACKUP)
"""\
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( showWarning(tr(TR.IMPORTING_UNABLE_TO_IMPORT_FROM_A_READONLY))
_(
"""\
Unable to import from a read-only file."""
)
)
else: else:
msg = tr(TR.IMPORTING_FAILED_DEBUG_INFO) + "\n" msg = tr(TR.IMPORTING_FAILED_DEBUG_INFO) + "\n"
msg += str(traceback.format_exc()) msg += str(traceback.format_exc())
@ -421,13 +399,7 @@ Unable to import from a read-only file."""
def invalidZipMsg(): def invalidZipMsg():
return _( return tr(TR.IMPORTING_THIS_FILE_DOES_NOT_APPEAR_TO)
"""\
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."""
)
def setupApkgImport(mw, importer): def setupApkgImport(mw, importer):
@ -441,11 +413,7 @@ def setupApkgImport(mw, importer):
# 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),
"""\
This will delete your existing collection and replace it with the data in \
the file you're importing. Are you sure?"""
),
msgfunc=QMessageBox.warning, msgfunc=QMessageBox.warning,
defaultno=True, defaultno=True,
): ):

View file

@ -29,7 +29,6 @@ from anki import hooks
from anki.collection import Collection from anki.collection import Collection
from anki.decks import Deck from anki.decks import Deck
from anki.hooks import runHook from anki.hooks import runHook
from anki.lang import _, ngettext
from anki.rsbackend import RustBackend from anki.rsbackend import RustBackend
from anki.sound import AVTag, SoundOrVideoTag from anki.sound import AVTag, SoundOrVideoTag
from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields from anki.utils import devMode, ids2str, intTime, isMac, isWin, splitFields
@ -123,12 +122,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( tooltip(tr(TR.QT_MISC_SHIFT_KEY_WAS_HELD_DOWN_SKIPPING))
_(
"Shift key was held down. Skipping automatic "
"syncing and add-on loading."
)
)
# 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])
@ -319,11 +313,7 @@ class AnkiQt(QMainWindow):
return showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE)) return showWarning(tr(TR.QT_MISC_THERE_MUST_BE_AT_LEAST_ONE))
# sure? # sure?
if not askUser( if not askUser(
_( tr(TR.QT_MISC_ALL_CARDS_NOTES_AND_MEDIA_FOR),
"""\
All cards, notes, and media for this profile will be deleted. \
Are you sure?"""
),
msgfunc=QMessageBox.warning, msgfunc=QMessageBox.warning,
defaultno=True, defaultno=True,
): ):
@ -333,10 +323,7 @@ Are you sure?"""
def onOpenBackup(self): def onOpenBackup(self):
if not askUser( if not askUser(
_( tr(TR.QT_MISC_REPLACE_YOUR_COLLECTION_WITH_AN_EARLIER),
"""\
Replace your collection with an earlier backup?"""
),
msgfunc=QMessageBox.warning, msgfunc=QMessageBox.warning,
defaultno=True, defaultno=True,
): ):
@ -364,13 +351,7 @@ Replace your collection with an earlier backup?"""
self.pendingImport = path self.pendingImport = path
self.restoringBackup = True self.restoringBackup = True
showInfo( showInfo(tr(TR.QT_MISC_AUTOMATIC_SYNCING_AND_BACKUPS_HAVE_BEEN))
_(
"""\
Automatic syncing and backups have been disabled while restoring. To enable them again, \
close the profile or restart Anki."""
)
)
self.onOpenProfile() self.onOpenProfile()
@ -568,15 +549,7 @@ close the profile or restart Anki."""
self.col = None self.col = None
self.progress.finish() self.progress.finish()
if corrupt: if corrupt:
showWarning( showWarning(tr(TR.QT_MISC_YOUR_COLLECTION_FILE_APPEARS_TO_BE))
_(
"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."
)
)
if not corrupt and not self.restoringBackup: if not corrupt and not self.restoringBackup:
self.backup() self.backup()
@ -1218,26 +1191,7 @@ title="%s" %s>%s</button>""" % (
print("clock is off; ignoring") print("clock is off; ignoring")
return return
diffText = tr(TR.QT_MISC_SECOND, count=diff) diffText = tr(TR.QT_MISC_SECOND, count=diff)
warn = ( warn = tr(TR.QT_MISC_IN_ORDER_TO_ENSURE_YOUR_COLLECTION, val="%s") % diffText
_(
"""\
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
)
showWarning(warn) showWarning(warn)
self.app.closeAllWindows() self.app.closeAllWindows()
@ -1281,13 +1235,7 @@ Difference to correct time: %s."""
self._activeWindowOnPlay: Optional[QWidget] = None self._activeWindowOnPlay: Optional[QWidget] = None
def onOdueInvalid(self): def onOdueInvalid(self):
showWarning( showWarning(tr(TR.QT_MISC_INVALID_PROPERTY_FOUND_ON_CARD_PLEASE))
_(
"""\
Invalid property found on card. Please use Tools>Check Database, \
and if the problem comes up again, please ask on the support site."""
)
)
def _isVideo(self, tag: AVTag) -> bool: def _isVideo(self, tag: AVTag) -> bool:
if isinstance(tag, SoundOrVideoTag): 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() progress_shown = self.progress.busy()
if progress_shown: if progress_shown:
self.progress.finish() self.progress.finish()
ret = askUser( ret = askUser(tr(TR.QT_MISC_THE_REQUESTED_CHANGE_WILL_REQUIRE_A))
_(
"""\
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?"""
)
)
if progress_shown: if progress_shown:
self.progress.start() self.progress.start()
return ret return ret
@ -1355,15 +1295,7 @@ will be lost. Continue?"""
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( return askUser(tr(TR.QT_MISC_THE_REQUESTED_CHANGE_WILL_REQUIRE_A))
_(
"""\
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?"""
)
)
# Advanced features # Advanced features
########################################################################## ##########################################################################
@ -1603,10 +1535,7 @@ will be lost. Continue?"""
# 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),
"""\
Please ensure a profile is open and Anki is not busy, then try again."""
),
parent=None, parent=None,
) )
return None return None

View file

@ -7,7 +7,6 @@ from typing import Any, List, Optional, Sequence
import aqt.clayout import aqt.clayout
from anki import stdmodels from anki import stdmodels
from anki.backend_pb2 import NoteTypeNameIDUseCount from anki.backend_pb2 import NoteTypeNameIDUseCount
from anki.lang import _, ngettext
from anki.models import NoteType from anki.models import NoteType
from anki.notes import Note from anki.notes import Note
from anki.rsbackend import pb from anki.rsbackend import pb

View file

@ -183,20 +183,9 @@ class Overview:
def _desc(self, deck): def _desc(self, deck):
if deck["dyn"]: if deck["dyn"]:
desc = _( desc = tr(TR.STUDYING_THIS_IS_A_SPECIAL_DECK_FOR)
"""\ desc += " " + tr(TR.STUDYING_CARDS_WILL_BE_AUTOMATICALLY_RETURNED_TO)
This is a special deck for studying outside of the normal schedule.""" desc += " " + tr(TR.STUDYING_DELETING_THIS_DECK_FROM_THE_DECK)
)
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."""
)
else: else:
desc = deck.get("desc", "") desc = deck.get("desc", "")
if not desc: if not desc:

View file

@ -181,11 +181,7 @@ class Preferences(QDialog):
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)
"""\
<b>Synchronization</b><br>
Not currently enabled; click the sync button in the main window to enable."""
)
) )
def onSyncDeauth(self) -> None: def onSyncDeauth(self) -> None:

View file

@ -253,11 +253,7 @@ class ProfileManager:
QMessageBox.warning( QMessageBox.warning(
None, None,
tr(TR.PROFILES_PROFILE_CORRUPT), tr(TR.PROFILES_PROFILE_CORRUPT),
_( tr(TR.PROFILES_ANKI_COULD_NOT_READ_YOUR_PROFILE),
"""\
Anki could not read your profile data. Window sizes and your sync login \
details have been forgotten."""
),
) )
traceback.print_stack() traceback.print_stack()
print("resetting corrupt profile") print("resetting corrupt profile")
@ -322,14 +318,7 @@ details have been forgotten."""
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( showWarning(tr(TR.PROFILES_ANKI_COULD_NOT_RENAME_YOUR_PROFILE))
_(
"""\
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."""
)
)
else: else:
raise raise
except: except:

View file

@ -14,7 +14,6 @@ from PyQt5.QtCore import Qt
from anki import hooks from anki import hooks
from anki.cards import Card from anki.cards import Card
from anki.lang import _, ngettext
from anki.utils import stripHTML from anki.utils import stripHTML
from aqt import AnkiQt, gui_hooks from aqt import AnkiQt, gui_hooks
from aqt.qt import * from aqt.qt import *
@ -388,10 +387,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 = _( warn = tr(TR.STUDYING_PLEASE_RUN_TOOLSEMPTY_CARDS)
"""\
Please run Tools>Empty 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)

View file

@ -3,13 +3,10 @@
import glob, re, json, stringcase import glob, re, json, stringcase
files = ( files = (
# glob.glob("../../pylib/**/*.py", recursive=True) # glob.glob("../../pylib/**/*.py", recursive=True) +
glob.glob("../../qt/**/*.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")) map = json.load(open("keys_by_text.json"))
@ -18,67 +15,29 @@ blacklist = {
"Label1", "Label1",
"After pressing OK, you can choose which tags to include.", "After pressing OK, you can choose which tags to include.",
"Filter/Cram", "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 # previewer.py needs updating to fix these
"Shortcut key: R", "Shortcut key: R",
"Shortcut key: B", "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] == "&#x":
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): def repl(m):
print(m.group(0)) # the argument may consistent of multiple strings that need merging together
text = decode_ents(m.group(1)) text = eval("(" + m.group(1) + ")")
print(f"text is `{text}`")
if text in blacklist: if text in blacklist:
return m.group(0) return m.group(0)
(module, key) = map[text] (module, key) = map[text]
key = munge_key(key)
screaming = stringcase.constcase(key) screaming = stringcase.constcase(key)
print(screaming)
ret = f"tr(TR.{screaming}, count={m.group(2)})" if "%d" in text or "%s" in text:
print(ret) # replace { $val } with %s for compat with old code
return ret return f'tr(TR.{screaming}, val="%s")'
return f"tr(TR.{screaming})"
for file in files: for file in files: