From 3f0024a6a384c4fc20ad079f5c85158fa59e87d0 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Thu, 9 Nov 2023 18:02:33 +0100
Subject: [PATCH 1/6] Use GUI language when translating meta data for the
viewer
---
novelwriter/core/tohtml.py | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/novelwriter/core/tohtml.py b/novelwriter/core/tohtml.py
index 41201412..2dd1eed9 100644
--- a/novelwriter/core/tohtml.py
+++ b/novelwriter/core/tohtml.py
@@ -31,7 +31,7 @@ from pathlib import Path
from novelwriter import CONFIG
from novelwriter.common import formatTimeStamp
-from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwHtmlUnicode
+from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwHtmlUnicode, trConst
from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import Tokenizer, stripEscape
@@ -477,7 +477,11 @@ class ToHtml(Tokenizer):
if not valid or not bits or bits[0] not in nwLabels.KEY_NAME:
return ""
- result = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
+ if self._genMode == self.M_PREVIEW:
+ result = f"{trConst(nwLabels.KEY_NAME[bits[0]])}: "
+ else:
+ result = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
+
if len(bits) > 1:
if bits[0] == nwKeyWords.TAG_KEY:
result += f"{bits[1]}"
From 27f3b8e0f203b8e41d86f4664cf41d0f65d52ac9 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Thu, 9 Nov 2023 18:02:53 +0100
Subject: [PATCH 2/6] Add project translations for Norwegian nynorsk
---
novelwriter/assets/i18n/project_nn_NO.json | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/novelwriter/assets/i18n/project_nn_NO.json b/novelwriter/assets/i18n/project_nn_NO.json
index 09b99a4e..aff847e2 100644
--- a/novelwriter/assets/i18n/project_nn_NO.json
+++ b/novelwriter/assets/i18n/project_nn_NO.json
@@ -2,6 +2,16 @@
"Synopsis": "Samandrag",
"Comment": "Kommentar",
"Notes": "Notat",
+ "Tag": "Knagg",
+ "Point of View": "Perspektiv",
+ "Focus": "Fokus",
+ "Characters": "Karakterar",
+ "Plot": "Plott",
+ "Timeline": "Tidslinje",
+ "Locations": "Lokasjonar",
+ "Objects": "Objekt",
+ "Entities": "Eining",
+ "Custom": "Anna",
"0": "null",
"1": "ein",
"2": "to",
From 2cde1b845ee9fb2d3241db9ba65434b4e118ddca Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Thu, 9 Nov 2023 18:26:33 +0100
Subject: [PATCH 3/6] Clean up project settings class
---
novelwriter/core/projectdata.py | 4 +-
novelwriter/dialogs/projsettings.py | 180 +++++++++-----------
tests/test_dialogs/test_dlg_projsettings.py | 34 ++--
3 files changed, 95 insertions(+), 123 deletions(-)
diff --git a/novelwriter/core/projectdata.py b/novelwriter/core/projectdata.py
index 9b0cc36c..d248a7a1 100644
--- a/novelwriter/core/projectdata.py
+++ b/novelwriter/core/projectdata.py
@@ -152,14 +152,14 @@ class NWProjectData:
"""Return the initial count of words for novel and note
documents.
"""
- return tuple(self._initCounts)
+ return self._initCounts[0], self._initCounts[1]
@property
def currCounts(self) -> tuple[int, int]:
"""Return the current count of words for novel and note
documents.
"""
- return tuple(self._currCounts)
+ return self._currCounts[0], self._currCounts[1]
@property
def lastHandle(self) -> dict[str, str | None]:
diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py
index ac79a986..337c823a 100644
--- a/novelwriter/dialogs/projsettings.py
+++ b/novelwriter/dialogs/projsettings.py
@@ -96,17 +96,17 @@ class GuiProjectSettings(NPagedDialog):
return
- def __del__(self): # pragma: no cover
+ def __del__(self) -> None: # pragma: no cover
logger.debug("Delete: GuiProjectSettings")
return
##
- # Slots
+ # Private Slots
##
- def _doSave(self):
- """Save settings and close dialog.
- """
+ @pyqtSlot()
+ def _doSave(self) -> None:
+ """Save settings and close dialog."""
project = SHARED.project
projName = self.tabMain.editName.text()
bookTitle = self.tabMain.editTitle.text()
@@ -140,9 +140,9 @@ class GuiProjectSettings(NPagedDialog):
return
- def _doClose(self):
- """Save settings and close the dialog.
- """
+ @pyqtSlot()
+ def _doClose(self) -> None:
+ """Save settings and close the dialog."""
self._saveGuiSettings()
self.reject()
return
@@ -151,9 +151,8 @@ class GuiProjectSettings(NPagedDialog):
# Internal Functions
##
- def _focusTab(self, tab):
- """Change which is the focused tab.
- """
+ def _focusTab(self, tab: int) -> None:
+ """Change which is the focused tab."""
if tab == self.TAB_MAIN:
self.setCurrentWidget(self.tabMain)
elif tab == self.TAB_STATUS:
@@ -164,9 +163,8 @@ class GuiProjectSettings(NPagedDialog):
self.setCurrentWidget(self.tabReplace)
return
- def _saveGuiSettings(self):
- """Save GUI settings.
- """
+ def _saveGuiSettings(self) -> None:
+ """Save GUI settings."""
winWidth = CONFIG.rpxInt(self.width())
winHeight = CONFIG.rpxInt(self.height())
replaceColW = CONFIG.rpxInt(self.tabReplace.listBox.columnWidth(0))
@@ -187,8 +185,8 @@ class GuiProjectSettings(NPagedDialog):
class GuiProjectEditMain(QWidget):
- def __init__(self, projGui):
- super().__init__(parent=projGui)
+ def __init__(self, parent: QWidget) -> None:
+ super().__init__(parent=parent)
# The Form
self.mainForm = NConfigLayout()
@@ -271,8 +269,8 @@ class GuiProjectEditStatus(QWidget):
COL_ROLE = Qt.ItemDataRole.UserRole + 1
NUM_ROLE = Qt.ItemDataRole.UserRole + 2
- def __init__(self, projGui, isStatus):
- super().__init__(parent=projGui)
+ def __init__(self, parent: QWidget, isStatus: bool) -> None:
+ super().__init__(parent=parent)
if isStatus:
self.theStatus = SHARED.project.data.itemStatus
@@ -372,9 +370,8 @@ class GuiProjectEditStatus(QWidget):
return
- def getNewList(self):
- """Return list of entries.
- """
+ def getNewList(self) -> tuple[list, list]:
+ """Return list of entries."""
if self.colChanged:
newList = []
for n in range(self.listBox.topLevelItemCount()):
@@ -394,9 +391,8 @@ class GuiProjectEditStatus(QWidget):
##
@pyqtSlot()
- def _selectColour(self):
- """Open a dialog to select the status icon colour.
- """
+ def _selectColour(self) -> None:
+ """Open a dialog to select the status icon colour."""
if self.selColour is not None:
newCol = QColorDialog.getColor(
self.selColour, self, self.tr("Select Colour")
@@ -410,17 +406,15 @@ class GuiProjectEditStatus(QWidget):
return
@pyqtSlot()
- def _newItem(self):
- """Create a new status item.
- """
+ def _newItem(self) -> None:
+ """Create a new status item."""
self._addItem(None, self.tr("New Item"), (100, 100, 100), 0)
self.colChanged = True
return
@pyqtSlot()
- def _delItem(self):
- """Delete a status item.
- """
+ def _delItem(self) -> None:
+ """Delete a status item."""
selItem = self._getSelectedItem()
if isinstance(selItem, QTreeWidgetItem):
iRow = self.listBox.indexOfTopLevelItem(selItem)
@@ -433,9 +427,8 @@ class GuiProjectEditStatus(QWidget):
return
@pyqtSlot()
- def _saveItem(self):
- """Save changes made to a status item.
- """
+ def _saveItem(self) -> None:
+ """Save changes made to a status item."""
selItem = self._getSelectedItem()
if isinstance(selItem, QTreeWidgetItem):
selItem.setText(self.COL_LABEL, simplified(self.editName.text()))
@@ -444,11 +437,10 @@ class GuiProjectEditStatus(QWidget):
self.selColour.red(), self.selColour.green(), self.selColour.blue()
))
self.colChanged = True
-
return
@pyqtSlot()
- def _selectedItem(self):
+ def _selectedItem(self) -> None:
"""Extract the info of a selected item and populate the settings
boxes and button. If no item is selected, clear the form.
"""
@@ -456,7 +448,6 @@ class GuiProjectEditStatus(QWidget):
if isinstance(selItem, QTreeWidgetItem):
cols = selItem.data(self.COL_LABEL, self.COL_ROLE)
name = selItem.text(self.COL_LABEL)
-
pixmap = QPixmap(self.iPx, self.iPx)
pixmap.fill(QColor(*cols))
self.selColour = QColor(*cols)
@@ -464,31 +455,27 @@ class GuiProjectEditStatus(QWidget):
self.colButton.setIcon(QIcon(pixmap))
self.editName.selectAll()
self.editName.setFocus()
-
self.editName.setEnabled(True)
self.colButton.setEnabled(True)
self.saveButton.setEnabled(True)
-
else:
pixmap = QPixmap(self.iPx, self.iPx)
pixmap.fill(QColor(100, 100, 100))
self.selColour = QColor(100, 100, 100)
self.editName.setText("")
self.colButton.setIcon(QIcon(pixmap))
-
self.editName.setEnabled(False)
self.colButton.setEnabled(False)
self.saveButton.setEnabled(False)
-
return
##
# Internal Functions
##
- def _addItem(self, key, name, cols, count):
- """Add a status item to the list.
- """
+ def _addItem(self, key: str | None, name: str,
+ cols: tuple[int, int, int], count: int) -> None:
+ """Add a status item to the list."""
pixmap = QPixmap(self.iPx, self.iPx)
pixmap.fill(QColor(*cols))
@@ -504,9 +491,8 @@ class GuiProjectEditStatus(QWidget):
return
- def _moveItem(self, step):
- """Move and item up or down step.
- """
+ def _moveItem(self, step: int) -> None:
+ """Move and item up or down step."""
selItem = self._getSelectedItem()
if selItem is None:
return
@@ -527,17 +513,15 @@ class GuiProjectEditStatus(QWidget):
return
- def _getSelectedItem(self):
- """Get the currently selected item.
- """
+ def _getSelectedItem(self) -> QTreeWidgetItem | None:
+ """Get the currently selected item."""
selItem = self.listBox.selectedItems()
if len(selItem) > 0:
return selItem[0]
return None
- def _usageString(self, nUse):
- """Generate usage string.
- """
+ def _usageString(self, nUse: int) -> str:
+ """Generate usage string."""
if nUse == 0:
return self.tr("Not in use")
elif nUse == 1:
@@ -553,8 +537,8 @@ class GuiProjectEditReplace(QWidget):
COL_KEY = 0
COL_REPL = 1
- def __init__(self, projGui):
- super().__init__(parent=projGui)
+ def __init__(self, parent: QWidget) -> None:
+ super().__init__(parent=parent)
self.arChanged = False
@@ -635,25 +619,23 @@ class GuiProjectEditReplace(QWidget):
return
- def getNewList(self):
- """Extract the list from the widget.
- """
- newList = {}
+ def getNewList(self) -> dict:
+ """Extract the list from the widget."""
+ new = {}
for n in range(self.listBox.topLevelItemCount()):
tItem = self.listBox.topLevelItem(n)
if tItem is not None:
aKey = self._stripNotAllowed(tItem.text(0))
aVal = tItem.text(1)
if len(aKey) > 0:
- newList[aKey] = aVal
-
- return newList
+ new[aKey] = aVal
+ return new
##
# Internal Functions
##
- def _selectedItem(self):
+ def _selectedItem(self) -> bool:
"""Extract the details from the selected item and populate the
edit form.
"""
@@ -670,63 +652,53 @@ class GuiProjectEditReplace(QWidget):
self.editKey.setFocus()
return True
- def _saveEntry(self):
- """Save the form data into the list widget.
- """
+ def _saveEntry(self) -> None:
+ """Save the form data into the list widget."""
selItem = self._getSelectedItem()
- if selItem is None:
- return False
-
- newKey = self.editKey.text()
- newVal = self.editValue.text()
- saveKey = self._stripNotAllowed(newKey)
-
- if len(saveKey) > 0 and len(newVal) > 0:
- selItem.setText(self.COL_KEY, "<%s>" % saveKey)
- selItem.setText(self.COL_REPL, newVal)
- self.editKey.clear()
- self.editValue.clear()
- self.editKey.setEnabled(False)
- self.editValue.setEnabled(False)
- self.listBox.clearSelection()
- self.arChanged = True
-
+ if selItem:
+ newKey = self.editKey.text()
+ newVal = self.editValue.text()
+ saveKey = self._stripNotAllowed(newKey)
+ if len(saveKey) > 0 and len(newVal) > 0:
+ selItem.setText(self.COL_KEY, "<%s>" % saveKey)
+ selItem.setText(self.COL_REPL, newVal)
+ self.editKey.clear()
+ self.editValue.clear()
+ self.editKey.setEnabled(False)
+ self.editValue.setEnabled(False)
+ self.listBox.clearSelection()
+ self.arChanged = True
return
- def _addEntry(self):
- """Add a new list entry.
- """
+ def _addEntry(self) -> None:
+ """Add a new list entry."""
saveKey = "" % (self.listBox.topLevelItemCount() + 1)
newVal = ""
newItem = QTreeWidgetItem([saveKey, newVal])
self.listBox.addTopLevelItem(newItem)
- return True
+ return
- def _delEntry(self):
- """Delete the selected entry.
- """
+ def _delEntry(self) -> None:
+ """Delete the selected entry."""
selItem = self._getSelectedItem()
- if selItem is None:
- return False
- self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(selItem))
- self.arChanged = True
- return True
+ if selItem:
+ self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(selItem))
+ self.arChanged = True
+ return
- def _getSelectedItem(self):
- """Extract the currently selected item.
- """
+ def _getSelectedItem(self) -> QTreeWidgetItem | None:
+ """Extract the currently selected item."""
selItem = self.listBox.selectedItems()
if len(selItem) == 0:
return None
return selItem[0]
- def _stripNotAllowed(self, theKey):
- """Clean up the replace key string.
- """
- retKey = ""
- for c in theKey:
+ def _stripNotAllowed(self, key: str) -> str:
+ """Clean up the replace key string."""
+ result = ""
+ for c in key:
if c.isalnum():
- retKey += c
- return retKey
+ result += c
+ return result
# END Class GuiProjectEditReplace
diff --git a/tests/test_dialogs/test_dlg_projsettings.py b/tests/test_dialogs/test_dlg_projsettings.py
index f56f01bf..824d0403 100644
--- a/tests/test_dialogs/test_dlg_projsettings.py
+++ b/tests/test_dialogs/test_dlg_projsettings.py
@@ -155,9 +155,9 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
# Set some values
theProject = SHARED.project
- theProject.tree[C.hTitlePage].setStatus(C.sFinished)
- theProject.tree[C.hChapterDoc].setStatus(C.sDraft)
- theProject.tree[C.hSceneDoc].setStatus(C.sDraft)
+ theProject.tree[C.hTitlePage].setStatus(C.sFinished) # type: ignore
+ theProject.tree[C.hChapterDoc].setStatus(C.sDraft) # type: ignore
+ theProject.tree[C.hSceneDoc].setStatus(C.sDraft) # type: ignore
nwGUI.projView.projTree.setSelectedHandle(C.hPlotRoot)
nwGUI.projView.projTree.newTreeItem(nwItemType.FILE, hLevel=1, isNote=True)
@@ -170,9 +170,9 @@ def testDlgProjSettings_StatusImport(qtbot, monkeypatch, nwGUI, fncPath, projPat
hCharNote = "0000000000011"
hWorldNote = "0000000000012"
- theProject.tree[hPlotNote].setImport(C.iMajor)
- theProject.tree[hCharNote].setImport(C.iMajor)
- theProject.tree[hWorldNote].setImport(C.iMain)
+ theProject.tree[hPlotNote].setImport(C.iMajor) # type: ignore
+ theProject.tree[hCharNote].setImport(C.iMajor) # type: ignore
+ theProject.tree[hWorldNote].setImport(C.iMain) # type: ignore
# Create Dialog
projSettings = GuiProjectSettings(nwGUI, GuiProjectSettings.TAB_STATUS)
@@ -367,23 +367,23 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mo
tabReplace = projSettings.tabReplace
- assert tabReplace.listBox.topLevelItem(0).text(0) == ""
- assert tabReplace.listBox.topLevelItem(0).text(1) == "B"
- assert tabReplace.listBox.topLevelItem(1).text(0) == ""
- assert tabReplace.listBox.topLevelItem(1).text(1) == "D"
+ assert tabReplace.listBox.topLevelItem(0).text(0) == "" # type: ignore
+ assert tabReplace.listBox.topLevelItem(0).text(1) == "B" # type: ignore
+ assert tabReplace.listBox.topLevelItem(1).text(0) == "" # type: ignore
+ assert tabReplace.listBox.topLevelItem(1).text(1) == "D" # type: ignore
assert tabReplace.listBox.topLevelItemCount() == 2
# Nothing to save or delete
tabReplace.listBox.clearSelection()
- assert tabReplace._saveEntry() is False
- assert tabReplace._delEntry() is False
+ tabReplace._saveEntry()
+ tabReplace._delEntry()
assert tabReplace.listBox.topLevelItemCount() == 2
# Create a new entry
qtbot.mouseClick(tabReplace.addButton, Qt.LeftButton)
assert tabReplace.listBox.topLevelItemCount() == 3
- assert tabReplace.listBox.topLevelItem(2).text(0) == ""
- assert tabReplace.listBox.topLevelItem(2).text(1) == ""
+ assert tabReplace.listBox.topLevelItem(2).text(0) == "" # type: ignore
+ assert tabReplace.listBox.topLevelItem(2).text(1) == "" # type: ignore
# Edit the entry
tabReplace.listBox.setCurrentItem(tabReplace.listBox.topLevelItem(2))
@@ -394,8 +394,8 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mo
for c in "With This Stuff ":
qtbot.keyClick(tabReplace.editValue, c, delay=KEY_DELAY)
qtbot.mouseClick(tabReplace.saveButton, Qt.LeftButton)
- assert tabReplace.listBox.topLevelItem(2).text(0) == ""
- assert tabReplace.listBox.topLevelItem(2).text(1) == "With This Stuff "
+ assert tabReplace.listBox.topLevelItem(2).text(0) == "" # type: ignore
+ assert tabReplace.listBox.topLevelItem(2).text(1) == "With This Stuff " # type: ignore
# Create a new entry again
tabReplace.listBox.clearSelection()
@@ -405,7 +405,7 @@ def testDlgProjSettings_Replace(qtbot, monkeypatch, nwGUI, fncPath, projPath, mo
# The list is sorted, so we must find it
newIdx = -1
for i in range(tabReplace.listBox.topLevelItemCount()):
- if tabReplace.listBox.topLevelItem(i).text(0) == "":
+ if tabReplace.listBox.topLevelItem(i).text(0) == "": # type: ignore
newIdx = i
break
assert newIdx >= 0
From c7bfb1b21ed0ec3fc7d6b1fe3b682807a14e2dd1 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Thu, 9 Nov 2023 18:44:08 +0100
Subject: [PATCH 4/6] Change to always use project language for generating
documents
---
novelwriter/core/docbuild.py | 6 +-----
novelwriter/core/tohtml.py | 16 ++++-----------
novelwriter/core/tokenizer.py | 3 ---
novelwriter/dialogs/projsettings.py | 32 +++++++++++++++++++++++------
novelwriter/tools/manussettings.py | 14 -------------
5 files changed, 31 insertions(+), 40 deletions(-)
diff --git a/novelwriter/core/docbuild.py b/novelwriter/core/docbuild.py
index 8c4b4ca5..75906d9a 100644
--- a/novelwriter/core/docbuild.py
+++ b/novelwriter/core/docbuild.py
@@ -248,13 +248,9 @@ class NWBuildDocument:
def _setupBuild(self, bldObj: Tokenizer) -> dict:
"""Configure the build object."""
# Get Settings
- buildLang = self._build.getStr("format.buildLang")
textFont = self._build.getStr("format.textFont")
textSize = self._build.getInt("format.textSize")
- # The language lookup dict is reloaded if needed
- self._project.setProjectLang(buildLang)
-
fontFamily = textFont or CONFIG.textFont
bldFont = QFont(fontFamily, textSize)
fontInfo = QFontInfo(bldFont)
@@ -287,7 +283,7 @@ class NWBuildDocument:
if isinstance(bldObj, ToOdt):
bldObj.setColourHeaders(self._build.getBool("odt.addColours"))
- bldObj.setLanguage(buildLang)
+ bldObj.setLanguage(self._project.data.language)
scale = nwLabels.UNIT_SCALE.get(self._build.getStr("format.pageUnit"), 1.0)
pW, pH = nwLabels.PAPER_SIZE.get(self._build.getStr("format.pageSize"), (-1.0, -1.0))
diff --git a/novelwriter/core/tohtml.py b/novelwriter/core/tohtml.py
index 2dd1eed9..ac73418d 100644
--- a/novelwriter/core/tohtml.py
+++ b/novelwriter/core/tohtml.py
@@ -31,7 +31,7 @@ from pathlib import Path
from novelwriter import CONFIG
from novelwriter.common import formatTimeStamp
-from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwHtmlUnicode, trConst
+from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwHtmlUnicode
from novelwriter.core.project import NWProject
from novelwriter.core.tokenizer import Tokenizer, stripEscape
@@ -456,12 +456,8 @@ class ToHtml(Tokenizer):
def _formatSynopsis(self, text: str) -> str:
"""Apply HTML formatting to synopsis."""
- if self._genMode == self.M_PREVIEW:
- sSynop = self._trSynopsis
- return f"\n"
- else:
- sSynop = self._localLookup("Synopsis")
- return f"{sSynop}: {text}
\n"
+ sSynop = self._localLookup("Synopsis")
+ return f"\n"
def _formatComments(self, text: str) -> str:
"""Apply HTML formatting to comments."""
@@ -477,11 +473,7 @@ class ToHtml(Tokenizer):
if not valid or not bits or bits[0] not in nwLabels.KEY_NAME:
return ""
- if self._genMode == self.M_PREVIEW:
- result = f"{trConst(nwLabels.KEY_NAME[bits[0]])}: "
- else:
- result = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
-
+ result = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
if len(bits) > 1:
if bits[0] == nwKeyWords.TAG_KEY:
result += f"{bits[1]}"
diff --git a/novelwriter/core/tokenizer.py b/novelwriter/core/tokenizer.py
index 63518ca7..4f4a8378 100644
--- a/novelwriter/core/tokenizer.py
+++ b/novelwriter/core/tokenizer.py
@@ -167,9 +167,6 @@ class Tokenizer(ABC):
self._localLookup = self._project.localLookup
self.tr = partial(QCoreApplication.translate, "Tokenizer")
- # Cached Translations
- self._trSynopsis = self.tr("Synopsis")
-
# Format RegEx
self._rxMarkdown = [
(QRegularExpression(nwRegEx.FMT_EI), [0, self.FMT_I_B, 0, self.FMT_I_E]),
diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py
index 337c823a..4accfed0 100644
--- a/novelwriter/dialogs/projsettings.py
+++ b/novelwriter/dialogs/projsettings.py
@@ -107,10 +107,11 @@ class GuiProjectSettings(NPagedDialog):
@pyqtSlot()
def _doSave(self) -> None:
"""Save settings and close dialog."""
- project = SHARED.project
+ project = SHARED.project
projName = self.tabMain.editName.text()
bookTitle = self.tabMain.editTitle.text()
bookAuthor = self.tabMain.editAuthor.text()
+ projLang = self.tabMain.projLang.currentData()
spellLang = self.tabMain.spellLang.currentData()
doBackup = not self.tabMain.doBackup.isChecked()
@@ -119,6 +120,7 @@ class GuiProjectSettings(NPagedDialog):
project.data.setAuthor(bookAuthor)
project.data.setDoBackup(doBackup)
project.data.setSpellLang(spellLang)
+ project.setProjectLang(projLang)
if self.tabStatus.colChanged:
newList, delList = self.tabStatus.getNewList()
@@ -228,24 +230,42 @@ class GuiProjectEditMain(QWidget):
self.tr("Change whenever you want!")
)
+ self.projLang = QComboBox(self)
+ self.projLang.setMaximumWidth(xW)
+ if CONFIG.hasEnchant:
+ for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
+ self.projLang.addItem(language, tag)
+ self.mainForm.addRow(
+ self.tr("Project language"),
+ self.projLang,
+ self.tr("Used when building the manuscript.")
+ )
+
+ langIdx = 0
+ if pData.language is not None:
+ langIdx = self.projLang.findData(pData.language)
+ if langIdx == -1:
+ langIdx = self.projLang.findData("en_GB")
+ if langIdx != -1:
+ self.projLang.setCurrentIndex(langIdx)
+
self.spellLang = QComboBox(self)
self.spellLang.setMaximumWidth(xW)
self.spellLang.addItem(self.tr("Default"), "None")
if CONFIG.hasEnchant:
for tag, language in SHARED.spelling.listDictionaries():
self.spellLang.addItem(language, tag)
-
self.mainForm.addRow(
self.tr("Spell check language"),
self.spellLang,
self.tr("Overrides main preferences.")
)
- spellIdx = 0
+ langIdx = 0
if pData.spellLang is not None:
- spellIdx = self.spellLang.findData(pData.spellLang)
- if spellIdx != -1:
- self.spellLang.setCurrentIndex(spellIdx)
+ langIdx = self.spellLang.findData(pData.spellLang)
+ if langIdx != -1:
+ self.spellLang.setCurrentIndex(langIdx)
self.doBackup = NSwitch(self)
self.doBackup.setChecked(not pData.doBackup)
diff --git a/novelwriter/tools/manussettings.py b/novelwriter/tools/manussettings.py
index cfa1b038..95235424 100644
--- a/novelwriter/tools/manussettings.py
+++ b/novelwriter/tools/manussettings.py
@@ -974,15 +974,6 @@ class _FormatTab(QWidget):
self.formFormat = NConfigLayout()
self.formFormat.addGroupLabel(self._build.getLabel("format.grpFormat"))
- # Build Language
- self.buildLang = QComboBox()
- langauges = CONFIG.listLanguages(CONFIG.LANG_PROJ)
- self.buildLang.addItem("[%s]" % self.tr("Not Set"), "None")
- for langID, langName in langauges:
- self.buildLang.addItem(langName, langID)
-
- self.formFormat.addRow(self._build.getLabel("format.buildLang"), self.buildLang)
-
# Font Family
self.textFont = QLineEdit()
self.textFont.setReadOnly(True)
@@ -1103,10 +1094,6 @@ class _FormatTab(QWidget):
def loadContent(self) -> None:
"""Populate the widgets."""
- langIdx = self.buildLang.findData(self._build.getStr("format.buildLang"))
- if langIdx != -1:
- self.buildLang.setCurrentIndex(langIdx)
-
textFont = self._build.getStr("format.textFont")
if not textFont:
textFont = str(CONFIG.textFont)
@@ -1146,7 +1133,6 @@ class _FormatTab(QWidget):
def saveContent(self) -> None:
"""Save choices back into build object."""
- self._build.setValue("format.buildLang", str(self.buildLang.currentData()))
self._build.setValue("format.textFont", self.textFont.text())
self._build.setValue("format.textSize", self.textSize.value())
self._build.setValue("format.lineHeight", self.lineHeight.value())
From e3997b53aa6687d809557202e9b8a6b3576b33e5 Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Thu, 9 Nov 2023 18:55:02 +0100
Subject: [PATCH 5/6] Add language setting to wizard
---
novelwriter/core/coretools.py | 2 ++
novelwriter/dialogs/projsettings.py | 5 ++---
novelwriter/guimain.py | 6 ++++++
novelwriter/tools/projwizard.py | 18 ++++++++++++++++--
4 files changed, 26 insertions(+), 5 deletions(-)
diff --git a/novelwriter/core/coretools.py b/novelwriter/core/coretools.py
index 017ea082..81803576 100644
--- a/novelwriter/core/coretools.py
+++ b/novelwriter/core/coretools.py
@@ -353,11 +353,13 @@ class ProjectBuilder:
projName = data.get("projName", lblNewProject)
projTitle = data.get("projTitle", lblNewProject)
projAuthor = data.get("projAuthor", "")
+ projLang = data.get("projLang", "en_GB")
project.data.setUuid(None)
project.data.setName(projName)
project.data.setTitle(projTitle)
project.data.setAuthor(projAuthor)
+ project.data.setLanguage(projLang)
project.setDefaultStatusImport()
project.session.startSession()
diff --git a/novelwriter/dialogs/projsettings.py b/novelwriter/dialogs/projsettings.py
index 4accfed0..20b11c53 100644
--- a/novelwriter/dialogs/projsettings.py
+++ b/novelwriter/dialogs/projsettings.py
@@ -232,9 +232,8 @@ class GuiProjectEditMain(QWidget):
self.projLang = QComboBox(self)
self.projLang.setMaximumWidth(xW)
- if CONFIG.hasEnchant:
- for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
- self.projLang.addItem(language, tag)
+ for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
+ self.projLang.addItem(language, tag)
self.mainForm.addRow(
self.tr("Project language"),
self.projLang,
diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py
index 41301476..519a40cf 100644
--- a/novelwriter/guimain.py
+++ b/novelwriter/guimain.py
@@ -1482,6 +1482,12 @@ class GuiMain(QMainWindow):
projData["numChapters"] = newProj.field("numChapters")
projData["numScenes"] = newProj.field("numScenes")
+ try:
+ langIdx = newProj.field("projLang")
+ projData["projLang"] = CONFIG.listLanguages(CONFIG.LANG_PROJ)[langIdx][0]
+ except Exception:
+ projData["projLang"] = "en_GB"
+
return projData
def _getTagSource(self, tag: str) -> tuple[str | None, str | None]:
diff --git a/novelwriter/tools/projwizard.py b/novelwriter/tools/projwizard.py
index ef715847..b47da1cf 100644
--- a/novelwriter/tools/projwizard.py
+++ b/novelwriter/tools/projwizard.py
@@ -28,8 +28,9 @@ import logging
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (
- QFileDialog, QFormLayout, QGridLayout, QHBoxLayout, QLabel, QLineEdit,
- QPushButton, QRadioButton, QSpinBox, QVBoxLayout, QWizard, QWizardPage
+ QComboBox, QFileDialog, QFormLayout, QGridLayout, QHBoxLayout, QLabel,
+ QLineEdit, QPushButton, QRadioButton, QSpinBox, QVBoxLayout, QWizard,
+ QWizardPage
)
from novelwriter import CONFIG, SHARED
@@ -127,15 +128,28 @@ class ProjWizardIntroPage(QWizardPage):
self.projAuthor.setFixedWidth(xW)
self.projAuthor.setPlaceholderText(self.tr("Optional"))
+ self.projLang = QComboBox(self)
+ self.projLang.setMaximumWidth(xW)
+ for tag, language in CONFIG.listLanguages(CONFIG.LANG_PROJ):
+ self.projLang.addItem(language, tag)
+
+ langIdx = self.projLang.findData(CONFIG.guiLocale)
+ if langIdx == -1:
+ langIdx = self.projLang.findData("en_GB")
+ if langIdx != -1:
+ self.projLang.setCurrentIndex(langIdx)
+
self.mainForm = QFormLayout()
self.mainForm.addRow(self.tr("Project Name"), self.projName)
self.mainForm.addRow(self.tr("Novel Title"), self.projTitle)
self.mainForm.addRow(self.tr("Author(s)"), self.projAuthor)
+ self.mainForm.addRow(self.tr("Language"), self.projLang)
self.mainForm.setVerticalSpacing(fS)
self.registerField("projName*", self.projName)
self.registerField("projTitle", self.projTitle)
self.registerField("projAuthor", self.projAuthor)
+ self.registerField("projLang", self.projLang)
# Assemble
self.outerBox = QVBoxLayout()
From 76d67dd0aaaf46f2339038fd3ba836b07db7767d Mon Sep 17 00:00:00 2001
From: Veronica Berglyd Olsen <1619840+vkbo@users.noreply.github.com>
Date: Thu, 9 Nov 2023 19:04:36 +0100
Subject: [PATCH 6/6] Clean up build settings and update tests
---
novelwriter/core/buildsettings.py | 2 --
novelwriter/core/tohtml.py | 5 ++++-
tests/reference/coreTools_NewMinimal_nwProject.nwx | 2 +-
tests/test_core/test_core_coretools.py | 2 ++
tests/test_tools/test_tools_manussettings.py | 3 ---
5 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/novelwriter/core/buildsettings.py b/novelwriter/core/buildsettings.py
index 931525ea..0698c2e0 100644
--- a/novelwriter/core/buildsettings.py
+++ b/novelwriter/core/buildsettings.py
@@ -64,7 +64,6 @@ SETTINGS_TEMPLATE = {
"text.includeKeywords": (bool, False),
"text.includeBodyText": (bool, True),
"text.addNoteHeadings": (bool, True),
- "format.buildLang": (str, "en_GB"),
"format.textFont": (str, CONFIG.textFont),
"format.textSize": (int, 12),
"format.lineHeight": (float, 1.15, 0.75, 3.0),
@@ -107,7 +106,6 @@ SETTINGS_LABELS = {
"text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
"format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
- "format.buildLang": QT_TRANSLATE_NOOP("Builds", "Language"),
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Font Family"),
"format.textSize": QT_TRANSLATE_NOOP("Builds", "Font Size"),
"format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
diff --git a/novelwriter/core/tohtml.py b/novelwriter/core/tohtml.py
index ac73418d..7443ed34 100644
--- a/novelwriter/core/tohtml.py
+++ b/novelwriter/core/tohtml.py
@@ -457,7 +457,10 @@ class ToHtml(Tokenizer):
def _formatSynopsis(self, text: str) -> str:
"""Apply HTML formatting to synopsis."""
sSynop = self._localLookup("Synopsis")
- return f"\n"
+ if self._genMode == self.M_PREVIEW:
+ return f"\n"
+ else:
+ return f"{sSynop}: {text}
\n"
def _formatComments(self, text: str) -> str:
"""Apply HTML formatting to comments."""
diff --git a/tests/reference/coreTools_NewMinimal_nwProject.nwx b/tests/reference/coreTools_NewMinimal_nwProject.nwx
index 23a377f5..a38b56b0 100644
--- a/tests/reference/coreTools_NewMinimal_nwProject.nwx
+++ b/tests/reference/coreTools_NewMinimal_nwProject.nwx
@@ -7,7 +7,7 @@
yes
- None
+ en_GB
None
None
diff --git a/tests/test_core/test_core_coretools.py b/tests/test_core/test_core_coretools.py
index a3f4e11c..0f127e05 100644
--- a/tests/test_core/test_core_coretools.py
+++ b/tests/test_core/test_core_coretools.py
@@ -446,6 +446,7 @@ def testCoreTools_NewCustomA(monkeypatch, fncPath, tstPaths, mockRnd):
"projName": "Test Custom",
"projTitle": "Test Novel",
"projAuthor": "Jane Doe",
+ "projLang": -1,
"projPath": fncPath,
"popSample": False,
"popMinimal": False,
@@ -484,6 +485,7 @@ def testCoreTools_NewCustomB(monkeypatch, fncPath, tstPaths, mockRnd):
"projName": "Test Custom",
"projTitle": "Test Novel",
"projAuthor": "Jane Doe",
+ "projLang": -1,
"projPath": fncPath,
"popSample": False,
"popMinimal": False,
diff --git a/tests/test_tools/test_tools_manussettings.py b/tests/test_tools/test_tools_manussettings.py
index 1371caf0..0a5f9c5a 100644
--- a/tests/test_tools/test_tools_manussettings.py
+++ b/tests/test_tools/test_tools_manussettings.py
@@ -562,7 +562,6 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain):
assert bSettings.toolStack.currentWidget() is fmtTab
# Check initial values
- assert fmtTab.buildLang.currentData() == "en_US"
assert fmtTab.textFont.text() == textFont
assert fmtTab.textSize.value() == 12
assert fmtTab.lineHeight.value() == 1.2
@@ -581,7 +580,6 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain):
assert fmtTab.rightMargin.value() == 15.0
# Change values
- fmtTab.buildLang.setCurrentIndex(fmtTab.buildLang.findData("en_GB"))
fmtTab.textFont.setText("Arial")
fmtTab.textSize.setValue(11)
fmtTab.lineHeight.setValue(1.15)
@@ -596,7 +594,6 @@ def testBuildSettings_Format(monkeypatch, qtbot: QtBot, nwGUI: GuiMain):
# Save values
fmtTab.saveContent()
- assert build.getStr("format.buildLang") == "en_GB"
assert build.getStr("format.textFont") == "Arial"
assert build.getInt("format.textSize") == 11
assert build.getFloat("format.lineHeight") == 1.15