Merge release 2.6 into main

This commit is contained in:
Veronica Berglyd Olsen
2025-01-26 20:50:58 +01:00
69 changed files with 2442 additions and 1751 deletions
@@ -1,6 +1,7 @@
{
"Synopsis": "Synopsis",
"Short Description": "Kurzbeschreibung",
"Footnotes": "Fußnoten",
"Comment": "Kommentar",
"Notes": "Notizen",
"Tag": "Schlagwort",
@@ -13,6 +14,7 @@
"Objects": "Objekte",
"Entities": "Organisationen",
"Custom": "Benutzerdefiniert",
"New Page": "Neue Seite",
"0": "Null",
"1": "Eins",
"2": "Zwei",
@@ -1,6 +1,7 @@
{
"Synopsis": "Synopsis",
"Short Description": "Short Description",
"Footnotes": "Footnotes",
"Comment": "Comment",
"Notes": "Notes",
"Tag": "Tag",
@@ -13,6 +14,7 @@
"Objects": "Objects",
"Entities": "Entities",
"Custom": "Custom",
"New Page": "New Page",
"0": "Zero",
"1": "One",
"2": "Two",
@@ -1,6 +1,7 @@
{
"Synopsis": "Sinossi",
"Short Description": "Breve descrizione",
"Footnotes": "Note a piè pagina",
"Comment": "Commento",
"Notes": "Note",
"Tag": "Etichetta",
@@ -13,6 +14,7 @@
"Objects": "Oggetti",
"Entities": "Enti",
"Custom": "Personalizzato",
"New Page": "Nuova pagina",
"0": "Zero",
"1": "Uno",
"2": "Due",
@@ -1,6 +1,7 @@
{
"Synopsis": "あらすじ",
"Short Description": "短い説明",
"Footnotes": "脚注",
"Comment": "コメント ",
"Notes": "ノート",
"Tag": "タグ",
@@ -13,6 +14,7 @@
"Objects": "オブジェクト",
"Entities": "エンティティ",
"Custom": "カスタム",
"New Page": "新規ページ",
"0": "零",
"1": "一",
"2": "二",
@@ -1,6 +1,7 @@
{
"Synopsis": "Sammendrag",
"Short Description": "Kort beskrivelse",
"Footnotes": "Fotnoter",
"Comment": "Kommentar",
"Notes": "Notat",
"Tag": "Knagg",
@@ -13,6 +14,7 @@
"Objects": "Objekter",
"Entities": "Enheter",
"Custom": "Annet",
"New Page": "Ny side",
"0": "null",
"1": "én",
"2": "to",
@@ -1,6 +1,7 @@
{
"Synopsis": "Synopsis",
"Short Description": "Korte beschrijving",
"Footnotes": "Voetnoten",
"Comment": "Opmerking",
"Notes": "Notities",
"Tag": "Label",
@@ -13,6 +14,7 @@
"Objects": "Objecten",
"Entities": "Entiteiten",
"Custom": "Aangepast",
"New Page": "Nieuwe pagina",
"0": "nul",
"1": "één",
"2": "twee",
@@ -1,6 +1,7 @@
{
"Synopsis": "Streszczenie",
"Short Description": "Krótki opis",
"Footnotes": "Przypisy",
"Comment": "Komentarz",
"Notes": "Notatki",
"Tag": "Znacznik",
@@ -13,6 +14,7 @@
"Objects": "Obiekty",
"Entities": "Podmioty",
"Custom": "Różne",
"New Page": "Nowa strona",
"0": "zero",
"1": "pierwszy",
"2": "drugi",
@@ -1,6 +1,7 @@
{
"Synopsis": "Sinopse",
"Short Description": "Descrição breve",
"Footnotes": "Notas de rodapé",
"Comment": "Comentário",
"Notes": "Notas",
"Tag": "Etiqueta",
@@ -13,6 +14,7 @@
"Objects": "Objetos",
"Entities": "Entidades",
"Custom": "Outros",
"New Page": "Nova página",
"0": "Zero",
"1": "Um",
"2": "Dois",
@@ -1,6 +1,7 @@
{
"Synopsis": "概要",
"Short Description": "简短描述",
"Footnotes": "注释",
"Comment": "注释",
"Notes": "笔记",
"Tag": "标签",
@@ -13,6 +14,7 @@
"Objects": "物品",
"Entities": "条目",
"Custom": "自定义",
"New Page": "新建页面",
"0": "零",
"1": "一",
"2": "二",
+7
View File
@@ -159,6 +159,13 @@ SETTINGS_LABELS = {
"format.indentFirstPar": QT_TRANSLATE_NOOP("Builds", "Indent First Paragraph"),
"format.grpMargins": QT_TRANSLATE_NOOP("Builds", "Text Margins"),
"format.titleMargin": QT_TRANSLATE_NOOP("Builds", "Title and Partition"),
"format.h1Margin": QT_TRANSLATE_NOOP("Builds", "Heading 1 and Chapter"),
"format.h2Margin": QT_TRANSLATE_NOOP("Builds", "Heading 2 and Scene"),
"format.h3Margin": QT_TRANSLATE_NOOP("Builds", "Heading 3 and Section"),
"format.h4Margin": QT_TRANSLATE_NOOP("Builds", "Heading 4"),
"format.textMargin": QT_TRANSLATE_NOOP("Builds", "Text Paragraph"),
"format.sepMargin": QT_TRANSLATE_NOOP("Builds", "Scene Separator"),
"format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
"format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
+12 -11
View File
@@ -104,17 +104,18 @@ class BlockTyp(IntEnum):
EMPTY = 1 # Empty line (new paragraph)
TITLE = 2 # Title
HEAD1 = 3 # Heading 1
HEAD2 = 4 # Heading 2
HEAD3 = 5 # Heading 3
HEAD4 = 6 # Heading 4
TEXT = 7 # Text line
SEP = 8 # Scene separator
SKIP = 9 # Paragraph break
SUMMARY = 10 # Synopsis/short comment
NOTE = 11 # Note
COMMENT = 12 # Comment
KEYWORD = 13 # Tag/reference keywords
PART = 3 # Partition
HEAD1 = 4 # Heading 1 or Chapter
HEAD2 = 5 # Heading 2 or Scene
HEAD3 = 6 # Heading 3 or Section
HEAD4 = 7 # Heading 4
TEXT = 8 # Text line
SEP = 9 # Scene separator
SKIP = 10 # Paragraph break
SUMMARY = 11 # Synopsis/short comment
NOTE = 12 # Note
COMMENT = 13 # Comment
KEYWORD = 14 # Tag/reference keywords
class BlockFmt(Flag):
+1 -1
View File
@@ -271,7 +271,7 @@ class ToDocX(Tokenizer):
if tType == BlockTyp.TEXT:
self._processFragments(par, S_NORM, tText, tFormat)
elif tType == BlockTyp.TITLE:
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
self._processFragments(par, S_TITLE, tText, tFormat)
elif tType == BlockTyp.HEAD1:
+30 -27
View File
@@ -30,7 +30,7 @@ from pathlib import Path
from time import time
from novelwriter.common import formatTimeStamp
from novelwriter.constants import nwHtmlUnicode
from novelwriter.constants import nwHtmlUnicode, nwStyles
from novelwriter.core.project import NWProject
from novelwriter.formats.shared import BlockFmt, BlockTyp, T_Formats, TextFmt, stripEscape
from novelwriter.formats.tokenizer import Tokenizer
@@ -130,20 +130,6 @@ class ToHtml(Tokenizer):
def doConvert(self) -> None:
"""Convert the list of text tokens into an HTML document."""
if self._isNovel:
# For story files, we bump the titles one level up
h1Cl = " class='title'"
h1 = "h1"
h2 = "h1"
h3 = "h2"
h4 = "h3"
else:
h1Cl = ""
h1 = "h1"
h2 = "h2"
h3 = "h3"
h4 = "h4"
lines = []
for tType, tMeta, tText, tFmt, tStyle in self._blocks:
@@ -213,25 +199,25 @@ class ToHtml(Tokenizer):
if tType == BlockTyp.TEXT:
lines.append(f"<p{hStyle}>{self._formatText(tText, tFmt)}</p>\n")
elif tType == BlockTyp.TITLE:
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
tHead = tText.replace("\n", "<br>")
lines.append(f"<h1 class='title'{hStyle}>{aNm}{tHead}</h1>\n")
elif tType == BlockTyp.HEAD1:
tHead = tText.replace("\n", "<br>")
lines.append(f"<{h1}{h1Cl}{hStyle}>{aNm}{tHead}</{h1}>\n")
lines.append(f"<h1{hStyle}>{aNm}{tHead}</h1>\n")
elif tType == BlockTyp.HEAD2:
tHead = tText.replace("\n", "<br>")
lines.append(f"<{h2}{hStyle}>{aNm}{tHead}</{h2}>\n")
lines.append(f"<h2{hStyle}>{aNm}{tHead}</h2>\n")
elif tType == BlockTyp.HEAD3:
tHead = tText.replace("\n", "<br>")
lines.append(f"<{h3}{hStyle}>{aNm}{tHead}</{h3}>\n")
lines.append(f"<h3{hStyle}>{aNm}{tHead}</h3>\n")
elif tType == BlockTyp.HEAD4:
tHead = tText.replace("\n", "<br>")
lines.append(f"<{h4}{hStyle}>{aNm}{tHead}</{h4}>\n")
lines.append(f"<h4{hStyle}>{aNm}{tHead}</h4>\n")
elif tType == BlockTyp.SEP:
lines.append(f"<p class='sep'{hStyle}>{tText}</p>\n")
@@ -310,9 +296,7 @@ class ToHtml(Tokenizer):
"</style>\n"
"</head>\n"
"<body>\n"
"<article>\n"
"{body:s}\n"
"</article>\n"
"</body>\n"
"</html>\n"
).format(
@@ -359,6 +343,12 @@ class ToHtml(Tokenizer):
mtSP = self._marginSep[0]
mbSP = self._marginSep[1]
fSz0 = nwStyles.H_SIZES[0]
fSz1 = nwStyles.H_SIZES[1]
fSz2 = nwStyles.H_SIZES[2]
fSz3 = nwStyles.H_SIZES[3]
fSz4 = nwStyles.H_SIZES[4]
font = self._textFont
fFam = font.family()
fSz = font.pointSize()
@@ -379,12 +369,25 @@ class ToHtml(Tokenizer):
styles.append(f"a {{color: {lColor};}}")
styles.append(f"mark {{background: {mColor};}}")
styles.append(f"h1, h2, h3, h4 {{color: {hColor}; page-break-after: avoid;}}")
styles.append(f"h1 {{margin-top: {mtH1:.2f}em; margin-bottom: {mbH1:.2f}em;}}")
styles.append(f"h2 {{margin-top: {mtH2:.2f}em; margin-bottom: {mbH2:.2f}em;}}")
styles.append(f"h3 {{margin-top: {mtH3:.2f}em; margin-bottom: {mbH3:.2f}em;}}")
styles.append(f"h4 {{margin-top: {mtH4:.2f}em; margin-bottom: {mbH4:.2f}em;}}")
styles.append(
f".title {{font-size: 2.5em; margin-top: {mtH0:.2f}em; margin-bottom: {mbH0:.2f}em;}}"
f"h1 {{font-size: {fSz1:.2f}em; "
f"margin-top: {mtH1:.2f}em; margin-bottom: {mbH1:.2f}em;}}"
)
styles.append(
f"h2 {{font-size: {fSz2:.2f}em; "
f"margin-top: {mtH2:.2f}em; margin-bottom: {mbH2:.2f}em;}}"
)
styles.append(
f"h3 {{font-size: {fSz3:.2f}em; "
f"margin-top: {mtH3:.2f}em; margin-bottom: {mbH3:.2f}em;}}"
)
styles.append(
f"h4 {{font-size: {fSz4:.2f}em; "
f"margin-top: {mtH4:.2f}em; margin-bottom: {mbH4:.2f}em;}}"
)
styles.append(
f".title {{font-size: {fSz0:.2f}em; "
f"margin-top: {mtH0:.2f}em; margin-bottom: {mbH0:.2f}em;}}"
)
styles.append(
f".sep {{text-align: center; margin-top: {mtSP:.2f}em; margin-bottom: {mbSP:.2f}em;}}"
+14 -8
View File
@@ -68,11 +68,11 @@ COMMENT_STYLE = {
nwComment.COMMENT: ComStyle(),
nwComment.STORY: ComStyle("", "modifier", "note"),
}
HEADINGS = [BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4]
SKIP_INDENT = [
BlockTyp.TITLE, BlockTyp.HEAD1, BlockTyp.HEAD2, BlockTyp.HEAD2, BlockTyp.HEAD3,
BlockTyp.HEAD4, BlockTyp.SEP, BlockTyp.SKIP,
HEADINGS = [
BlockTyp.TITLE, BlockTyp.PART, BlockTyp.HEAD1,
BlockTyp.HEAD2, BlockTyp.HEAD3, BlockTyp.HEAD4,
]
SKIP_INDENT = HEADINGS + [BlockTyp.SEP, BlockTyp.SKIP]
B_EMPTY: T_Block = (BlockTyp.EMPTY, "", "", [], BlockFmt.NONE)
@@ -654,6 +654,7 @@ class Tokenizer(ABC):
if not (isPlain or isNovel and sHide):
tStyle |= self._titleStyle
if isNovel:
tType = BlockTyp.PART if isPlain else BlockTyp.TITLE
if sHide:
tText = ""
tType = BlockTyp.EMPTY
@@ -687,6 +688,7 @@ class Tokenizer(ABC):
sHide = self._hideChapter if isPlain else self._hideUnNum
tFormat = self._fmtChapter if isPlain else self._fmtUnNum
if isNovel:
tType = BlockTyp.HEAD1 # Promote
if isPlain:
self._hFormatter.incChapter()
if sHide:
@@ -721,6 +723,7 @@ class Tokenizer(ABC):
sHide = self._hideScene if isPlain else self._hideHScene
tFormat = self._fmtScene if isPlain else self._fmtHScene
if isNovel:
tType = BlockTyp.HEAD2 # Promote
self._hFormatter.incScene()
if sHide:
tText = ""
@@ -752,6 +755,7 @@ class Tokenizer(ABC):
tText = aLine[5:].strip()
tType = BlockTyp.HEAD4
if isNovel:
tType = BlockTyp.HEAD3 # Promote
if self._hideSection:
tText = ""
tType = BlockTyp.EMPTY
@@ -927,12 +931,14 @@ class Tokenizer(ABC):
for tType, tKey, tText, _, _ in self._blocks:
if tType == BlockTyp.TITLE:
prefix = "TT"
elif tType == BlockTyp.PART:
prefix = "PT"
elif tType == BlockTyp.HEAD1:
prefix = "PT" if isNovel else "H1"
prefix = "CH" if isNovel else "H1"
elif tType == BlockTyp.HEAD2:
prefix = "CH" if isNovel else "H2"
elif tType == BlockTyp.HEAD3:
prefix = "SC" if isNovel else "H3"
prefix = "SC" if isNovel else "H2"
elif tType == BlockTyp.HEAD3 and not isNovel:
prefix = "H3"
else:
continue
+3 -2
View File
@@ -113,9 +113,10 @@ class ToMarkdown(Tokenizer):
tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n")
lines.append(f"{tTemp}\n\n")
elif tType == BlockTyp.TITLE:
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
tHead = tText.replace("\n", " - ")
lines.append(f"# {tHead}\n\n")
lines.append(f"{tHead}\n")
lines.append("="*len(tHead) + "\n\n")
elif tType == BlockTyp.HEAD1:
tHead = tText.replace("\n", " - ")
+1 -1
View File
@@ -363,7 +363,7 @@ class ToOdt(Tokenizer):
else:
self._addTextPar(xText, S_TEXT, oStyle, tText, tFmt=tFormat)
elif tType == BlockTyp.TITLE:
elif tType in (BlockTyp.TITLE, BlockTyp.PART):
# Title must be text:p
self._addTextPar(xText, S_TITLE, oStyle, tText, isHead=False)
+2
View File
@@ -156,6 +156,7 @@ class ToQTextDocument(Tokenizer):
self._mHead = {
BlockTyp.TITLE: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]),
BlockTyp.PART: (fPx * self._marginTitle[0], fPx * self._marginTitle[1]),
BlockTyp.HEAD1: (fPx * self._marginHead1[0], fPx * self._marginHead1[1]),
BlockTyp.HEAD2: (fPx * self._marginHead2[0], fPx * self._marginHead2[1]),
BlockTyp.HEAD3: (fPx * self._marginHead3[0], fPx * self._marginHead3[1]),
@@ -165,6 +166,7 @@ class ToQTextDocument(Tokenizer):
hScale = self._scaleHeads
self._sHead = {
BlockTyp.TITLE: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
BlockTyp.PART: (nwStyles.H_SIZES.get(0, 1.0) * fPt) if hScale else fPt,
BlockTyp.HEAD1: (nwStyles.H_SIZES.get(1, 1.0) * fPt) if hScale else fPt,
BlockTyp.HEAD2: (nwStyles.H_SIZES.get(2, 1.0) * fPt) if hScale else fPt,
BlockTyp.HEAD3: (nwStyles.H_SIZES.get(3, 1.0) * fPt) if hScale else fPt,
+8 -8
View File
@@ -38,7 +38,7 @@ from PyQt6.QtWidgets import (
from novelwriter import CONFIG, SHARED
from novelwriter.common import describeFont, fontMatcher, qtAddAction, qtLambda
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwStyles, trConst
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, trConst
from novelwriter.core.buildsettings import BuildSettings, FilterMode
from novelwriter.extensions.configlayout import (
NColorLabel, NFixedPage, NScrollableForm, NScrollablePage
@@ -1065,7 +1065,7 @@ class _FormattingTab(NScrollableForm):
self.titleMarginB.setFixedWidth(dbW)
self.addRow(
trConst(nwStyles.T_LABEL["H0"]),
self._build.getLabel("format.titleMargin"),
[pixT, self.titleMarginT, 6, pixB, self.titleMarginB],
unit="em",
)
@@ -1078,7 +1078,7 @@ class _FormattingTab(NScrollableForm):
self.h1MarginB.setFixedWidth(dbW)
self.addRow(
trConst(nwStyles.T_LABEL["H1"]),
self._build.getLabel("format.h1Margin"),
[pixT, self.h1MarginT, 6, pixB, self.h1MarginB],
unit="em",
)
@@ -1091,7 +1091,7 @@ class _FormattingTab(NScrollableForm):
self.h2MarginB.setFixedWidth(dbW)
self.addRow(
trConst(nwStyles.T_LABEL["H2"]),
self._build.getLabel("format.h2Margin"),
[pixT, self.h2MarginT, 6, pixB, self.h2MarginB],
unit="em",
)
@@ -1104,7 +1104,7 @@ class _FormattingTab(NScrollableForm):
self.h3MarginB.setFixedWidth(dbW)
self.addRow(
trConst(nwStyles.T_LABEL["H3"]),
self._build.getLabel("format.h3Margin"),
[pixT, self.h3MarginT, 6, pixB, self.h3MarginB],
unit="em",
)
@@ -1117,7 +1117,7 @@ class _FormattingTab(NScrollableForm):
self.h4MarginB.setFixedWidth(dbW)
self.addRow(
trConst(nwStyles.T_LABEL["H4"]),
self._build.getLabel("format.h4Margin"),
[pixT, self.h4MarginT, 6, pixB, self.h4MarginB],
unit="em",
)
@@ -1130,7 +1130,7 @@ class _FormattingTab(NScrollableForm):
self.textMarginB.setFixedWidth(dbW)
self.addRow(
trConst(nwStyles.T_LABEL["TT"]),
self._build.getLabel("format.textMargin"),
[pixT, self.textMarginT, 6, pixB, self.textMarginB],
unit="em",
)
@@ -1143,7 +1143,7 @@ class _FormattingTab(NScrollableForm):
self.sepMarginB.setFixedWidth(dbW)
self.addRow(
trConst(nwStyles.T_LABEL["SP"]),
self._build.getLabel("format.sepMargin"),
[pixT, self.sepMarginT, 6, pixB, self.sepMarginB],
unit="em",
)