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
may not load installed spell check dictionaries.
Linux
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.
Linux and MacOS
---------------
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
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
not exist, so you may need to create them.
``C:\Users\<USER>\AppData\Local\enchant\hunspell``
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:
+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
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
: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
also rearrange them here of you wish.
+10 -10
View File
@@ -3352,44 +3352,44 @@
<translation type="unfinished" />
</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>
<translation type="unfinished" />
</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>
<translation type="unfinished" />
</message>
<message>
<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>
<translation type="unfinished" />
</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>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation type="unfinished" />
</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>
<translation type="unfinished" />
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation type="unfinished" />
</message>
@@ -3405,7 +3405,7 @@
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="1207" />
<source>Change Label</source>
<source>Rename</source>
<translation type="unfinished" />
</message>
<message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Neuer Ordner</translation>
</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>
<translation>Derzeit gibt es keinen Papierkorb für dieses Projekt.</translation>
</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>
<translation>Papierkorb ist bereits leer.</translation>
</message>
<message>
<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>
<translation>Papierkorb leeren</translation>
</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>
<translation>{0} Element(e) endgültig löschen?</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation>Löschen</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation>„{0}“ in den Papierkorb verschieben?</translation>
</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>
<translation>Hauptordner können nur gelöscht werden, wenn sie leer sind.</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation>„{0}“ endgültig löschen?</translation>
</message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>New Folder</translation>
</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>
<translation>There is currently no Trash folder in this project.</translation>
</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>
<translation>The Trash folder is already empty.</translation>
</message>
<message>
<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>
<translation>Empty Trash</translation>
</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>
<translation>Permanently delete {0} file(s) from Trash?</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation>Delete</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation>Move '{0}' to Trash?</translation>
</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>
<translation>Root folders can only be deleted when they are empty.</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation>Permanently delete '{0}'?</translation>
</message>
+10 -10
View File
@@ -1925,7 +1925,7 @@
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="797" />
<source>Check Spelling</source>
<translation>Comprobar Ortografía</translation>
<translation>Comprobar la Ortografía</translation>
</message>
<message>
<location filename="../novelwriter/gui/mainmenu.py" line="805" />
@@ -3352,44 +3352,44 @@
<translation>Nueva Carpeta</translation>
</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>
<translation>No hay actualmente una carpeta Papelera en este proyecto.</translation>
</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>
<translation>La carpeta Papelera ya está vacía.</translation>
</message>
<message>
<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>
<translation>Vaciar la Papelera</translation>
</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>
<translation>¿Eliminar {0} archivo(s) permanentemente de la Papelera?</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation>Eliminar</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation>¿Mover '{0}' a la Papelera?</translation>
</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>
<translation>Las carpetas raíz sólo pueden eliminarse si están vacías.</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation>¿Eliminar Permanentemente '{0}'?</translation>
</message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Nuova cartella</translation>
</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>
<translation>Al momento non c'è una cartella Cestino in questo progetto.</translation>
</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>
<translation>La cartella Cestino è già vuota.</translation>
</message>
<message>
<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>
<translation>Svuota il cestino</translation>
</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>
<translation>Eliminare definitivamente {0} file(s) dal cestino?</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation>Elimina</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation>Spostare '{0}' nel Cestino?</translation>
</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>
<translation>Le cartelle radice possono essere eliminate solo quando sono vuote.</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation>Eliminare definitivamente '{0}'?</translation>
</message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Ny mappe</translation>
</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>
<translation>Det er for øyeblikket ingen papirkurv i dette prosjektet.</translation>
</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>
<translation>Papirkurven er allerede tom.</translation>
</message>
<message>
<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>
<translation>Tøm papirkurven</translation>
</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>
<translation>Vil du slette {0} filer i papirkurven for godt?</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation>Slett</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation>Vil du flytte filen "{0}" til søpla?</translation>
</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>
<translation>Rotmapper kan bare slettes når de er tomme.</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation>Slette filen "{0}" for godt?</translation>
</message>
+52 -41
View File
@@ -757,32 +757,32 @@
<context>
<name>GuiDocEditFooter</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2924" />
<location filename="../novelwriter/gui/doceditor.py" line="2931" />
<source>Status</source>
<translation>Status</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3073" />
<location filename="../novelwriter/gui/doceditor.py" line="3080" />
<source>Line: {0} ({1})</source>
<translation>Regel: {0} ({1})</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3102" />
<location filename="../novelwriter/gui/doceditor.py" line="3109" />
<source>Words: {0} ({1})</source>
<translation>Woorden: {0} ({1})</translation>
</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>
<translation>Document grootte is {0} bytes</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3119" />
<location filename="../novelwriter/gui/doceditor.py" line="3126" />
<source>Words: {0} selected</source>
<translation>Woorden: {0} geselecteerd</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="3122" />
<location filename="../novelwriter/gui/doceditor.py" line="3129" />
<source>Character count: {0}</source>
<translation>Aantal tekens: {0}</translation>
</message>
@@ -790,22 +790,22 @@
<context>
<name>GuiDocEditHeader</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2694" />
<location filename="../novelwriter/gui/doceditor.py" line="2701" />
<source>Edit document label</source>
<translation>Bewerk document label</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2703" />
<location filename="../novelwriter/gui/doceditor.py" line="2710" />
<source>Search document</source>
<translation>Doorzoek document</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2712" />
<location filename="../novelwriter/gui/doceditor.py" line="2719" />
<source>Toggle Focus Mode</source>
<translation>Schakel focus modus in/uit</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2721" />
<location filename="../novelwriter/gui/doceditor.py" line="2728" />
<source>Close the document</source>
<translation>Sluit het document</translation>
</message>
@@ -813,58 +813,58 @@
<context>
<name>GuiDocEditSearch</name>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2287" />
<location filename="../novelwriter/gui/doceditor.py" line="2274" />
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
<location filename="../novelwriter/gui/doceditor.py" line="2281" />
<source>Search</source>
<translation>Zoek</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2279" />
<location filename="../novelwriter/gui/doceditor.py" line="2286" />
<source>Replace</source>
<translation>Vervang</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
<location filename="../novelwriter/gui/doceditor.py" line="2302" />
<source>Case Sensitive</source>
<translation>Hoofdlettergevoelig</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
<location filename="../novelwriter/gui/doceditor.py" line="2308" />
<source>Whole Words Only</source>
<translation>Alleen hele woorden</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
<location filename="../novelwriter/gui/doceditor.py" line="2314" />
<source>RegEx Mode</source>
<translation>RegEx modus</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
<location filename="../novelwriter/gui/doceditor.py" line="2320" />
<source>Loop Search</source>
<translation>Zoekopdracht lus</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
<location filename="../novelwriter/gui/doceditor.py" line="2326" />
<source>Search Next File</source>
<translation>Doorzoek volgend bestand</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2327" />
<location filename="../novelwriter/gui/doceditor.py" line="2334" />
<source>Preserve Case</source>
<translation>Behoud hoofd/kleine letters</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2335" />
<location filename="../novelwriter/gui/doceditor.py" line="2342" />
<source>Close Search</source>
<translation>Zoekopdracht afsluiten</translation>
</message>
<message>
<location filename="../novelwriter/gui/doceditor.py" line="2351" />
<location filename="../novelwriter/gui/doceditor.py" line="2358" />
<source>Find in current document</source>
<translation>Zoeken in huidige document</translation>
</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>
<translation>Zoek en vervang in huidig document</translation>
</message>
@@ -2050,55 +2050,66 @@
<context>
<name>GuiNovelToolBar</name>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="207" />
<location filename="../novelwriter/gui/noveltree.py" line="216" />
<source>Outline of {0}</source>
<translation>Omlijning van {0}</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="215" />
<location filename="../novelwriter/gui/noveltree.py" line="224" />
<source>Novel Root</source>
<translation>Roman Hoofdmap</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="221" />
<location filename="../novelwriter/gui/noveltree.py" line="230" />
<source>Refresh</source>
<translation>Verversen</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="228" />
<location filename="../novelwriter/gui/noveltree.py" line="237" />
<source>Last Column</source>
<translation>Laatste Kolom</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="231" />
<location filename="../novelwriter/gui/noveltree.py" line="240" />
<source>Hidden</source>
<translation>Verborgen</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="232" />
<location filename="../novelwriter/gui/noveltree.py" line="241" />
<source>Point of View Character</source>
<translation>Perspectief Karakter</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="233" />
<location filename="../novelwriter/gui/noveltree.py" line="242" />
<source>Focus Character</source>
<translation>Focus Karakter</translation>
</message>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="234" />
<location filename="../novelwriter/gui/noveltree.py" line="243" />
<source>Novel Plot</source>
<translation>Roman Plot</translation>
</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>
<translation>Meer Opties</translation>
</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>
<name>GuiNovelTree</name>
<message>
<location filename="../novelwriter/gui/noveltree.py" line="778" />
<location filename="../novelwriter/gui/noveltree.py" line="815" />
<source>No meta data</source>
<translation>Geen metadata</translation>
</message>
@@ -3341,44 +3352,44 @@
<translation>Nieuwe map</translation>
</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>
<translation>Er is momenteel geen Prullenbak map in dit project.</translation>
</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>
<translation>De Prullenbak map is al leeg.</translation>
</message>
<message>
<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>
<translation>Prullenbak legen</translation>
</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>
<translation>{0} bestand(en) permanent verwijderen uit de prullenbak?</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation>Verwijderen</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation>Verplaats '{0}' naar Prullenbak?</translation>
</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>
<translation>Root mappen kunnen alleen verwijderd worden wanneer ze leeg zijn.</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation>'{0}' permanent verwijderen?</translation>
</message>
+9 -9
View File
@@ -3352,44 +3352,44 @@
<translation>Novo Diretório</translation>
</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>
<translation>Não exite um diretório de Lixeira neste projeto.</translation>
</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>
<translation>O diretório de Lixeira já está vazio.</translation>
</message>
<message>
<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>
<translation>Esvaziar a Lixeira</translation>
</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>
<translation>Permanentemente remover {0} arquivo(s) da Lixeira?</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="908" />
<location filename="../novelwriter/gui/projtree.py" line="852" />
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="853" />
<source>Delete</source>
<translation>Excluir</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="853" />
<location filename="../novelwriter/gui/projtree.py" line="854" />
<source>Move '{0}' to Trash?</source>
<translation>Mover '{0}' para a Lixeira?</translation>
</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>
<translation>Os diretórios-raiz só podem ser excluídos quando estiverem vazios.</translation>
</message>
<message>
<location filename="../novelwriter/gui/projtree.py" line="909" />
<location filename="../novelwriter/gui/projtree.py" line="910" />
<source>Permanently delete '{0}'?</source>
<translation>Excluir permanentemente '{0}?</translation>
</message>
+5 -3
View File
@@ -59,9 +59,9 @@ __license__ = "GPLv3"
__author__ = "Veronica Berglyd Olsen"
__maintainer__ = "Veronica Berglyd Olsen"
__email__ = "code@vkbo.net"
__version__ = "2.1-alpha0"
__hexversion__ = "0x020100a0"
__date__ = "2023-02-12"
__version__ = "2.0.6"
__hexversion__ = "0x020006f0"
__date__ = "2023-02-26"
__status__ = "Stable"
__domain__ = "novelwriter.io"
__url__ = "https://novelwriter.io"
@@ -246,6 +246,8 @@ def main(sysArgs=None):
nwApp.setApplicationName(CONFIG.appName)
nwApp.setApplicationVersion(__version__)
nwApp.setOrganizationDomain(__domain__)
nwApp.setOrganizationName(__domain__)
nwApp.setDesktopFileName(CONFIG.appName)
# Connect the exception handler before making the main GUI
sys.excepthook = exceptionHandler
+1 -1
View File
@@ -1359,7 +1359,7 @@ class GuiDocEditor(QTextEdit):
if self._docHandle is None or self._nwItem is None:
return
logger.debug("User selectee %d words", wCount)
logger.debug("User selected %d words", wCount)
self.docFooter.updateCounts(wCount=wCount, cCount=cCount)
self.wcTimerSel.stop()
+22 -1
View File
@@ -38,6 +38,7 @@ from PyQt5.QtWidgets import (
QMenu, QShortcut, QSizePolicy, QToolButton, QTreeWidget, QTreeWidgetItem,
QVBoxLayout, QWidget
)
from novelwriter.core.item import NWItem
from novelwriter.enum import nwDocMode, nwItemType, nwItemClass, nwItemLayout, nwAlert, nwWidget
from novelwriter.constants import nwHeaders, nwUnicode, trConst, nwLabels
@@ -108,6 +109,9 @@ class GuiProjectView(QWidget):
self.keyContext.setContext(Qt.WidgetShortcut)
self.keyContext.activated.connect(lambda: self.projTree.openContextOnSelected())
# Signals
self.selectedItemChanged.connect(self.projBar._treeSelectionChanged)
# Function Mappings
self.emptyTrash = self.projTree.emptyTrash
self.requestDeleteItem = self.projTree.requestDeleteItem
@@ -418,6 +422,23 @@ class GuiProjectToolBar(QWidget):
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
@@ -1204,7 +1225,7 @@ class GuiProjectTree(QTreeWidget):
# Edit Item Settings
# ==================
aLabel = ctxMenu.addAction(self.tr("Change Label"))
aLabel = ctxMenu.addAction(self.tr("Rename"))
aLabel.triggered.connect(lambda: self.renameTreeItem(tHandle))
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