def __init__(self, model): super().__init__(model) self.builder = model.builder self.treestore = self.builder.get_object("ts_styles") self.treeview = self.builder.get_object("tv_Styles") self.treeview.set_model(self.treestore) cr = Gtk.CellRendererText() tvc = Gtk.TreeViewColumn("Marker", cr, text=1) self.treeview.append_column(tvc) tself = self.treeview.get_selection() tself.connect("changed", self.onSelected) self.treeview.set_search_equal_func(self.tree_search) searchentry = self.builder.get_object("t_styleSearch") self.treeview.set_search_entry(searchentry) #self.treeview.set_enable_search(True) for k, v in stylemap.items(): if v[0].startswith("l_") or k in dialogKeys: continue w = self.builder.get_object(v[0]) #key = stylediverts.get(k, k) (pref, name) = v[0].split("_", 1) signal = widgetsignals.get(pref, "changed") if signal is not None: w.connect(signal, self.item_changed, k) # if v[0].startswith("s_"): # w.connect("focus-out-event", self.item_changed, k) self.isLoading = False self.stylediverts = { "LineSpacing": ("_linespacing", _("Line Spacing\nFactor:"), _("Baseline:")), "FontSize": ("_fontsize", _("Font Size\nFactor:"), _("Font Scale:")) }
def mask_media(self, row): src = row[_pickeys['src']][:2] inf = self.parent.copyrightInfo['copyrights'].get( src.lower(), { "media": { "default": "paw", "limit": "paw", "tip": { "en": "Default" } } })["media"] tip = inf["tip"].get(getlang()[0], inf["tip"]["en"]) if inf["tip"]["en"] == 'Default': self.builder.get_object("l_plMedia").set_tooltip_text( _("Media permissions unknown\nfor this illustration")) else: self.builder.get_object("l_plMedia").set_tooltip_text( _("Permission for {} series:\n{}").format(src.upper(), tip)) val = row[_pickeys['media']] for c in 'paw': w = _form_structure["med" + c.upper()] wid = self.builder.get_object(w) if val is None or val == "": isactive = c in inf["default"] # isactive = False # c in inf["limit"] else: isactive = c in val if wid is not None: wid.set_sensitive(c in inf["limit"]) wid.set_active(isactive)
def carefulCopy(self, ratio, srcpath, tgtfile, cropme): tmpPicPath = os.path.join(self.printer.working_dir, "tmpPics") tgtpath = os.path.join(tmpPicPath, tgtfile) if os.path.splitext(srcpath)[1].lower().startswith(".pdf"): copyfile(srcpath, tgtpath) return os.path.basename(tgtpath) try: im = Image.open(srcpath) iw = im.size[0] ih = im.size[1] except OSError: print(("Failed to get size of (image) file:"), srcpath) # If either the source image is a TIF (or) the proportions aren't right for page dimensions # then we first need to convert to a JPG and/or pad with which space on either side if cropme or self.ispdfxa != "None" or (ratio is not None and iw/ih < ratio) \ or os.path.splitext(srcpath)[1].lower().startswith(".tif"): # (.tif or .tiff) tgtpath = os.path.splitext(tgtpath)[0] + ".jpg" try: self.convertToJPGandResize(ratio, srcpath, tgtpath, cropme) except: # MH: Which exception should I try to catch? print( _("Error: Unable to convert/resize image!\nImage skipped:" ), srcpath) return os.path.basename(tgtpath) else: try: copyfile(srcpath, tgtpath) except OSError: print( _("Error: Unable to copy {}\n image to {} in tmpPics folder" ), srcpath, tgtpath) return os.path.basename(tgtpath) return os.path.basename(tgtpath)
def removeTempFiles(self, texfiles): notDeleted = [] # MH: Should we try to remove the generated Nested files (now that they are stored along with the config)? # What impact does that have on Paratext's S/R (cluttering) # n = os.path.join(self.tmpdir, "NestedStyles.sty") # if os.path.exists(n): # try: # os.remove(n) # except: # notDeleted += [n] for extn in ('delayed', 'parlocs', 'notepages', 'SFM', 'sfm', 'xdv', 'tex', 'log'): for t in set(texfiles): delfname = os.path.join(self.tmpdir, t.replace(".tex", "." + extn)) if os.path.exists(delfname): try: os.remove(delfname) except OSError: notDeleted += [delfname] for f in self.books: delfname = os.path.join(self.tmpdir, f) if os.path.exists(delfname): try: os.remove(delfname) except OSError: notDeleted += [delfname] #folderList = ["tmpPics", "tmpPicLists"] #notDeleted += self.removeTmpFolders(self.tmpdir, folderList) if len(notDeleted): self.printer.doError(_( "Warning: Could not delete\ntemporary file(s) or folder(s):"), secondary="\n".join(set(notDeleted)))
def done_job(self, outfname, pdfname, info): # Work out what the resulting PDF was called logger.debug(f"done_job: {outfname}, {pdfname}") cfgname = info['config/name'] if cfgname is not None and cfgname != "": cfgname = "-" + cfgname else: cfgname = "" if pdfname is not None: print(pdfname) if self.res == 0: if not self.noview and self.printer.isDisplay and os.path.exists( pdfname): if sys.platform == "win32": os.startfile(pdfname) elif sys.platform == "linux": subprocess.call(('xdg-open', pdfname)) # Only delete the temp files if the PDF was created AND the user did NOT select to keep them if not self.noview and not self.args.print: # We don't want pop-up messages if running in command-line mode fname = os.path.join(self.tmpdir, pdfname.replace(".pdf", ".log")) if os.path.exists(fname): with open(fname, "r", encoding="utf-8", errors="ignore") as logfile: log = logfile.read( ) # unlike other places, we *do* want the entire log file badpgs = re.findall( r'(?i)SOMETHING BAD HAPPENED on page (\d+)\.', "".join(log)) if len(badpgs): print( _("Layout problems were encountered on page(s): ") + ", ".join(badpgs)) self.printer.doError(_("PDF was created BUT..."), secondary=_("Layout problems were encountered on page(s): ") + ",".join(badpgs) + \ _("\n\nTry changing the PicList and/or AdjList settings to solve issues."), \ title=_("PTXprint [{}] - Warning!").format(VersionStr), threaded=True) elif not self.noview and not self.args.print: # We don't want pop-up messages if running in command-line mode finalLogLines = self.parseLogLines() self.printer.doError( _("Failed to create: ") + re.sub(r"\.tex", r".pdf", outfname), secondary="".join(finalLogLines[-20:]), title="PTXprint [{}] - Error!".format(VersionStr), threaded=True, copy2clip=True) self.printer.onIdle(self.printer.showLogFile) if len(self.rerunReasons): self.printer.set( "l_statusLine", _("Rerun to fix: ") + ", ".join(self.rerunReasons)) else: self.printer.set("l_statusLine", "") self.printer.finished() self.busy = False logger.debug("done_job: Finishing thread") unlockme()
def setFontButton(btn, value): btn.font_info = value if value is None: btn.set_label(_("Set Font...")) return style = getattr(value, 'style', None) if not style: styles = [] if "embolden" in value.feats: styles.append("(bold)") if "slant" in value.feats: styles.append("(italic)") style = " ".join(styles) btn.set_label("{}\n{}".format(value.name, style))
class mymr(ScriptSnippet): dialogstruct = [ MiniCheckButton("c_scrmymrSyllable", _("Syllable line breaking")) ] @classmethod def regexes(cls, model): res = [(None, re.compile(r'(\s)/'), r'\1'), (None, re.compile('([\u00AB\u2018\u201B\u201C\u201F\u2039\u2E02\u2E04\u2E09\u2E0C\u2E1C\u2E20])/'), r'\1', re.S), (None, re.compile('/([\u00BB\u2019\u201D\u203A\u2E03\u2E05\u2E0A\u2E0D\u2E1D\u2E21])'), r'\1', re.S), (None, re.compile('/([\\s\u104A\u104B])'), r'\1', re.S), (None, re.compile(r'/'), "\u200B")] if model["scripts/mymr/syllables"]: cons = "[\u1000-\u102A\u103F\u104C-\u1055\u105A-\u105D\u1061\u1065\u1066\u106E-\u1070\u1075-\u1081" + \ "\u108E\u109E\u109F\uA9E0-\uA9E4\uA9E7-\uA9EF\uA9F8-\uA9FE\uAA60-\uAA6F" + \ "\uAA71-\uAA7A\uAA7E\uAA7F]\uFE00?" ncons = "[\u102B-\u103E\u1056-\u1059\u105E-\u1060\u1062-\u1064\u1067-\u106D\u1071-\u1074" + \ "\u1082-\u108D\u108F\u109A-\u109D\uA9E5\uA9E6\uAA70\uAA7B-\uAA7D]" res += [(None, re.compile('(?<![\\s\u1039"\'\[\(\{{\u2018-\u201F])({0})(?![\\s\u1039\u103A])'.format(cons)), '\u200B\\1')] res += [(None, re.compile('(\u103A\u1039{0})\u200B'.format(cons)), r'\1')] res += [(None, re.compile('(\\s{0}(?:\u1039{0})*{1}*)\u200B'.format(cons, ncons)), r'\1')] return res
def checkForMissingDecorations(self, info): deco = { "pageborder": "Page Border", "sectionheader": "Section Heading", "endofbook": "End of Book", "versedecorator": "Verse Number" } warnings = [] if info.asBool("fancy/enableborders"): for k, v in deco.items(): if info.asBool("fancy/" + k): ftype = "fancy/{}type".format(k) if ftype not in info.dict or info[ftype] == "file": f = info.dict["fancy/{}pdf".format(k)] or "" if not os.path.exists(f): warnings += ["{} Decorator\n{}\n\n".format(v, f)] if info.asBool("paper/ifwatermark"): f = info["paper/watermarkpdf"] if not os.path.exists(f): warnings += ["Watermark\n{}\n\n".format(f)] if len(warnings): self.printer.doError( _("Warning: Could not locate decorative PDF(s):"), secondary="\n".join(warnings))
def mkrDialog(self, newkey=False): dialog = self.builder.get_object("dlg_styModsdialog") for k, v in dialogKeys.items(): if k == "OccursUnder": o = self.getval(self.marker, k, None) if o is not None: self.model.set(v, " ".join(sorted(str(x) for x in o))) else: self.model.set(v, "") else: self.model.set(v, self.getval(self.marker, k, '') or "") # print(f"setting {self.marker}:{k} = {self.getval(self.marker, k, '')}") self.model.set(dialogKeys['Marker'], '' if newkey else self.marker) wid = self.builder.get_object(dialogKeys['Marker']) if wid is not None: wid.set_sensitive(newkey) tryme = True while tryme: response = dialog.run() if response != Gtk.ResponseType.OK: break key = self.model.get(dialogKeys['Marker']).strip().replace("\\","") if key == "": break for a in ('StyleType', 'TextType', 'OccursUnder'): if not self.model.get(dialogKeys[a]): self.model.doError(_("Required element {} is not set. Please set it.").format(a)) break else: tryme = False if tryme: continue (d, selecti) = self.treeview.get_selection().get_selected() name = self.model.get(dialogKeys['Name'], '') if key not in self.sheet: self.sheet[key] = Marker({" deletable": True}) for k, v in stylemap.items(): if not k.startswith("_"): self.setval(key, k, self.getval(self.marker, k)) m = name_reg.match(name) if m: if not m.group(1) and " " in m.group(2): cat = m.group(2) else: cat = m.group(1) or m.group(3) else: cat = "Other" cat, url = categorymapping.get(cat, (cat, None)) self.sheet[key][' category'] = cat selecti = self.treestore.get_iter_first() while selecti: r = self.treestore[selecti] if r[0] == cat: selecti = self.treestore.append(selecti, [key, name, True]) break selecti = self.treestore.iter_next(selecti) else: selecti = self.treestore.append(None, [cat, cat, False]) selecti = self.treestore.append(selecti, [key, name, True]) else: self.treestore.set_value(selecti, 1, name) for k, v in dialogKeys.items(): if k == 'Marker': continue val = self.model.get(v).replace("\\","") # print(f"{k=} {v=} -> {val=}") if k.lower() == 'occursunder': val = set(val.split()) self.setval(key, k, val) st = self.getval(key, 'StyleType', '') if st == 'Character' or st == 'Note': self.setval(key, 'EndMarker', key + "*") if st == 'Character': ou = self.getval(key, 'OccursUnder') if not isinstance(ou, set): ou = set(ou.split()) ou.add("NEST") self.setval(key, 'OccursUnder', ou) self.resolveEndMarker(key, None) elif st == 'Milestone': self.resolveEndMarker(key, self.getval(key, 'EndMarker')) self.setval(key, 'EndMarker', None) self.marker = key self.treeview.get_selection().select_iter(selecti) dialog.hide()
def run_xetex(self, outfname, info): numruns = 0 cachedata = {} cacheexts = { "toc": (_("table of contents"), True), "picpages": (_("image copyrights"), False), "delayed": (_("chapter numbers"), True), "parlocs": (_("chapter positions"), True) } for a in cacheexts.keys(): cachedata[a] = self.readfile( os.path.join(self.tmpdir, outfname.replace(".tex", "." + a))) while numruns < self.maxRuns: self.printer.incrementProgress() commentstr = " ".join([ "date=" + datetime.today().isoformat(), "ptxprint_version=" + VersionStr, "run=" + str(numruns) ]) cmd = [ "xetex", "-halt-on-error", "-interaction=nonstopmode", '-output-comment="' + commentstr + '"', "-no-pdf" ] if self.forcedlooseness is None: action = outfname else: action = r"\def\ForcedLooseness{{{}}}\input {}".format( self.forcedlooseness, outfname) logger.debug(f"Running: {cmd} {action}") runner = call(cmd + [action], cwd=self.tmpdir) if isinstance(runner, subprocess.Popen) and runner is not None: try: #runner.wait(self.args.timeout) runner.wait() except subprocess.TimeoutExpired: print("Timed out!") self.res = runner.returncode else: self.res = runner print("cd {}; xetex {} -> {}".format(self.tmpdir, outfname, self.res)) logfname = outfname.replace(".tex", ".log") (self.loglines, rerun) = self.parselog(os.path.join(self.tmpdir, logfname), rerunp=True, lines=300) info.printer.editFile_delayed(logfname, "wrk", "scroll_XeTeXlog", False) numruns += 1 self.rerunReasons = [] tocfname = os.path.join(self.tmpdir, outfname.replace(".tex", ".toc")) if self.res > 0: rerun = False if os.path.exists(tocfname): os.remove(tocfname) break rererun = rerun for a in cacheexts.keys(): testdata = cachedata[a] fpath = os.path.join(self.tmpdir, outfname.replace(".tex", "." + a)) cachedata[a] = self.readfile(fpath) if testdata != cachedata[a]: #if a == "delayed" and len(testdata) and numruns < self.maxRuns: # os.remove(fpath) # cachedata[a] = "" if numruns >= self.maxRuns or not cacheexts[a][1]: self.rerunReasons.append(cacheexts[a][0]) else: print( _("Rerunning because the {} changed").format( cacheexts[a][0])) rererun = True break if os.path.exists(tocfname): tailoring = self.printer.ptsettings.getCollation() ducet = tailored(tailoring.text) if tailoring else None bklist = self.printer.getBooks() toc = TOC(tocfname) newtoc = generateTex(toc.createtocvariants(bklist, ducet=ducet)) with open(tocfname, "w", encoding="utf-8") as outf: outf.write(newtoc) if not rererun: break pdffile = None if not self.noview and not self.args.testing and not self.res: self.printer.incrementProgress() cmd = [ "xdvipdfmx", "-E", "-V", "1.4", "-C", "16", "-q", "-o", outfname.replace(".tex", ".prepress.pdf") ] #if self.ispdfxa == "PDF/A-1": # cmd += ["-z", "0"] if self.args.extras & 7: cmd += ["-" + ("v" * (self.args.extras & 7))] runner = call(cmd + [outfname.replace(".tex", ".xdv")], cwd=self.tmpdir) logger.debug(f"Running: {cmd} for {outfname}") if self.args.extras & 1: print(f"Subprocess return value: {runner}") if isinstance(runner, subprocess.Popen) and runner is not None: try: runner.wait() #runner.wait(self.args.timeout) except subprocess.TimeoutExpired: print("Timed out!") self.res = runner.returncode outpath = os.path.join(self.tmpdir, outfname[:-4]) if self.tmpdir == os.path.join(self.prjdir, "local", "ptxprint", info['config/name']): pdffile = os.path.join(self.prjdir, "local", "ptxprint", outfname[:-4] + ".pdf") else: pdffile = outpath + ".pdf" try: fixpdffile( outpath + ".prepress.pdf", pdffile, colour="rgbx4" if self.ispdfxa == "None" else "cmyk", parlocs=outpath + ".parlocs") except PdfError: self.res = 1 os.remove(outpath + ".prepress.pdf") print("Done") self.done_job(outfname, pdffile, info)
def digdojob(self, jobs, info, diginfo, digprjid, digprjdir): texfiles = [] donebooks = [] digdonebooks = [] _digSecSettings = [ "paper/pagesize", "paper/height", "paper/width", "paper/margins", "paper/topmarginfactor", "paper/bottommarginfactor", "paper/headerposition", "paper/footerposition", "paper/ruleposition", "document/ch1pagebreak", "document/bookintro", "document/introoutline", "document/parallelrefs", "document/elipsizemptyvs", "notes/iffootnoterule", "notes/xrlocation", "notes/includefootnotes", "notes/includexrefs", "notes/fneachnewline", "notes/xreachnewline", "document/filterglossary", "document/chapfrom", "document/chapto", "document/ifcolorfonts", "document/ifshow1chbooknum" ] diginfo["project/bookids"] = jobs diginfo["project/books"] = digdonebooks diginfo["document/ifdiglot"] = "%" diginfo["footer/ftrcenter"] = "-empty-" diginfo["footer/ifftrtitlepagenum"] = "%" diginfo["fancy/pageborder"] = "%" diginfo["document/diffcolayout"] = False diginfo["snippets/diglot"] = False docdir = os.path.join(info["/ptxpath"], info["project/id"], "local", "ptxprint", info["config/name"]) for k in _digSecSettings: diginfo[k] = info[k] syntaxErrors = [] if len(jobs) == 1 and info["project/bookscope"] == "single": chaprange = (int(info["document/chapfrom"]), int(info["document/chapto"])) else: chaprange = (-1, -1) # create differential ptxprint.sty cfgname = info['config/name'] outstyname = os.path.join(self.tmpdir, "diglot.sty") with open(outstyname, "w", encoding="utf-8") as outf: diginfo.printer.styleEditor.output_diffile( outf, basesheet=info.printer.styleEditor.asStyle(None), sheet=diginfo.printer.styleEditor.asStyle(None)) diginfo["project/ptxprintstyfile_"] = outstyname.replace("\\", "/") logger.debug('Diglot processing jobs: {}'.format(jobs)) for b in jobs: logger.debug(f"Diglot({b}): f{self.tmpdir} from f{self.prjdir}") try: out = info.convertBook(b, chaprange, self.tmpdir, self.prjdir) digout = diginfo.convertBook(b, chaprange, self.tmpdir, digprjdir, letterspace="\ufdd1") except FileNotFoundError as e: self.printer.doError(str(e)) out = None if out is None: continue else: donebooks.append(out) if digout is None: continue else: digdonebooks.append(digout) # Now merge the secondary text (right) into the primary text (left) left = os.path.join(self.tmpdir, out) right = os.path.join(self.tmpdir, digout) outFile = re.sub(r"^([^.]*).(.*)$", r"\1-diglot.\2", left) logFile = os.path.join(self.tmpdir, "ptxprint-merge.log") sheetsa = info.printer.getStyleSheets() sheetsb = diginfo.printer.getStyleSheets() logger.debug(f"usfmerge2({left}, {right})") try: usfmerge2(left, right, outFile, stylesheetsa=sheetsa, stylesheetsb=sheetsb, mode=info["document/diglotmergemode"]) except SyntaxError as e: syntaxErrors.append("{} {} line: {}".format( self.prjid, b, str(e).split('line', maxsplit=1)[1])) except Exception as e: syntaxErrors.append("{} {} Error: {}".format( self.prjid, b, str(e))) print_traceback() for f in [left, right, outFile, logFile]: texfiles += [os.path.join(self.tmpdir, f)] if not len(donebooks) or not len(digdonebooks): unlockme() return [] if len(syntaxErrors): prtDrft = _( "And check if a faulty rule in PrintDraftChanges.txt has caused the error(s)." ) if info["project/usechangesfile"] else "" self.printer.doError(_("Failed to merge texts due to a Syntax Error:"), secondary="\n".join(syntaxErrors)+"\n\n"+_("Run the Basic Checks in Paratext to ensure there are no Marker errors "+ \ "in either of the diglot projects. If this error persists, try running the Schema Check in Paratext as well.") + " " + prtDrft, title=_("PTXprint [{}] - Diglot Merge Error!").format(VersionStr), copy2clip=True) info["project/bookids"] = jobs info["project/books"] = donebooks self.books += digdonebooks # Pass all the needed parameters for the snippet from diginfo to info for k, v in _diglot.items(): info[k] = diginfo[v] for k, v in _diglotprinter.items(): info.printer.set(k, diginfo.printer.get(v)) info["document/diglotcfgrpath"] = os.path.relpath( diginfo.printer.configPath(diginfo.printer.configName()), docdir).replace("\\", "/") info["_isDiglot"] = True res = self.sharedjob(jobs, info, extra="-diglot") texfiles += res return texfiles
def doit(self, noview=False): if not lockme(self): return False self.noview = noview self.texfiles = [] if self.printer.ptsettings is None: self.fail(_("Illegal Project")) return info = TexModel(self.printer, self.args.paratext, self.printer.ptsettings, self.printer.prjid, inArchive=self.inArchive) info.debug = self.args.debug self.tempFiles = [] self.prjid = info.dict["project/id"] configid = info.dict["config/name"] self.prjdir = os.path.join(self.args.paratext, self.prjid) if self.prjid is None or not len(self.prjid): # can't print no project return self.tmpdir = os.path.join(self.prjdir, 'local', 'ptxprint', configid) os.makedirs(self.tmpdir, exist_ok=True) jobs = self.printer.getBooks(files=True) reasons = info.prePrintChecks() if len(reasons): self.fail(", ".join(reasons)) return if not len(jobs): self.fail(_("No books to print")) return self.books = [] self.maxRuns = 1 if self.printer.get("c_quickRun") else (self.args.runs or 5) self.changes = None self.ispdfxa = self.printer.get("fcb_outputFormat") or "None" if not self.inArchive: self.checkForMissingDecorations(info) info["document/piclistfile"] = "" if info.asBool("document/ifinclfigs"): self.picfiles = self.gatherIllustrations(info, jobs, self.args.paratext) # self.texfiles += self.gatherIllustrations(info, jobs, self.args.paratext) if True: # info.asBool("project/combinebooks"): joblist = [jobs] else: joblist = [[j] for j in jobs] if self.printer.diglotView is not None: digfraction = info.dict["document/diglotprifraction"] digprjid = info.dict["document/diglotsecprj"] digcfg = info.dict["document/diglotsecconfig"] digprjdir = os.path.join(self.args.paratext, digprjid) digptsettings = ParatextSettings(self.args.paratext, digprjid) diginfo = TexModel(self.printer.diglotView, self.args.paratext, digptsettings, digprjid, inArchive=self.inArchive) reasons = diginfo.prePrintChecks() if len(reasons): self.fail(", ".join(reasons) + " in diglot secondary") return digbooks = self.printer.diglotView.getAllBooks() badbooks = set() for j in joblist: allj = set(j) j[:] = [b for b in j if b in digbooks] badbooks.update(allj - set(j)) if len(badbooks): self.printer.doError( "These books are not available in the secondary diglot project", " ".join(sorted(badbooks)), show=not self.printer.get("c_quickRun")) self.printer.finished() self.busy = False unlockme() return self.texfiles += sum( (self.digdojob(j, info, diginfo, digprjid, digprjdir) for j in joblist), []) else: # Normal (non-diglot) self.texfiles += sum((self.dojob(j, info) for j in joblist), []) self.printer.tempFiles = self.texfiles # Always do this now - regardless!
from ptxprint.ptsettings import ParatextSettings from ptxprint.view import ViewModel, VersionStr, refKey from ptxprint.font import getfontcache from ptxprint.usfmerge import usfmerge2 from ptxprint.utils import _, universalopen, print_traceback from ptxprint.pdf.fixcol import fixpdffile from ptxprint.pdfrw.errors import PdfError from ptxprint.toc import TOC, generateTex from ptxprint.unicode.ducet import tailored from datetime import datetime import logging logger = logging.getLogger(__name__) _errmsghelp = { "! Argument": _("Probably a TeX macro problem - contact support, or post a bug report"), "! TeX capacity exceeded, sorry": _("Uh oh! You've pushed TeX too far! Try turning Hyphenation off, or contact support."), "! Paratext stylesheet": _("Check if the stylesheet specified on the Advanced tab exists."), "! Unable to load picture": _("Check if picture file is located in 'Figures', 'local\\figures' or a\n" +\ "specified folder. Also try the option 'Omit Missing Pictures'"), "! Unable to load picture or PDF file": _("Check if image/PDF file is available on the system.\n" + "If you have specified one or more Front/Back matter PDFs or a Watermark PDF\n" + "then ensure that the PDF(s) exist(s); OR uncheck those options (Advanced tab)."), "! Missing control sequence inserted.": _("Fallback font probably being applied to text in a footnote (not permitted!)"), "! Missing number, treated as zero.": _("Related to USFM3 illustration markup"), "! Undefined control sequence.": _("This might be related to a USFM marker error (using an unsupported marker).\n" +\ "Try running 'Basic Checks' in Paratext to validate markers."), "! Illegal unit of measure (pt inserted).": _("One of the settings in the Stylesheet may be missing the units.\n" +\ "To confirm that this is a stylesheet issue, temporarily turn off Stylesheets.\n" +\ "Then, check any recent changes to the Stylesheets (on Advanced tab) and try again."), "! File ended while scanning use of": _("Try turning off various settings on the Advanced tab."),