Turn main into only release branch (#1408)

This commit is contained in:
Veronica Berglyd Olsen
2023-04-04 17:47:52 +02:00
committed by GitHub
16 changed files with 170 additions and 650 deletions
+24 -12
View File
@@ -19,22 +19,34 @@ Spell Check Dictionaries
novelWriter uses Enchant_ as the spell checking tool. Depending on your operating system, it may or novelWriter uses Enchant_ as the spell checking tool. Depending on your operating system, it may or
may not load installed spell check dictionaries. may not load installed spell check dictionaries.
Linux Linux and MacOS
On Linux, you generally only have to install hunspell or aspell dictionaries on your system like ---------------
you do for other applications. See your distro's documentation for how to do this. These
dictionaries should then show up as available spell check languages in novelWriter. On Linux and MacOS, you generally only have to install hunspell or aspell dictionaries on your
system like you do for other applications. See your distro or OS documentation for how to do this.
These dictionaries should then show up as available spell check languages in novelWriter.
Windows Windows
For Windows, English is included with the installation. For other languages you have to download -------
and add dictionaries yourself. You can find the various dictionaries on the `Free Desktop`_
website. You should find a folder for your language, if it is available at all, and download the
files ending with ``.aff`` and ``.dic``. These files must then be copied to the following
location:
``C:\Users\<USER>\AppData\Local\enchant\hunspell`` For Windows, English is included with the installation. For other languages you have to download
and add dictionaries yourself. You can find the various dictionaries on the `Free Desktop`_
website. You should find a folder for your language, if it is available at all, and download the
files ending with ``.aff`` and ``.dic``. These files must then be copied to the following location:
This assumes your user profile is stored at ``C:\Users\<USER>``. The last one or two folders may ``C:\Users\<USER>\AppData\Local\enchant\hunspell``
not exist, so you may need to create them.
This assumes your user profile is stored at ``C:\Users\<USER>``. The last one or two folders may
not exist, so you may need to create them.
.. note::
The Free Desktop link points to a repository, and what may look like file links inside the
dictionary folder are actually links to web pages. If you right-click and download those, you
get HTML files, not dictionaries!
In order to download the actual dictionary files, right-click the "plain" label at the end of
each line and download that.
.. _a_custom_theme: .. _a_custom_theme:
+1 -1
View File
@@ -51,7 +51,7 @@ Merge Multiple Documents Into One
If you need to merge a set of documents in your project into a single document, you can achieve If you need to merge a set of documents in your project into a single document, you can achieve
this by first making a new folder for just that purpose, and drag all the files you want merged this by first making a new folder for just that purpose, and drag all the files you want merged
into this folder. Then you can right click the folder, select :guilabel:`Transform` and into this folder. Then you can right click the folder, select :guilabel:`Transform` and
:guilabel:`Merge Documents in FOlder`. :guilabel:`Merge Documents in Folder`.
In the dialog that pops up, the documents will be in the same order as in the folder, but you can In the dialog that pops up, the documents will be in the same order as in the folder, but you can
also rearrange them here of you wish. also rearrange them here of you wish.
+10 -10
View File
@@ -3352,44 +3352,44 @@
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
@@ -3405,7 +3405,7 @@
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1207" /> <location filename="../novelwriter/gui/projtree.py" line="1207" />
<source>Change Label</source> <source>Rename</source>
<translation type="unfinished" /> <translation type="unfinished" />
</message> </message>
<message> <message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Neuer Ordner</translation> <translation>Neuer Ordner</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation>Derzeit gibt es keinen Papierkorb für dieses Projekt.</translation> <translation>Derzeit gibt es keinen Papierkorb für dieses Projekt.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation>Papierkorb ist bereits leer.</translation> <translation>Papierkorb ist bereits leer.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation>Papierkorb leeren</translation> <translation>Papierkorb leeren</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation>{0} Element(e) endgültig löschen?</translation> <translation>{0} Element(e) endgültig löschen?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation>Löschen</translation> <translation>Löschen</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation>„{0}“ in den Papierkorb verschieben?</translation> <translation>„{0}“ in den Papierkorb verschieben?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation>Hauptordner können nur gelöscht werden, wenn sie leer sind.</translation> <translation>Hauptordner können nur gelöscht werden, wenn sie leer sind.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation>„{0}“ endgültig löschen?</translation> <translation>„{0}“ endgültig löschen?</translation>
</message> </message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>New Folder</translation> <translation>New Folder</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation>There is currently no Trash folder in this project.</translation> <translation>There is currently no Trash folder in this project.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation>The Trash folder is already empty.</translation> <translation>The Trash folder is already empty.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation>Empty Trash</translation> <translation>Empty Trash</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation>Permanently delete {0} file(s) from Trash?</translation> <translation>Permanently delete {0} file(s) from Trash?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation>Delete</translation> <translation>Delete</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation>Move '{0}' to Trash?</translation> <translation>Move '{0}' to Trash?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation>Root folders can only be deleted when they are empty.</translation> <translation>Root folders can only be deleted when they are empty.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation>Permanently delete '{0}'?</translation> <translation>Permanently delete '{0}'?</translation>
</message> </message>
+10 -10
View File
@@ -1925,7 +1925,7 @@
<message> <message>
<location filename="../novelwriter/gui/mainmenu.py" line="797" /> <location filename="../novelwriter/gui/mainmenu.py" line="797" />
<source>Check Spelling</source> <source>Check Spelling</source>
<translation>Comprobar Ortografía</translation> <translation>Comprobar la Ortografía</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/mainmenu.py" line="805" /> <location filename="../novelwriter/gui/mainmenu.py" line="805" />
@@ -3352,44 +3352,44 @@
<translation>Nueva Carpeta</translation> <translation>Nueva Carpeta</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation>No hay actualmente una carpeta Papelera en este proyecto.</translation> <translation>No hay actualmente una carpeta Papelera en este proyecto.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation>La carpeta Papelera ya está vacía.</translation> <translation>La carpeta Papelera ya está vacía.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation>Vaciar la Papelera</translation> <translation>Vaciar la Papelera</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation>¿Eliminar {0} archivo(s) permanentemente de la Papelera?</translation> <translation>¿Eliminar {0} archivo(s) permanentemente de la Papelera?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation>Eliminar</translation> <translation>Eliminar</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation>¿Mover '{0}' a la Papelera?</translation> <translation>¿Mover '{0}' a la Papelera?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation>Las carpetas raíz sólo pueden eliminarse si están vacías.</translation> <translation>Las carpetas raíz sólo pueden eliminarse si están vacías.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation>¿Eliminar Permanentemente '{0}'?</translation> <translation>¿Eliminar Permanentemente '{0}'?</translation>
</message> </message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Nuova cartella</translation> <translation>Nuova cartella</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation>Al momento non c'è una cartella Cestino in questo progetto.</translation> <translation>Al momento non c'è una cartella Cestino in questo progetto.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation>La cartella Cestino è già vuota.</translation> <translation>La cartella Cestino è già vuota.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation>Svuota il cestino</translation> <translation>Svuota il cestino</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation>Eliminare definitivamente {0} file(s) dal cestino?</translation> <translation>Eliminare definitivamente {0} file(s) dal cestino?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation>Elimina</translation> <translation>Elimina</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation>Spostare '{0}' nel Cestino?</translation> <translation>Spostare '{0}' nel Cestino?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation>Le cartelle radice possono essere eliminate solo quando sono vuote.</translation> <translation>Le cartelle radice possono essere eliminate solo quando sono vuote.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation>Eliminare definitivamente '{0}'?</translation> <translation>Eliminare definitivamente '{0}'?</translation>
</message> </message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Ny mappe</translation> <translation>Ny mappe</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation>Det er for øyeblikket ingen papirkurv i dette prosjektet.</translation> <translation>Det er for øyeblikket ingen papirkurv i dette prosjektet.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation>Papirkurven er allerede tom.</translation> <translation>Papirkurven er allerede tom.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation>Tøm papirkurven</translation> <translation>Tøm papirkurven</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation>Vil du slette {0} filer i papirkurven for godt?</translation> <translation>Vil du slette {0} filer i papirkurven for godt?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation>Slett</translation> <translation>Slett</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation>Vil du flytte filen "{0}" til søpla?</translation> <translation>Vil du flytte filen "{0}" til søpla?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation>Rotmapper kan bare slettes når de er tomme.</translation> <translation>Rotmapper kan bare slettes når de er tomme.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation>Slette filen "{0}" for godt?</translation> <translation>Slette filen "{0}" for godt?</translation>
</message> </message>
+52 -41
View File
@@ -757,32 +757,32 @@
<context> <context>
<name>GuiDocEditFooter</name> <name>GuiDocEditFooter</name>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2924" /> <location filename="../novelwriter/gui/doceditor.py" line="2931" />
<source>Status</source> <source>Status</source>
<translation>Status</translation> <translation>Status</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="3073" /> <location filename="../novelwriter/gui/doceditor.py" line="3080" />
<source>Line: {0} ({1})</source> <source>Line: {0} ({1})</source>
<translation>Regel: {0} ({1})</translation> <translation>Regel: {0} ({1})</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="3102" /> <location filename="../novelwriter/gui/doceditor.py" line="3109" />
<source>Words: {0} ({1})</source> <source>Words: {0} ({1})</source>
<translation>Woorden: {0} ({1})</translation> <translation>Woorden: {0} ({1})</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="3107" /> <location filename="../novelwriter/gui/doceditor.py" line="3114" />
<source>Document size is {0} bytes</source> <source>Document size is {0} bytes</source>
<translation>Document grootte is {0} bytes</translation> <translation>Document grootte is {0} bytes</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="3119" /> <location filename="../novelwriter/gui/doceditor.py" line="3126" />
<source>Words: {0} selected</source> <source>Words: {0} selected</source>
<translation>Woorden: {0} geselecteerd</translation> <translation>Woorden: {0} geselecteerd</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="3122" /> <location filename="../novelwriter/gui/doceditor.py" line="3129" />
<source>Character count: {0}</source> <source>Character count: {0}</source>
<translation>Aantal tekens: {0}</translation> <translation>Aantal tekens: {0}</translation>
</message> </message>
@@ -790,22 +790,22 @@
<context> <context>
<name>GuiDocEditHeader</name> <name>GuiDocEditHeader</name>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2694" /> <location filename="../novelwriter/gui/doceditor.py" line="2701" />
<source>Edit document label</source> <source>Edit document label</source>
<translation>Bewerk document label</translation> <translation>Bewerk document label</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2703" /> <location filename="../novelwriter/gui/doceditor.py" line="2710" />
<source>Search document</source> <source>Search document</source>
<translation>Doorzoek document</translation> <translation>Doorzoek document</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2712" /> <location filename="../novelwriter/gui/doceditor.py" line="2719" />
<source>Toggle Focus Mode</source> <source>Toggle Focus Mode</source>
<translation>Schakel focus modus in/uit</translation> <translation>Schakel focus modus in/uit</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2721" /> <location filename="../novelwriter/gui/doceditor.py" line="2728" />
<source>Close the document</source> <source>Close the document</source>
<translation>Sluit het document</translation> <translation>Sluit het document</translation>
</message> </message>
@@ -813,58 +813,58 @@
<context> <context>
<name>GuiDocEditSearch</name> <name>GuiDocEditSearch</name>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2287" /> <location filename="../novelwriter/gui/doceditor.py" line="2294" />
<location filename="../novelwriter/gui/doceditor.py" line="2274" /> <location filename="../novelwriter/gui/doceditor.py" line="2281" />
<source>Search</source> <source>Search</source>
<translation>Zoek</translation> <translation>Zoek</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2279" /> <location filename="../novelwriter/gui/doceditor.py" line="2286" />
<source>Replace</source> <source>Replace</source>
<translation>Vervang</translation> <translation>Vervang</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2295" /> <location filename="../novelwriter/gui/doceditor.py" line="2302" />
<source>Case Sensitive</source> <source>Case Sensitive</source>
<translation>Hoofdlettergevoelig</translation> <translation>Hoofdlettergevoelig</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2301" /> <location filename="../novelwriter/gui/doceditor.py" line="2308" />
<source>Whole Words Only</source> <source>Whole Words Only</source>
<translation>Alleen hele woorden</translation> <translation>Alleen hele woorden</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2307" /> <location filename="../novelwriter/gui/doceditor.py" line="2314" />
<source>RegEx Mode</source> <source>RegEx Mode</source>
<translation>RegEx modus</translation> <translation>RegEx modus</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2313" /> <location filename="../novelwriter/gui/doceditor.py" line="2320" />
<source>Loop Search</source> <source>Loop Search</source>
<translation>Zoekopdracht lus</translation> <translation>Zoekopdracht lus</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2319" /> <location filename="../novelwriter/gui/doceditor.py" line="2326" />
<source>Search Next File</source> <source>Search Next File</source>
<translation>Doorzoek volgend bestand</translation> <translation>Doorzoek volgend bestand</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2327" /> <location filename="../novelwriter/gui/doceditor.py" line="2334" />
<source>Preserve Case</source> <source>Preserve Case</source>
<translation>Behoud hoofd/kleine letters</translation> <translation>Behoud hoofd/kleine letters</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2335" /> <location filename="../novelwriter/gui/doceditor.py" line="2342" />
<source>Close Search</source> <source>Close Search</source>
<translation>Zoekopdracht afsluiten</translation> <translation>Zoekopdracht afsluiten</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2351" /> <location filename="../novelwriter/gui/doceditor.py" line="2358" />
<source>Find in current document</source> <source>Find in current document</source>
<translation>Zoeken in huidige document</translation> <translation>Zoeken in huidige document</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/doceditor.py" line="2356" /> <location filename="../novelwriter/gui/doceditor.py" line="2363" />
<source>Find and replace in current document</source> <source>Find and replace in current document</source>
<translation>Zoek en vervang in huidig document</translation> <translation>Zoek en vervang in huidig document</translation>
</message> </message>
@@ -2050,55 +2050,66 @@
<context> <context>
<name>GuiNovelToolBar</name> <name>GuiNovelToolBar</name>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="207" /> <location filename="../novelwriter/gui/noveltree.py" line="216" />
<source>Outline of {0}</source> <source>Outline of {0}</source>
<translation>Omlijning van {0}</translation> <translation>Omlijning van {0}</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="215" /> <location filename="../novelwriter/gui/noveltree.py" line="224" />
<source>Novel Root</source> <source>Novel Root</source>
<translation>Roman Hoofdmap</translation> <translation>Roman Hoofdmap</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="221" /> <location filename="../novelwriter/gui/noveltree.py" line="230" />
<source>Refresh</source> <source>Refresh</source>
<translation>Verversen</translation> <translation>Verversen</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="228" /> <location filename="../novelwriter/gui/noveltree.py" line="237" />
<source>Last Column</source> <source>Last Column</source>
<translation>Laatste Kolom</translation> <translation>Laatste Kolom</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="231" /> <location filename="../novelwriter/gui/noveltree.py" line="240" />
<source>Hidden</source> <source>Hidden</source>
<translation>Verborgen</translation> <translation>Verborgen</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="232" /> <location filename="../novelwriter/gui/noveltree.py" line="241" />
<source>Point of View Character</source> <source>Point of View Character</source>
<translation>Perspectief Karakter</translation> <translation>Perspectief Karakter</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="233" /> <location filename="../novelwriter/gui/noveltree.py" line="242" />
<source>Focus Character</source> <source>Focus Character</source>
<translation>Focus Karakter</translation> <translation>Focus Karakter</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="234" /> <location filename="../novelwriter/gui/noveltree.py" line="243" />
<source>Novel Plot</source> <source>Novel Plot</source>
<translation>Roman Plot</translation> <translation>Roman Plot</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="237" /> <location filename="../novelwriter/gui/noveltree.py" line="361" />
<location filename="../novelwriter/gui/noveltree.py" line="246" />
<source>Column Size</source>
<translation>Kolom grootte</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="250" />
<source>More Options</source> <source>More Options</source>
<translation>Meer Opties</translation> <translation>Meer Opties</translation>
</message> </message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="361" />
<source>Maximum column size in %</source>
<translation>Maximum kolom grootte in %</translation>
</message>
</context> </context>
<context> <context>
<name>GuiNovelTree</name> <name>GuiNovelTree</name>
<message> <message>
<location filename="../novelwriter/gui/noveltree.py" line="778" /> <location filename="../novelwriter/gui/noveltree.py" line="815" />
<source>No meta data</source> <source>No meta data</source>
<translation>Geen metadata</translation> <translation>Geen metadata</translation>
</message> </message>
@@ -3341,44 +3352,44 @@
<translation>Nieuwe map</translation> <translation>Nieuwe map</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation>Er is momenteel geen Prullenbak map in dit project.</translation> <translation>Er is momenteel geen Prullenbak map in dit project.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation>De Prullenbak map is al leeg.</translation> <translation>De Prullenbak map is al leeg.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation>Prullenbak legen</translation> <translation>Prullenbak legen</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation>{0} bestand(en) permanent verwijderen uit de prullenbak?</translation> <translation>{0} bestand(en) permanent verwijderen uit de prullenbak?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation>Verwijderen</translation> <translation>Verwijderen</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation>Verplaats '{0}' naar Prullenbak?</translation> <translation>Verplaats '{0}' naar Prullenbak?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation>Root mappen kunnen alleen verwijderd worden wanneer ze leeg zijn.</translation> <translation>Root mappen kunnen alleen verwijderd worden wanneer ze leeg zijn.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation>'{0}' permanent verwijderen?</translation> <translation>'{0}' permanent verwijderen?</translation>
</message> </message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Novo Diretório</translation> <translation>Novo Diretório</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="788" /> <location filename="../novelwriter/gui/projtree.py" line="789" />
<source>There is currently no Trash folder in this project.</source> <source>There is currently no Trash folder in this project.</source>
<translation>Não exite um diretório de Lixeira neste projeto.</translation> <translation>Não exite um diretório de Lixeira neste projeto.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="799" /> <location filename="../novelwriter/gui/projtree.py" line="800" />
<source>The Trash folder is already empty.</source> <source>The Trash folder is already empty.</source>
<translation>O diretório de Lixeira está vazio.</translation> <translation>O diretório de Lixeira está vazio.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="1181" /> <location filename="../novelwriter/gui/projtree.py" line="1181" />
<location filename="../novelwriter/gui/projtree.py" line="805" /> <location filename="../novelwriter/gui/projtree.py" line="806" />
<source>Empty Trash</source> <source>Empty Trash</source>
<translation>Esvaziar a Lixeira</translation> <translation>Esvaziar a Lixeira</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="806" /> <location filename="../novelwriter/gui/projtree.py" line="807" />
<source>Permanently delete {0} file(s) from Trash?</source> <source>Permanently delete {0} file(s) from Trash?</source>
<translation>Permanentemente remover {0} arquivo(s) da Lixeira?</translation> <translation>Permanentemente remover {0} arquivo(s) da Lixeira?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="908" /> <location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="852" /> <location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source> <source>Delete</source>
<translation>Excluir</translation> <translation>Excluir</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="853" /> <location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source> <source>Move '{0}' to Trash?</source>
<translation>Mover '{0}' para a Lixeira?</translation> <translation>Mover '{0}' para a Lixeira?</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="887" /> <location filename="../novelwriter/gui/projtree.py" line="888" />
<source>Root folders can only be deleted when they are empty.</source> <source>Root folders can only be deleted when they are empty.</source>
<translation>Os diretórios-raiz podem ser excluídos quando estiverem vazios.</translation> <translation>Os diretórios-raiz podem ser excluídos quando estiverem vazios.</translation>
</message> </message>
<message> <message>
<location filename="../novelwriter/gui/projtree.py" line="909" /> <location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source> <source>Permanently delete '{0}'?</source>
<translation>Excluir permanentemente '{0}?</translation> <translation>Excluir permanentemente '{0}?</translation>
</message> </message>
+5 -3
View File
@@ -59,9 +59,9 @@ __license__ = "GPLv3"
__author__ = "Veronica Berglyd Olsen" __author__ = "Veronica Berglyd Olsen"
__maintainer__ = "Veronica Berglyd Olsen" __maintainer__ = "Veronica Berglyd Olsen"
__email__ = "code@vkbo.net" __email__ = "code@vkbo.net"
__version__ = "2.1-alpha0" __version__ = "2.0.6"
__hexversion__ = "0x020100a0" __hexversion__ = "0x020006f0"
__date__ = "2023-02-12" __date__ = "2023-02-26"
__status__ = "Stable" __status__ = "Stable"
__domain__ = "novelwriter.io" __domain__ = "novelwriter.io"
__url__ = "https://novelwriter.io" __url__ = "https://novelwriter.io"
@@ -246,6 +246,8 @@ def main(sysArgs=None):
nwApp.setApplicationName(CONFIG.appName) nwApp.setApplicationName(CONFIG.appName)
nwApp.setApplicationVersion(__version__) nwApp.setApplicationVersion(__version__)
nwApp.setOrganizationDomain(__domain__) nwApp.setOrganizationDomain(__domain__)
nwApp.setOrganizationName(__domain__)
nwApp.setDesktopFileName(CONFIG.appName)
# Connect the exception handler before making the main GUI # Connect the exception handler before making the main GUI
sys.excepthook = exceptionHandler sys.excepthook = exceptionHandler
+1 -1
View File
@@ -1359,7 +1359,7 @@ class GuiDocEditor(QTextEdit):
if self._docHandle is None or self._nwItem is None: if self._docHandle is None or self._nwItem is None:
return return
logger.debug("User selectee %d words", wCount) logger.debug("User selected %d words", wCount)
self.docFooter.updateCounts(wCount=wCount, cCount=cCount) self.docFooter.updateCounts(wCount=wCount, cCount=cCount)
self.wcTimerSel.stop() self.wcTimerSel.stop()
+22 -1
View File
@@ -38,6 +38,7 @@ from PyQt5.QtWidgets import (
QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem, QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
QVBoxLayout, QWidget QVBoxLayout, QWidget
) )
from novelwriter.core.item import NWItem
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert, nwWidget from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert, nwWidget
from novelwriter.constants import nwHeaders, nwUnicode, trConst, nwLabels from novelwriter.constants import nwHeaders, nwUnicode, trConst, nwLabels
@@ -108,6 +109,9 @@ class GuiProjectView(QWidget):
self.keyContext.setContext(Qt.WidgetShortcut) self.keyContext.setContext(Qt.WidgetShortcut)
self.keyContext.activated.connect(lambda: self.projTree.openContextOnSelected()) self.keyContext.activated.connect(lambda: self.projTree.openContextOnSelected())
# Signals
self.selectedItemChanged.connect(self.projBar._treeSelectionChanged)
# Function Mappings # Function Mappings
self.emptyTrash = self.projTree.emptyTrash self.emptyTrash = self.projTree.emptyTrash
self.requestDeleteItem = self.projTree.requestDeleteItem self.requestDeleteItem = self.projTree.requestDeleteItem
@@ -418,6 +422,23 @@ class GuiProjectToolBar(QWidget):
return return
##
# Slots
##
@pyqtSlot(str)
def _treeSelectionChanged(self, tHandle):
"""Toggle the visibility of the new item enties for novel
documents. They should only be visible if novel documents can
actually be added.
"""
nwItem = self.theProject.tree[tHandle]
allowDoc = isinstance(nwItem, NWItem) and nwItem.documentAllowed()
self.aAddEmpty.setVisible(allowDoc)
self.aAddChap.setVisible(allowDoc)
self.aAddScene.setVisible(allowDoc)
return
# END Class GuiProjectToolBar # END Class GuiProjectToolBar
@@ -1204,7 +1225,7 @@ class GuiProjectTree(QTreeWidget):
# Edit Item Settings # Edit Item Settings
# ================== # ==================
aLabel = ctxMenu.addAction(self.tr("Change Label")) aLabel = ctxMenu.addAction(self.tr("Rename"))
aLabel.triggered.connect(lambda: self.renameTreeItem(tHandle)) aLabel.triggered.connect(lambda: self.renameTreeItem(tHandle))
if isFile: if isFile:
-3
View File
@@ -1,3 +0,0 @@
"""
novelWriter Manuscript Build Init File
"""
-241
View File
@@ -1,241 +0,0 @@
"""
novelWriter Build Document Tool
=================================
A class to build one or more novelWriter files to a single document
File History:
Created: 2022-12-01 [2.1b1]
This file is a part of novelWriter
Copyright 20182023, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import logging
import novelwriter
from PyQt5.QtGui import QFont, QFontInfo
from novelwriter.error import formatException
from novelwriter.core.tomd import ToMarkdown
from novelwriter.core.toodt import ToOdt
from novelwriter.core.tohtml import ToHtml
logger = logging.getLogger(__name__)
class NWBuildDocument:
def __init__(self, project):
self._conf = novelwriter.CONFIG
self._project = project
self._build = {}
self._documents = []
self._error = None
return
##
# Properties
##
@property
def error(self):
return self._error
@property
def buildLength(self):
return len(self._documents)
##
# Setters
##
def setBuildConfig(self, config):
"""Set the build config dictionary.
"""
self._build = config
return
def addDocument(self, tHandle):
"""Add a document to the build queue.
"""
self._documents.append(tHandle)
return
##
# Methods
##
def iterBuildOpenDocument(self, savePath, isFlat):
"""Build an Open Document file.
"""
makeOdt = ToOdt(self._project, isFlat=isFlat)
self._setupBuild(makeOdt)
makeOdt.initDocument()
for i, tHandle in enumerate(self._documents):
yield i, self._doBuild(makeOdt, tHandle)
makeOdt.closeDocument()
self._error = None
try:
if isFlat:
makeOdt.saveFlatXML(savePath)
else:
makeOdt.saveOpenDocText(savePath)
except Exception as exc:
self._error = formatException(exc)
return
def iterBuildHTML(self, savePath):
"""Build an HTML file.
"""
makeHtml = ToHtml(self._project)
self._setupBuild(makeHtml)
if self._build.get("process.replaceTabs", False):
makeHtml.replaceTabs()
for i, tHandle in enumerate(self._documents):
yield i, self._doBuild(makeHtml, tHandle)
self._error = None
try:
makeHtml.saveHTML5(savePath)
except Exception as exc:
self._error = formatException(exc)
return
def iterBuildMarkdown(self, savePath, extendedMd):
"""Build a Markdown file.
"""
makeMd = ToMarkdown(self._project)
self._setupBuild(makeMd)
if extendedMd:
makeMd.setGitHubMarkdown()
else:
makeMd.setStandardMarkdown()
if self._build.get("process.replaceTabs", False):
makeMd.replaceTabs(nSpaces=4, spaceChar=" ")
for i, tHandle in enumerate(self._documents):
yield i, self._doBuild(makeMd, tHandle)
self._error = None
try:
makeMd.saveMarkdown(savePath)
except Exception as exc:
self._error = formatException(exc)
return
##
# Internal Functions
##
def _setupBuild(self, bldObj):
"""Configure the build object.
"""
# Get Settings
fmtTitle = self._build.get("format.fmtTitle", "%title%")
fmtChapter = self._build.get("format.fmtChapter", "%title%")
fmtUnnumbered = self._build.get("format.fmtUnnumbered", "%title%")
fmtScene = self._build.get("format.fmtScene", "%title%")
fmtSection = self._build.get("format.fmtSection", "%title%")
buildLang = self._build.get("format.buildLang", "en_GB")
hideScene = self._build.get("format.hideScene", False)
hideSection = self._build.get("format.hideSection", False)
textFont = self._build.get("format.textFont", self._conf.textFont)
textSize = self._build.get("format.textSize", self._conf.textSize)
lineHeight = self._build.get("format.lineHeight", 1.15)
justifyText = self._build.get("format.justifyText", False)
noStyling = self._build.get("format.noStyling", False)
replaceUCode = self._build.get("format.replaceUCode", False)
incSynopsis = self._build.get("filter.includeSynopsis", False)
incComments = self._build.get("filter.includeComments", False)
incKeywords = self._build.get("filter.includeKeywords", False)
includeBody = self._build.get("filter.includeBody", True)
# The language lookup dict is reloaded if needed
self._project.setProjectLang(buildLang)
# Get font information
fontInfo = QFontInfo(QFont(textFont, textSize))
textFixed = fontInfo.fixedPitch()
bldObj.setTitleFormat(fmtTitle)
bldObj.setChapterFormat(fmtChapter)
bldObj.setUnNumberedFormat(fmtUnnumbered)
bldObj.setSceneFormat(fmtScene, hideScene)
bldObj.setSectionFormat(fmtSection, hideSection)
bldObj.setFont(textFont, textSize, textFixed)
bldObj.setJustify(justifyText)
bldObj.setLineHeight(lineHeight)
bldObj.setSynopsis(incSynopsis)
bldObj.setComments(incComments)
bldObj.setKeywords(incKeywords)
bldObj.setBodyText(includeBody)
if isinstance(bldObj, ToHtml):
bldObj.setStyles(not noStyling)
bldObj.setReplaceUnicode(replaceUCode)
if isinstance(bldObj, ToOdt):
bldObj.setColourHeaders(not noStyling)
bldObj.setLanguage(buildLang)
return
def _doBuild(self, bldObj, tHandle):
"""Build a single document and add it to the build object.
"""
self._error = None
tItem = self._project.tree[tHandle]
if tItem is None:
self._error = f"Build: Unknown item '{tHandle}'"
logger.error(self._error)
return False
try:
if tItem.isRootType() and not tItem.isNovelLike():
bldObj.addRootHeading(tItem.itemHandle)
bldObj.doConvert()
elif tItem.isFileType():
bldObj.setText(tHandle)
bldObj.doPreProcessing()
bldObj.tokenizeText()
bldObj.doHeaders()
bldObj.doConvert()
bldObj.doPostProcessing()
else:
logger.info(f"Build: Skipping '{tHandle}'")
except Exception:
self._error = f"Build: Failed to build '{tHandle}'"
logger.error(self._error)
return False
return True
# END Class NWBuildDocument
-282
View File
@@ -1,282 +0,0 @@
"""
novelWriter Manuscript Builder Class Tests
============================================
This file is a part of novelWriter
Copyright 20182023, Veronica Berglyd Olsen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import pytest
from shutil import copyfile
from mock import causeException, causeOSError
from tools import ODT_IGNORE, cmpFiles
from novelwriter.core.project import NWProject
from novelwriter.mbuild.docbuild import NWBuildDocument
BUILD_CONF = {
"format.fmtTitle": "Title: %title%",
"format.fmtChapter": "Chapter: %title%",
"format.fmtUnnumbered": "%title%",
"format.fmtScene": "Scene: %title%",
"format.fmtSection": "Section: %title%",
"format.buildLang": "en_GB",
"format.hideScene": False,
"format.hideSection": False,
"format.textFont": "Arial",
"format.textSize": 12,
"format.lineHeight": 1.5,
"format.justifyText": True,
"format.noStyling": False,
"format.replaceUCode": False,
"filter.includeSynopsis": True,
"filter.includeComments": True,
"filter.includeKeywords": True,
"filter.includeBody": True,
"process.replaceTabs": True,
}
@pytest.mark.core
def testMBuildDocBuild_OpenDocument(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
"""Test builing an open document manuscript.
"""
theProject = NWProject(mockGUI)
theProject.openProject(prjLipsum)
docBuild = NWBuildDocument(theProject)
docBuild.setBuildConfig(BUILD_CONF)
for tItem in theProject.tree:
docBuild.addDocument(tItem.itemHandle)
assert docBuild.buildLength == 21
# Check FODT Build
# ================
docFile = fncPath / "Lorem Ipsum.fodt"
tstFile = tstPaths.outDir / "mBuildDocBuild_OpenDocument_Lorem_Ipsum.fodt"
cmpFile = tstPaths.refDir / "mBuildDocBuild_OpenDocument_Lorem_Ipsum.fodt"
count = 0
error = []
for _, success in docBuild.iterBuildOpenDocument(docFile, True):
count += 1 if success else 0
if docBuild.error:
error.append(docBuild.error)
assert count == 21
assert error == []
copyfile(docFile, tstFile)
assert cmpFiles(tstFile, cmpFile, ignoreStart=ODT_IGNORE)
# Check ODT Build
# ===============
docFile = fncPath / "Lorem Ipsum.odt"
count = 0
error = []
for _, success in docBuild.iterBuildOpenDocument(docFile, False):
count += 1 if success else 0
if docBuild.error:
error.append(docBuild.error)
assert count == 21
assert error == []
assert docFile.is_file()
# Check Error Handling
# ====================
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
docFile = fncPath / "Lorem Ipsum Err.fodt"
for _ in docBuild.iterBuildOpenDocument(docFile, True):
pass
assert docBuild.error == "OSError: Mock OSError"
assert not docFile.is_file()
# Check Build Issues
# ==================
with monkeypatch.context() as mp:
mp.setattr("novelwriter.core.toodt.ToOdt.doConvert", causeException)
docBuild.addDocument("0000000000000")
assert docBuild.buildLength == 22
count = 0
error = []
docFile = fncPath / "Lorem Ipsum Err.fodt"
for _, success in docBuild.iterBuildOpenDocument(docFile, True):
count += 1 if success else 0
if docBuild.error:
error.append(docBuild.error)
assert count == 3
assert error == [
"Build: Failed to build '7a992350f3eb6'",
"Build: Failed to build '8c58a65414c23'",
"Build: Failed to build '88d59a277361b'",
"Build: Failed to build 'db7e733775d4d'",
"Build: Failed to build 'fb609cd8319dc'",
"Build: Failed to build '88243afbe5ed8'",
"Build: Failed to build 'f96ec11c6a3da'",
"Build: Failed to build '846352075de7d'",
"Build: Failed to build '441420a886d82'",
"Build: Failed to build 'eb103bc70c90c'",
"Build: Failed to build 'f8c0562e50f1b'",
"Build: Failed to build '47666c91c7ccf'",
"Build: Failed to build '67a8707f2f249'",
"Build: Failed to build '4c4f28287af27'",
"Build: Failed to build '6c6afb1247750'",
"Build: Failed to build '2426c6f0ca922'",
"Build: Failed to build '60bdf227455cc'",
"Build: Failed to build '04468803b92e1'",
"Build: Unknown item '0000000000000'",
]
# END Test testMBuildDocBuild_OpenDocument
@pytest.mark.core
def testMBuildDocBuild_HTML(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
"""Test builing an HTML manuscript.
"""
theProject = NWProject(mockGUI)
theProject.openProject(prjLipsum)
docBuild = NWBuildDocument(theProject)
docBuild.setBuildConfig(BUILD_CONF)
for tItem in theProject.tree:
docBuild.addDocument(tItem.itemHandle)
assert docBuild.buildLength == 21
# Check HTML5 Build
# =================
docFile = fncPath / "Lorem Ipsum.htm"
tstFile = tstPaths.outDir / "mBuildDocBuild_HTML5_Lorem_Ipsum.htm"
cmpFile = tstPaths.refDir / "mBuildDocBuild_HTML5_Lorem_Ipsum.htm"
count = 0
error = []
for _, success in docBuild.iterBuildHTML(docFile):
count += 1 if success else 0
if docBuild.error:
error.append(docBuild.error)
assert count == 21
assert error == []
copyfile(docFile, tstFile)
assert cmpFiles(tstFile, cmpFile)
# Check Error Handling
# ====================
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
docFile = fncPath / "Lorem Ipsum Err.htm"
for _ in docBuild.iterBuildHTML(docFile):
pass
assert docBuild.error == "OSError: Mock OSError"
assert not docFile.is_file()
# END Test testMBuildDocBuild_HTML
@pytest.mark.core
def testMBuildDocBuild_Markdown(monkeypatch, mockGUI, prjLipsum, fncPath, tstPaths):
"""Test builing an Markdown manuscript.
"""
theProject = NWProject(mockGUI)
theProject.openProject(prjLipsum)
docBuild = NWBuildDocument(theProject)
docBuild.setBuildConfig(BUILD_CONF)
for tItem in theProject.tree:
docBuild.addDocument(tItem.itemHandle)
assert docBuild.buildLength == 21
# Check Standard Markdown Build
# =============================
docFile = fncPath / "Lorem Ipsum Standard.md"
tstFile = tstPaths.outDir / "mBuildDocBuild_Standard_Markdown_Lorem_Ipsum.md"
cmpFile = tstPaths.refDir / "mBuildDocBuild_Standard_Markdown_Lorem_Ipsum.md"
count = 0
error = []
for _, success in docBuild.iterBuildMarkdown(docFile, False):
count += 1 if success else 0
if docBuild.error:
error.append(docBuild.error)
assert count == 21
assert error == []
copyfile(docFile, tstFile)
assert cmpFiles(tstFile, cmpFile)
# Check Extended Markdown Build
# =============================
docFile = fncPath / "Lorem Ipsum Standard.md"
tstFile = tstPaths.outDir / "mBuildDocBuild_Extended_Markdown_Lorem_Ipsum.md"
cmpFile = tstPaths.refDir / "mBuildDocBuild_Extended_Markdown_Lorem_Ipsum.md"
count = 0
error = []
for _, success in docBuild.iterBuildMarkdown(docFile, True):
count += 1 if success else 0
if docBuild.error:
error.append(docBuild.error)
assert count == 21
assert error == []
copyfile(docFile, tstFile)
assert cmpFiles(tstFile, cmpFile)
# Check Error Handling
# ====================
with monkeypatch.context() as mp:
mp.setattr("builtins.open", causeOSError)
docFile = fncPath / "Lorem Ipsum Err.md"
for _ in docBuild.iterBuildMarkdown(docFile, False):
pass
assert docBuild.error == "OSError: Mock OSError"
assert not docFile.is_file()
# END Test testMBuildDocBuild_Markdown