Compare commits
250 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55714bbcad | ||
|
|
6f144c20cd | ||
|
|
f23bd3818f | ||
|
|
d3ea763d6b | ||
|
|
91222f631f | ||
|
|
aceb344856 | ||
|
|
f11ea8d07e | ||
|
|
a4e3bf848b | ||
|
|
e74c1057a4 | ||
|
|
6cc046c65c | ||
|
|
c97a070e98 | ||
|
|
b4c0bf3322 | ||
|
|
e998cb634e | ||
|
|
c8017a1f42 | ||
|
|
6d84942746 | ||
|
|
818f145b62 | ||
|
|
f92c22ce7e | ||
|
|
69b362b9d2 | ||
|
|
1fe7ca3db8 | ||
|
|
cc32674b0f | ||
|
|
cf16b57f66 | ||
|
|
411163f750 | ||
|
|
7f3da655c0 | ||
|
|
76e786d961 | ||
|
|
7e1f1a725c | ||
|
|
c63a0c2f58 | ||
|
|
04a7e092a9 | ||
|
|
309065bcbf | ||
|
|
20ae3febef | ||
|
|
e95d33031c | ||
|
|
3fd62d0b02 | ||
|
|
dc0ddcfa9f | ||
|
|
7a13b14c15 | ||
|
|
adf0550571 | ||
|
|
ba6259f08a | ||
|
|
d8bb2ad3ae | ||
|
|
afe4a29fd1 | ||
|
|
1203dd639b | ||
|
|
aadad6aa8c | ||
|
|
8ac0440bb3 | ||
|
|
d2fca3b980 | ||
|
|
d6b4019614 | ||
|
|
a6eb951361 | ||
|
|
dce5bdd31d | ||
|
|
0b999bd726 | ||
|
|
774437f7bb | ||
|
|
c0673b8128 | ||
|
|
0bc8a63ccf | ||
|
|
192f4507e3 | ||
|
|
2d22adcd2a | ||
|
|
4c4b92fdd4 | ||
|
|
2a727d1c39 | ||
|
|
35693f5433 | ||
|
|
bf459b4090 | ||
|
|
728f1ce1e3 | ||
|
|
7b8021de02 | ||
|
|
60593cde21 | ||
|
|
f9292d61da | ||
|
|
9388ce6a46 | ||
|
|
cb19475409 | ||
|
|
09b51badd4 | ||
|
|
fddd5fda47 | ||
|
|
5b0a6f05ed | ||
|
|
51f91a27e2 | ||
|
|
09018d1214 | ||
|
|
de12b22c97 | ||
|
|
d1ae7f5fe2 | ||
|
|
201d32f6ae | ||
|
|
6a441b1c6b | ||
|
|
0afa15f2db | ||
|
|
85eb44da02 | ||
|
|
4856c7a61b | ||
|
|
1b4cc933e7 | ||
|
|
d64acb038b | ||
|
|
b5def640ed | ||
|
|
7e35b4c675 | ||
|
|
e5e3066b3d | ||
|
|
e1af21bf88 | ||
|
|
8c9d08e46b | ||
|
|
e4acfb4831 | ||
|
|
a8101c2231 | ||
|
|
a3ce426613 | ||
|
|
161d02cd98 | ||
|
|
101400bea3 | ||
|
|
1ff9fea378 | ||
|
|
3f4538a60e | ||
|
|
142d7c4f3a | ||
|
|
2afe0ebbe9 | ||
|
|
bc71a62199 | ||
|
|
1e85ce4a84 | ||
|
|
39951a5099 | ||
|
|
9cbb6f3125 | ||
|
|
2dbd3e2534 | ||
|
|
f871a51e5b | ||
|
|
6ab3c68ebb | ||
|
|
7243ccd44c | ||
|
|
2a96fa1a2d | ||
|
|
c05620dddb | ||
|
|
917977ae13 | ||
|
|
2b8338f537 | ||
|
|
e75b5e012c | ||
|
|
78e194d8c1 | ||
|
|
c594e07c8c | ||
|
|
a3ed079828 | ||
|
|
976ce16ac2 | ||
|
|
5faeb12a74 | ||
|
|
acc463eb76 | ||
|
|
3b7459ffbc | ||
|
|
cfb19a697a | ||
|
|
ceec43db67 | ||
|
|
229fa39436 | ||
|
|
2496eb22cb | ||
|
|
d0a45bceca | ||
|
|
7180fae453 | ||
|
|
e1a1b5980e | ||
|
|
53d410a6ee | ||
|
|
a56b38694c | ||
|
|
600b60b441 | ||
|
|
aa7208b602 | ||
|
|
0092b3ece6 | ||
|
|
d01c1e867d | ||
|
|
dd3c8dfac8 | ||
|
|
7c9c5a9a76 | ||
|
|
8f9a55c5ca | ||
|
|
ea0b61aa6d | ||
|
|
b94e7159b8 | ||
|
|
2eabca8267 | ||
|
|
afbe434b59 | ||
|
|
2a50799873 | ||
|
|
77727ad500 | ||
|
|
e89f1fe5a8 | ||
|
|
503e7eceb5 | ||
|
|
c15eba8f62 | ||
|
|
e2f83d5106 | ||
|
|
937b5cca12 | ||
|
|
1d438d5d76 | ||
|
|
22a34be21a | ||
|
|
17a492444e | ||
|
|
9a714a903d | ||
|
|
69a99fc97f | ||
|
|
8beb74689c | ||
|
|
6be7da0305 | ||
|
|
8a08fe213c | ||
|
|
205b17aea0 | ||
|
|
864172ea50 | ||
|
|
e01e14075c | ||
|
|
e9596e1bbc | ||
|
|
db9305c230 | ||
|
|
4572d101cf | ||
|
|
41506911c1 | ||
|
|
b722224863 | ||
|
|
b585b8ecd1 | ||
|
|
52e8ae9cb6 | ||
|
|
6d6d0c2d12 | ||
|
|
383640cb7e | ||
|
|
e5ef27dfbf | ||
|
|
96741fc08b | ||
|
|
dc41f495be | ||
|
|
b278d64d0c | ||
|
|
b5e32844f5 | ||
|
|
4179d2e515 | ||
|
|
815ba9d553 | ||
|
|
0d294f49f9 | ||
|
|
a195cfc792 | ||
|
|
d3c9168ebf | ||
|
|
4d153b8d99 | ||
|
|
bf8d224064 | ||
|
|
b7ad2c969a | ||
|
|
d78643160c | ||
|
|
221b38c766 | ||
|
|
e8bd9b21b5 | ||
|
|
c2f0d04a35 | ||
|
|
54ebcd91cb | ||
|
|
07411327b6 | ||
|
|
094ad1a17b | ||
|
|
c362848b86 | ||
|
|
47a8dfbd93 | ||
|
|
73b8443d7b | ||
|
|
48a7929254 | ||
|
|
2c1abf1519 | ||
|
|
e27e066ccc | ||
|
|
621e933f63 | ||
|
|
885974a84e | ||
|
|
b1d1af2153 | ||
|
|
cb94be5b3c | ||
|
|
5a202e96fd | ||
|
|
b80edee225 | ||
|
|
48e653a546 | ||
|
|
a2d8aefb21 | ||
|
|
ae893be79b | ||
|
|
791080107f | ||
|
|
7d22ed1249 | ||
|
|
8150edbc43 | ||
|
|
5acbfeffa5 | ||
|
|
3b763e3460 | ||
|
|
6dd5f4295d | ||
|
|
ac7b0bc9a2 | ||
|
|
1733938eb4 | ||
|
|
e5c9ed4b80 | ||
|
|
f45170850c | ||
|
|
bdce0e12c7 | ||
|
|
57f9a0a844 | ||
|
|
988d969de7 | ||
|
|
17960d286f | ||
|
|
26ac68e98e | ||
|
|
0729dd798b | ||
|
|
c65dee1df9 | ||
|
|
92888338f4 | ||
|
|
44192c88f5 | ||
|
|
8d24243d4f | ||
|
|
7c4d4dec5c | ||
|
|
9823677983 | ||
|
|
ec6a5712e5 | ||
|
|
70033cb0f3 | ||
|
|
da102d3d5a | ||
|
|
5568b43b22 | ||
|
|
5da30e6608 | ||
|
|
0fb0af5b32 | ||
|
|
f5fcc57a06 | ||
|
|
4a1a3013f4 | ||
|
|
cf57a3ead0 | ||
|
|
39b2ff4a72 | ||
|
|
eced026aeb | ||
|
|
730d09a76c | ||
|
|
b521b39498 | ||
|
|
492bc044fc | ||
|
|
84ff2f8371 | ||
|
|
54f26ea06e | ||
|
|
e10f3a19d3 | ||
|
|
21a5dbbb52 | ||
|
|
f67d2c5a4c | ||
|
|
6cf83bb381 | ||
|
|
f4decae77f | ||
|
|
e47f0c5166 | ||
|
|
778b65b48c | ||
|
|
d1dbb0b378 | ||
|
|
adfd003532 | ||
|
|
f17302439e | ||
|
|
63d2f5c57d | ||
|
|
478db63b30 | ||
|
|
127588699e | ||
|
|
29c10542b1 | ||
|
|
5c9fd471a7 | ||
|
|
dd15c93f51 | ||
|
|
4003ececb2 | ||
|
|
ff3cae9db4 | ||
|
|
af44646a77 | ||
|
|
ba42285172 | ||
|
|
dff2d5996b | ||
|
|
08b17daec9 |
5
.flake8
5
.flake8
@@ -1,5 +0,0 @@
|
||||
[flake8]
|
||||
ignore = E133,E221,E226,E228,E241,W503,ANN101,ANN102,ANN401
|
||||
per-file-ignores=tests/*:ANN
|
||||
max-line-length = 99
|
||||
exclude = docs/*
|
||||
58
.github/workflows/build.yml
vendored
58
.github/workflows/build.yml
vendored
@@ -9,7 +9,7 @@ jobs:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
python-version: "3.12"
|
||||
architecture: x64
|
||||
|
||||
- name: Install Packages (apt)
|
||||
@@ -35,15 +35,14 @@ jobs:
|
||||
novelwriter/assets/manual.pdf
|
||||
novelwriter/assets/i18n/*.qm
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
retention-days: 14
|
||||
|
||||
buildLinux:
|
||||
needs: buildAssets
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.11"]
|
||||
linux-tag: ["manylinux_2_24_x86_64", "manylinux_2_28_x86_64"]
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
LINUX_TAG: "manylinux_2_28_x86_64"
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
@@ -64,19 +63,24 @@ jobs:
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build AppImage
|
||||
run: python pkgutils.py build-appimage --linux-tag ${{ matrix.linux-tag }} --python-version ${{ matrix.python-version }}
|
||||
run: python pkgutils.py build-appimage --linux-tag $LINUX_TAG --python-version $PYTHON_VERSION
|
||||
|
||||
- name: Upload Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: AppImage-${{ matrix.python-version }}-${{ matrix.linux-tag }}
|
||||
name: Linux-AppImage
|
||||
path: dist_appimage
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
retention-days: 14
|
||||
|
||||
buildMac:
|
||||
buildMac-AMD64:
|
||||
needs: buildAssets
|
||||
# Stay on macos-12 due to https://github.com/create-dmg/create-dmg/issues/143
|
||||
runs-on: macos-12
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
PACKAGE_ARCH: x86_64
|
||||
MINICONDA_ARCH: x86_64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -88,12 +92,40 @@ jobs:
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build App Bundle
|
||||
run: ./setup/macos/build.sh
|
||||
run: ./setup/macos/build.sh $PYTHON_VERSION $PACKAGE_ARCH $MINICONDA_ARCH
|
||||
|
||||
- name: Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MacOS-DMG
|
||||
name: MacOS-AMD64-DMG
|
||||
path: dist_macos
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
retention-days: 14
|
||||
|
||||
buildMac-M1:
|
||||
needs: buildAssets
|
||||
runs-on: macos-14
|
||||
env:
|
||||
PYTHON_VERSION: "3.12"
|
||||
PACKAGE_ARCH: aarch64
|
||||
MINICONDA_ARCH: arm64
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: nw-assets
|
||||
path: novelwriter/assets
|
||||
|
||||
- name: Build App Bundle
|
||||
run: ./setup/macos/build.sh $PYTHON_VERSION $PACKAGE_ARCH $MINICONDA_ARCH
|
||||
|
||||
- name: Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MacOS-M1-DMG
|
||||
path: dist_macos
|
||||
if-no-files-found: error
|
||||
retention-days: 14
|
||||
|
||||
4
.github/workflows/test_linux.yml
vendored
4
.github/workflows/test_linux.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
testLinux:
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12"]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Python Setup
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: |
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
pytest -v --cov=novelwriter --timeout=60
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
4
.github/workflows/test_mac.yml
vendored
4
.github/workflows/test_mac.yml
vendored
@@ -12,7 +12,7 @@ on:
|
||||
|
||||
jobs:
|
||||
testMac:
|
||||
runs-on: macos-latest
|
||||
runs-on: macos-13
|
||||
steps:
|
||||
- name: Python Setup
|
||||
uses: actions/setup-python@v5
|
||||
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Run Tests
|
||||
run: |
|
||||
export QT_QPA_PLATFORM=offscreen
|
||||
pytest -v --cov=novelwriter --timeout=60
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
2
.github/workflows/test_win.yml
vendored
2
.github/workflows/test_win.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
||||
pip install -U -r requirements.txt -r tests/requirements.txt
|
||||
- name: Run Tests
|
||||
run: |
|
||||
pytest -v --cov=novelwriter --timeout=60
|
||||
python -m pytest -v --cov=novelwriter --timeout=60
|
||||
- name: Upload to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
env:
|
||||
|
||||
178
CHANGELOG.md
178
CHANGELOG.md
@@ -1,5 +1,183 @@
|
||||
# novelWriter Changelog
|
||||
|
||||
## Version 2.5 Beta 1 [2024-05-26]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a beta release of the next release version, and is intended for testing purposes. Please be
|
||||
careful when using this version on live writing projects, and make sure you take frequent backups.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**General Changes**
|
||||
|
||||
* novelWriter now requires Python 3.9 and Qt 5.15 as a minimum. That means Ubuntu 20.04 and older
|
||||
are no longer supported for the Debian packages. Users on Ubuntu 20.04 and equivalent Linux
|
||||
distros must use the AppImage. PRs #1826 and #1833.
|
||||
|
||||
**Major Features**
|
||||
|
||||
* Status and Importance icons can now be assigned a shape in addition to a colour. Issue #1786.
|
||||
PRs #1810 and #1819.
|
||||
* Footnotes have been added. They use a modified comment format for specifying the footnote text,
|
||||
and a shortcode for inserting the footnote into the text. They are linked via a key. If the
|
||||
footnote is inserted via the **Insert** menu, a unique key is generated. Issue #342. PR #1832.
|
||||
* Comments in general now support formatting, so format tags work just like in regular text. This
|
||||
was needed for footnotes, but has been expanded to include all comments. PR #1832.
|
||||
* Two new themes have been added. Dracula is available as a set for both the GUI and the editor.
|
||||
Snazzy Light is available for syntax only, but works well with the default light GUI theme.
|
||||
PR #1840.
|
||||
* Character dialogue highlighting has been completely redesigned. The highlighting rule now
|
||||
specifically relates to dialogue, and not just quoted text in general. To that effect, more rules
|
||||
for detecting what is and isn't dialogue has been added. This is designed to support difference
|
||||
between dialogue conventions in different languages. Issues #1770 and #1771. PR #1864.
|
||||
* The font settings in Preferences now considers the full range of font options, in particular font
|
||||
style and weight. The changes include the font size in these settings, so the additional setting
|
||||
for font size has been removed. Use the font dialog to pick size as well. Due to this removal,
|
||||
the font size has been reset to default and must be set again by the user. Issue #1733. PR #1881.
|
||||
* The document viewer and the manuscript preview now uses a completely new class to generate the
|
||||
formatted text. The old method used an outdated HTML format as the go-between, which restricted
|
||||
what formatting could be applied. The main noticeable change to users at the moment should be the
|
||||
size of headings, that now match the size in the editor. Issue #1882. PR #1892.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* The default dark theme has been redesigned to match the GUI theme a little better, and is now
|
||||
also consistent with the default light themes. PRs #1836 and #1840.
|
||||
* Special comments now have a different text colour than plain comments. PR #1836.
|
||||
* The various Tomorrow themes are now a little more consistent in what colours are used for which
|
||||
components. More variation has also been added. PR #1840.
|
||||
* The Tango theme has been updated. PR #1840.
|
||||
* The last cursor position is now always saved when a document is closed in the editor, even if the
|
||||
content has not been changed. PR #1849.
|
||||
* The settings for first line indent have now been extended to allow setting how deep the indents
|
||||
are and whether or not to indent the first paragraph after a heading or break. The settings have
|
||||
also moved from being Open Document specific to the general formatting tab for manuscripts.
|
||||
PR #1857.
|
||||
* Preserving in-paragraph line breaks is now a general Manuscript setting that applies to all
|
||||
output formats. PR #1891.
|
||||
* The Manuscript builds now also uses the full font settings of the selected output font, not just
|
||||
the font family and size option. Since the size option has been merged into the general font
|
||||
choice, the separate font size setting has been dropped and users must set it again. PR #1891.
|
||||
* It is now possible to disable the usage of the font selection dialog from your operating system.
|
||||
At least on Linux Gnome desktops, the system's font dialog lacks a lot of the selection options
|
||||
available in the font dialog provided with Qt. PR #1891.
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed an issue where Manuscript dialogs would be left open if the project was closed. PR #1844.
|
||||
* First line indents are no longer reset after a comment. Issue #1852. PR #1857.
|
||||
|
||||
**Packaging**
|
||||
|
||||
* Minimal zip file release packages can no longer be built from the package utility script. The zip
|
||||
file needed for building the Windows installer is still available. PR #1826.
|
||||
* Added build packages for AARCH64 on MacOS. It seems some dependencies still prevents it from
|
||||
being installed cleanly without requiring some virtualisation feature, but it works. PR #1829.
|
||||
* AppImages are now released with Python 3.12. PR #1829.
|
||||
|
||||
**Other Changes**
|
||||
|
||||
* A new GUI theme setting for error text has been added. It is used when error messages need to be
|
||||
displayed on the GUI. PR #1880.
|
||||
|
||||
**Code Improvements**
|
||||
|
||||
* The behaviour of dialogs across various platforms has been unified and improved a little to
|
||||
ensure more consistent behaviour. It is mostly related to modality and z-order. There are still
|
||||
limitations due to platform restrictions, like non-modal dialogs being stuck on top on Linux
|
||||
Wayland. PR #1844.
|
||||
* Some GUI components have been improved and refactored to rely more on signals and slots rather
|
||||
than reaching into each other's classes and calling methods. This is a little more robust.
|
||||
PR #1849.
|
||||
* The text tokenizer used to parse the formatting codes in novelWriter has been refactored and
|
||||
improved. In particular, multi-line paragraphs are now processed during the second pass of
|
||||
tokenization rather than when the final format is applied. This allows a much more compact format
|
||||
of the token data, and avoid potential inconsistencies between the various output formats.
|
||||
PR #1885.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4.3 [2024-05-20]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes issues with the document font in the editor, viewer and
|
||||
manuscript preview on some Linux distros, and also fixes a potential crash on Windows when using
|
||||
the spell check dictionary install tool.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fix a crash in the dictionaries install tool on Windows if the config folder reported by the
|
||||
third party Enchant spell checker tool didn't already exist prior to adding new dictionaries.
|
||||
The folder is now created when the tool is opened if it doesn't exist. Issue #1874. PR #1876.
|
||||
* Fix issues setting a different text font for the editor and viewer, and related issues with the
|
||||
preview in the Manuscript Build tool, on certain platforms. Changing the font and setting
|
||||
non-standard font sizes produced unexpected results when reloading. The issue seems to be related
|
||||
to Qt 5.15.3, but that is not fully confirmed. However, the only place so far where the issue is
|
||||
observed is on Mint 21.3. Issues #1862 and #1875. PR #1877.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4.2 [2024-05-18]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes two minor font issues and updates the Dutch and Chinese
|
||||
translations.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Change the preview widget in the Manuscript Build tool to use the document font only for the
|
||||
document itself, not the yellow heading stating the age of the previewed text. PR #1863.
|
||||
* Fixes the syntax highlighter so that it is re-initialised when the document editor is
|
||||
re-initialised, so that changes to document font size regenerates the heading font sizes as well.
|
||||
Issue #1865. PR #1866.
|
||||
|
||||
**Internationalisation**
|
||||
|
||||
* Dutch translation updated by Martijn van der Kleijn (@mvdkleijn). PR #1872.
|
||||
* Chinese translation updated by @longqzh. PR #1872.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4.1 [2024-05-06]
|
||||
|
||||
### Release Notes
|
||||
|
||||
This is a patch release that fixes a number of minor issues with the Manuscript Build tool. The
|
||||
only critical fix is related to a potential crash when deleting a build entry when its settings
|
||||
dialog is still open.
|
||||
|
||||
### Detailed Changelog
|
||||
|
||||
**Bugfixes**
|
||||
|
||||
* Fixed an issue that could crash novelWriter if a build settings entry was deleted from the
|
||||
Manuscript tool while its settings window was open. PR #1845.
|
||||
|
||||
**Improvements**
|
||||
|
||||
* Changed the font used for the document editor and viewer header and footer from the one used for
|
||||
the document text to the one used for the user interface. Issue #1842. PR #1843.
|
||||
* Added a save document step in the editor before running a manuscript build or a preview job. This
|
||||
ensures that the text in the editor is included in the manuscript. Issue #1835. PR #1846.
|
||||
* Restore preview panel scroll bar position after updating the preview on the Manuscript tool.
|
||||
Issue #1837. PR #1846.
|
||||
* Close all non-modal dialogs when a project is closed. PR #1848.
|
||||
|
||||
**Code Improvements**
|
||||
|
||||
* Fixed an issue with the Build Settings dialog that blocks the garbage collector from deleting the
|
||||
dialog after it's been closed. PR #1843.
|
||||
* Remove some deprecated translation entries from the translation files. PR #1850.
|
||||
|
||||
----
|
||||
|
||||
## Version 2.4 [2024-04-20]
|
||||
|
||||
### Release Notes
|
||||
|
||||
@@ -55,6 +55,9 @@ Some of the assets bundled with novelWriter were adapted from the following sour
|
||||
* [Tomorrow](https://github.com/chriskempson/base16) syntax themes by Chris Kempson (MIT License)
|
||||
* [Owl](https://github.com/sdras/night-owl-vscode-theme) syntax themes by Sarah Drasner (MIT License)
|
||||
* [Solarized](https://github.com/altercation/solarized) themes by Ethan Schoonover (MIT License)
|
||||
* [Cyberpunk Night](https://github.com/alemvigh) theme by Anders Lemvigh (CC BY-SA 4.0)
|
||||
* [Dracula](https://draculatheme.com) theme by Zeno Rocha (MIT License)
|
||||
* [Snazzy Light](https://github.com/loilo/vscode-snazzy-light) theme by Florian Reuschel (MIT License)
|
||||
|
||||
## Fonts
|
||||
|
||||
|
||||
@@ -31,9 +31,9 @@ documentation.
|
||||
|
||||
## Implementation
|
||||
|
||||
novelWriter is written with Python 3 (3.8+) using Qt5 and PyQt5 (5.10+), and is released on Linux,
|
||||
Windows and macOS. It can in principle run on any Operating System that also supports Qt, PyQt and
|
||||
Python.
|
||||
novelWriter is written with Python 3 (3.9+) using Qt5 and PyQt5 (5.15 only), and is released on
|
||||
Linux, Windows and macOS. It can in principle run on any Operating System that also supports Qt,
|
||||
PyQt and Python.
|
||||
|
||||
## Project Contributions
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
@@ -16,13 +16,21 @@ This is a list of hopefully helpful little tips on how to get the most out of no
|
||||
Managing the Project
|
||||
====================
|
||||
|
||||
.. dropdown:: Create a Project from a Template
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
On the Welcome dialog's **Create New Project** form, you can select to "Prefill Project" from
|
||||
the content of a different project. This feature is most useful if you copy a project you have
|
||||
dedicated to be a template project. If you have a structure and settings you want to use for
|
||||
every new project, this is the best solution.
|
||||
|
||||
.. dropdown:: Merge Multiple Documents Into One
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
If you need to merge a selection 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`.
|
||||
achieve this by first making a new folder for just that purpose, and drag all the documents you
|
||||
want merged into this folder. Then you can right click the folder, select :guilabel:`Transform`
|
||||
and :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 rearrange them here of you wish. See :ref:`a_ui_tree_split_merge` for more details.
|
||||
@@ -58,8 +66,6 @@ Organising Your Text
|
||||
such text. Separating chapter and scene files also allows you to make scene files child
|
||||
documents of the chapter.
|
||||
|
||||
.. versionadded:: 2.0
|
||||
|
||||
.. dropdown:: Distinguishing Soft and Hard Scene Breaks
|
||||
:animate: fade-in-slide-down
|
||||
|
||||
|
||||
@@ -131,9 +131,11 @@ A GUI theme ``.conf`` file consists of the following settings:
|
||||
linkvisited = 100, 100, 100
|
||||
|
||||
[GUI]
|
||||
statusnone = 100, 100, 100
|
||||
statussaved = 100, 100, 100
|
||||
statusunsaved = 100, 100, 100
|
||||
helptext = 0, 0, 0
|
||||
errortext = 255, 0, 0
|
||||
statusnone = 120, 120, 120
|
||||
statussaved = 2, 133, 37
|
||||
statusunsaved = 200, 15, 39
|
||||
|
||||
In the Main section you must at least define the ``name`` and ``icontheme`` settings. The
|
||||
``icontheme`` settings should correspond to one of the internal icon themes, either
|
||||
@@ -143,7 +145,11 @@ setting must match the icon theme's folder name.
|
||||
The Palette values correspond to the Qt enum values for ``QPalette::ColorRole``, see the
|
||||
`Qt documentation <https://doc.qt.io/qt-5.15/qpalette.html#ColorRole-enum>`_ for more details. The
|
||||
colour values are RGB numbers on the format ``r, g, b`` where each is an integer from ``0`` to
|
||||
``255``. Omitted values are not loaded and will use default values.
|
||||
``255``. Omitted values are not loaded and will use default values. If the ``helptext`` colour is
|
||||
not defined, it is computed as a colour between the ``window`` and ``windowtext`` colour.
|
||||
|
||||
.. versionadded:: 2.5
|
||||
The ``errortext`` theme colour entry was added.
|
||||
|
||||
|
||||
Custom Syntax Theme
|
||||
@@ -168,12 +174,13 @@ A syntax theme ``.conf`` file consists of the following settings:
|
||||
headertext = 0, 0, 0
|
||||
headertag = 0, 0, 0
|
||||
emphasis = 0, 0, 0
|
||||
straightquotes = 0, 0, 0
|
||||
doublequotes = 0, 0, 0
|
||||
singlequotes = 0, 0, 0
|
||||
dialog = 0, 0, 0
|
||||
altdialog = 0, 0, 0
|
||||
note = 0, 0, 0
|
||||
hidden = 0, 0, 0
|
||||
shortcode = 0, 0, 0
|
||||
keyword = 0, 0, 0
|
||||
tag = 0, 0, 0
|
||||
value = 0, 0, 0
|
||||
optional = 0, 0, 0
|
||||
spellcheckline = 0, 0, 0
|
||||
@@ -197,3 +204,7 @@ Omitted syntax colours default to black, except ``background`` which defaults to
|
||||
|
||||
.. versionadded:: 2.4
|
||||
The ``texthighlight`` syntax colour entry was added.
|
||||
|
||||
.. versionadded:: 2.5
|
||||
The ``dialog``, ``altdialog``, ``note`` and ``tag`` syntax colour entries were added.
|
||||
``straightquotes``, ``doublequotes`` and ``singlequotes`` were removed.
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
.. _a_proj:
|
||||
|
||||
**************
|
||||
Novel Projects
|
||||
**************
|
||||
*****************
|
||||
Managing Projects
|
||||
*****************
|
||||
|
||||
Your text in novelWriter is organised into projects. Each project is meant to contain one novel
|
||||
and associated notes. If you have multiple novels in a series, with the same characters and shared
|
||||
notes, it is also possible to keep all of them in the same project.
|
||||
|
||||
.. _a_proj_new:
|
||||
|
||||
Creating Project
|
||||
================
|
||||
|
||||
New projects can be created from the **Project** menu by selecting **Create or Open Project**. This
|
||||
will open the **Welcome** dialog, where you can select the :guilabel:`New` button that will assist
|
||||
@@ -27,10 +36,19 @@ and page counts, is available through the **Novel Details** dialog. Statistics a
|
||||
is also available in the **Manuscript Build** tool.
|
||||
|
||||
|
||||
Template Projects
|
||||
-----------------
|
||||
|
||||
From the Welcome dialog you can also create a new from another existing project. If you have a
|
||||
specific structure you want to use for all your new projects, you can create a dedicated project to
|
||||
be used as a template, and select to copy an existing project from the :guilabel:"Prefill Project"
|
||||
option from the **New Project** form.
|
||||
|
||||
|
||||
.. _a_proj_roots:
|
||||
|
||||
Project Roots
|
||||
=============
|
||||
Project Structure
|
||||
=================
|
||||
|
||||
Projects are structured into a set of top level folders called "Root Folders". They are visible in
|
||||
the project tree at the left side of the main window.
|
||||
|
||||
@@ -39,11 +39,9 @@ The following Python packages are needed to run all features of novelWriter:
|
||||
* ``PyQt5`` – needed for connecting with the Qt5 libraries.
|
||||
* ``PyEnchant`` – needed for spell checking (optional).
|
||||
|
||||
PyQt/Qt should be at least 5.10, but ideally 5.13 or higher for all features to work. For instance,
|
||||
searching using regular expressions with full Unicode support requires 5.13.
|
||||
|
||||
If you want spell checking, you must install the ``PyEnchant`` package. The spell check library
|
||||
must be at least 3.0 to work with Windows. On Linux, 2.0 also works fine.
|
||||
PyQt/Qt must be at least 5.15.0. If you want spell checking, you must install the ``PyEnchant``
|
||||
package. The spell check library must be at least 3.0 to work with Windows. On Linux, 2.0 also
|
||||
works fine.
|
||||
|
||||
If you install from PyPi, these dependencies should be installed automatically. If you install from
|
||||
source, dependencies can still be installed from PyPi with:
|
||||
@@ -55,7 +53,7 @@ source, dependencies can still be installed from PyPi with:
|
||||
.. note::
|
||||
On Linux distros, the Qt library is usually split up into multiple packages. In some cases,
|
||||
secondary dependencies may not be installed automatically. For novelWriter, the library files
|
||||
for renderring the SVG icons may be left out and needs to be installed manually. This is the
|
||||
for rendering the SVG icons may be left out and needs to be installed manually. This is the
|
||||
case on for instance Arch Linux.
|
||||
|
||||
|
||||
|
||||
255
i18n/nw_base.ts
255
i18n/nw_base.ts
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation type="unfinished" />
|
||||
</message>
|
||||
|
||||
255
i18n/nw_de_DE.ts
255
i18n/nw_de_DE.ts
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>Zeile: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>Wörter: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>Wörter: {0} markiert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>Status</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>Werkzeugleiste ein/aus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation>Gliederung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>Suche</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>Ablenkungsfrei ein/aus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>Schließen</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation>Suchen nach</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation>Ersetzen durch</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>Suchen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>Groß-/Kleinschreibung beachten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>Nur ganze Wörter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>RegEx-Modus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>Suche am Anfang fortsetzen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>Nächstes Dokument durchsuchen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>Groß-/Kleinschreibung beibehalten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>Suche schließen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>Im geöffneten Dokument suchen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>Im geöffneten Dokument suchen und ersetzen</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>Dokument geöffnet: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>Dieses Dokument wurde außerhalb von novelWriter geändert, während es hier geöffnet war. Möchten Sie die externen Änderungen überschreiben?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>Dokument konnte nicht gespeichert werden.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>Dokument gespeichert: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>Die Rechtschreibprüfung erfordert das Paket PyEnchant. Es scheint nicht installiert zu sein.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>Rechtschreibprüfung abgeschlossen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>Details</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>Erstellt: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>Aktualisiert: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>Dateispeicherort: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>Als Dokumentname verwenden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>Schlagwort öffnen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>Notiz für Schlagwort erstellen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>Ausschneiden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>Kopieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>Einfügen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>Alles markieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>Wort markieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>Absatz markieren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>Korrekturvorschläge</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>Keine Vorschläge</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>Zum Wörterbuch hinzufügen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>Bitte markieren Sie den Text, in dem die Anführungszeichen ersetzt werden sollen.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>Möchten Sie für das Schlagwort „{0}“ eine neue Projektnotiz erstellen?</translation>
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>Fett mit Markdown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>Kursiv mit Markdown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>Durchgestrichen mit Markdown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>Fett mit Shortcode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>Kursiv mit Shortcode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>Durchgestrichen mit Shortcode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>Unterstrichen mit Shortcode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation>Hervorheben mit Shortcode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>Hochgestellt mit Shortcode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>Tiefgestellt mit Shortcode</translation>
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>Manuskript erstellen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>Ausgabeformat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>Inhaltsverzeichnis</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>Pfad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>Dateiname</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>Dateiname auf Standard zurücksetzen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>Ordner öffnen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>&Erstellen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>Verzeichnis wählen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>Das Ausgabeverzeichnis existiert nicht.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>Die Datei ist bereits vorhanden. Möchten Sie sie überschreiben?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>Gliederung für</translation>
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>Standard wiederherstellen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>Zurück</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< &Zurück</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>Fortsetzen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&Weiter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>&Weiter ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>Commit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>Fertig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>&Fertig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>&Abbrechen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>Hilfe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&Hilfe</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>novelWriter-Projektdatei oder Zip-Datei</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>novelWriter-Projektdatei</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>Projekt öffnen</translation>
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>Einstellung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>Wert</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>Name</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>Auswahl</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>Titel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation>Ausgeblendet</translation>
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>Information</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>Warnung</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>Fehler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>Frage</translation>
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>Zum Generieren den "Vorschau"-Button anklicken ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>In Bearbeitung ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>Fertig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>Unbekannt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>Erstellt</translation>
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation>Wörter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation>Zeichen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation>Wörter in Überschriften</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation>Wörter im Text</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation>Überschriften</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation>Absätze</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation>Zeichen in Überschriften</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation>Zeichen im Text</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation>Zeichen ohne Leerzeichen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation>Zeichen in Überschriften ohne Leerzeichen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation>Zeichen im Text ohne Leerzeichen</translation>
|
||||
</message>
|
||||
|
||||
255
i18n/nw_en_US.ts
255
i18n/nw_en_US.ts
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>Line: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>Words: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>Words: {0} selected</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>Status</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>Toggle Tool Bar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation>Outline</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>Search</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>Toggle Focus Mode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>Close</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation>Search for</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation>Replace with</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>Search</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>Case Sensitive</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>Whole Words Only</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>RegEx Mode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>Loop Search</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>Search Next File</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>Preserve Case</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>Close Search</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>Find in current document</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>Find and replace in current document</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>Opened Document: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>Could not save document.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>Saved Document: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>Spell checking requires the package PyEnchant. It does not appear to be installed.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>Spell check complete</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>Document Details</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>Created: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>Updated: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>File Location: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>Set as Document Name</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>Follow Tag</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>Create Note for Tag</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>Cut</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>Copy</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>Paste</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>Select All</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>Select Word</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>Select Paragraph</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>Spelling Suggestion(s)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>No Suggestions</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>Add Word to Dictionary</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>Please select some text before calling replace quotes.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>Do you want to create a new project note for the tag '{0}'?</translation>
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>Markdown Bold</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>Markdown Italic</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>Markdown Strikethrough</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>Shortcode Bold</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>Shortcode Italic</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>Shortcode Strikethrough</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>Shortcode Underline</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation>Shortcode Highlight</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>Shortcode Superscript</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>Shortcode Subscript</translation>
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>Build Manuscript</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>Output Format</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>Table of Contents</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>Path</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>File Name</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>Reset file name to default</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>Open Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>&Build</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>Select Folder</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>Output folder does not exist.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>The file already exists. Do you want to overwrite it?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>Outline of</translation>
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>Restore Defaults</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>Go Back</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< &Back</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>Continue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&Next</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>&Next ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>Commit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>Done</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>&Finish</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>Cancel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>Help</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&Help</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>novelWriter Project File or Zip File</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>novelWriter Project File</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>Open Project</translation>
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>Setting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>Value</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>Name</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>Selection</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>Title</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation>Hidden</translation>
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>Information</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>Warning</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>Error</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>Question</translation>
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>Press the "Preview" button to generate ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>Processing ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>Done</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>Unknown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>Built</translation>
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation>Words</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation>Characters</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation>Words in Headings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation>Words in Text</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation>Headings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation>Paragraphs</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation>Characters in Headings</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation>Characters in Text</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation>Characters, No Spaces</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation>Characters in Headings, No Spaces</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation>Characters in Text, No Spaces</translation>
|
||||
</message>
|
||||
|
||||
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>Línea: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>Palabras: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>Palabras: {0} seleccionadas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>Estado</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>Alternar Barra de Herramientas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation>Estructura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>Buscar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>Alternar el Modo Enfocado</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>Cerrar</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation>Buscar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation>Reemplazar con</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>Buscar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>Sensibilidad a Mayúsculas y Minúsculas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>Sólo Palabras Enteras</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>Modo ExReg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>Reiniciar la Búsqueda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>Buscar en el Siguiente Archivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>Conservar Mayúsculas y Minúsculas</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>Cerrar la Búsqueda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>Buscar en el documento actual</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>Buscar y reemplazar en el documento actual</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>Se Abrió el Documento: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>Este documento ha cambiado por fuera de novelWriter estando abierto. ¿Sobreescribir en el disco?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>No se puedo guardar el documento.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>Documento Guardado: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>Para la corrección ortográfica se requiere del paquete PyEnchant. Parece que no se encuentra instalado.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>Se completó la comprobación ortográfica</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>Detalles del Documento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>Creación: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>Actualizado en: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>Ubicación del Archivo: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>Elegir como Nombre del Documento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>Continuar a Etiqueta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>Crear Nota para la Etiqueta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>Cortar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>Copiar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>Pegar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>Seleccionar Todo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>Seleccionar Palabra</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>Seleccionar Párrafo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>Sugerencia(s) de Ortografía</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>No Hay Sugerencias</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>Añadir Palabra al Diccionario</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>Por favor seleccione algo del texto antes de intentar reemplazar las comillas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>¿Desea crear una nueva nota del proyecto para la etiqueta '{0}'?</translation>
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>Negrita (de Markdown)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>Cursiva (de Markdown)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>Tachado (de Markdown)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>Negrita (en código)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>Cursiva (en código)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>Tachado (en código)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>Subrayado (en código)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation>Resaltado (en código)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>Superíndice (en código)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>Subíndice (en código)</translation>
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>Compilar el Manuscrito</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>Grabar al Siguiente Formato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>Tabla de Contenidos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>Ruta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>Nombre del Archivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>Restablecer al Nombre de Archivo Por Defecto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>Abrir la Carpeta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>C&ompilar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>Seleccionar una Carpeta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>La carpeta destino no existe en la ruta definida.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>El archivo ya existe. ¿Desea sobrescribirlo?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>Estructura de</translation>
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>Restaurar valores predeterminados</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>Volver</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< &Volver</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>Continuar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&Siguiente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>Seguir ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>Confirmar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>Listo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>&Finalizar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>Cancelar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>Ayuda</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&Ayuda</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>Archivo de proyecto de novelWriter o archivo Zip</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>Archivo de Proyecto de novelWriter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>Abrir un Proyecto</translation>
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>Opciones</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>Valores Definidos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>Nombre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>Selecciones</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>Título</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation>Oculto</translation>
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>Información</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>Advertencia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>Error</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>Pregunta</translation>
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>Pulse el botón "Vista Previa" para así generarla...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>Procesando...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>Hecho</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>Desconocido</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>Compilado</translation>
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation>Palabras</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation>Caracteres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation>Palabras en Titulos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation>Palabras en el Texto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation>Títulos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation>Párrafos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation>Caracteres en los Títulos</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation>Caracteres en el Texto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation>Caracteres, Sin Espacios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation>Caracteres en los Títulos, Sin Espacios</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation>Caracteres en el Texto, Sin Espacios</translation>
|
||||
</message>
|
||||
|
||||
255
i18n/nw_fr_FR.ts
255
i18n/nw_fr_FR.ts
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>Ligne : {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>Mots : {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>Mots sélectionnés : {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>État</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>Afficher/Masquer la barre d'outils</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation>Plan</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>Chercher</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>Basculer le mode focus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>Fermer</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation>Rechercher</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation>Remplacer par</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>Chercher</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>Sensible à la casse</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>Mots entiers uniquement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>Expressions régulières</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>Recherche en boucle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>Chercher dans le fichier suivant</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>Conserver la casse</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>Terminer la recherche</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>Chercher dans le document actuel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>Chercher et remplacer dans le document actuel</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>Document ouvert : {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>Ce document a été modifié en dehors de novelWriter pendant qu'il était ouvert. Écraser le fichier sur le disque ?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>Impossible d'enregistrer le document.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>Document enregistré : {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>La vérification orthographique nécessite PyEnchant qui ne semble pas installé ici.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>La vérification orthographique est terminée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>Détails du document</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>Créé : {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>Mis à jour : {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>Emplacement du fichier : {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>Définir comme nom du document</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>Suivre cette étiquette</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>Créer une note pour l'étiquette</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>Couper</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>Copier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>Coller</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>Sélectionner tout</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>Sélectionner le mot</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>Sélectionner le paragraphe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>Orthographe suggérée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>Pas de suggestion</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>Ajouter ce mot au dictionnaire</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>Veuillez sélectionner du texte avant de demander le remplacement des guillemets.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>Voulez-vous créer une nouvelle note de projet pour l'étiquette '{0}' ?</translation>
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>Markdown gras</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>Markdown italique</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>Markdown barré</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>Code court gras</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>Code court italique</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>Code court barré</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>Code court souligné</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation>Surligner les codes courts</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>Code court exposant</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>Code court indice</translation>
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>Compiler le manuscrit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>Format de sortie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>Table des matières</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>Emplacement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>Nom du fichier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>Rétablir le nom de fichier par défaut</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>Ouvrir le dossier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>&Compiler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>Sélectionner un dossier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>Le dossier de sortie n'existe pas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>Ce fichier existe déjà. Voulez-vous l'écraser ?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>Plan de</translation>
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>Rétablir les valeurs par défaut</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>Revenir en arrière</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< Retour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>Continuer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&Suivant</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>&Suivant ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>Appliquer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>Terminé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>&Terminer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>Annuler</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>Aide</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&Aide</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>Fichier de projet ou fichier Zip novelWriter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>Fichier projet novelWriter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>Ouvrir un projet</translation>
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>Paramètre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>Valeur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>Nom</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>Sélection</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>Titre</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation>Caché</translation>
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>Information</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>Avertissement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>Erreur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>Question</translation>
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>Appuyez sur le bouton "Aperçu" pour générer...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>Traitement en cours...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>Terminé</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>Inconnu</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>Compilé</translation>
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation>Mots</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation>Signes, espaces compris</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation>Mots dans les titres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation>Mots dans le texte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation>Titres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation>Paragraphes</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation>Signes dans les titres</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation>Signes dans le texte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation>Signes, espaces exclus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation>Signes dans les titres, espaces exclus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation>Signes dans le texte, espaces exclus</translation>
|
||||
</message>
|
||||
|
||||
255
i18n/nw_it_IT.ts
255
i18n/nw_it_IT.ts
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>Riga: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>Parole: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>Parole: {0} selezionate</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>Stato</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>Attiva/disattiva la Barra degli strumenti</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation>Struttura</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>Cerca</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>Attiva/Disattiva modalità Focus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>Chiudi</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation>Ricerca</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation>Sostituisci con</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>Cerca</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>Considera maiuscole/minuscole</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>Solo parole intere</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>Modalità RegEx</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>Ricerca a ciclo continuo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>Cerca nel file successivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>Non considerare maiuscole/minuscole</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>Chiudi ricerca</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>Trova nel documento corrente</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>Trova e sostituisci nel documento corrente</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>Documento aperto: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>Questo documento è stato cambiato al di fuori di novelWriter mentre era aperto. Sovrascrivere il file su disco?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>Impossibile salvare il documento.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>Documento salvato: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>Il controllo ortografico richiede il pacchetto PyEnchant. Non sembra essere installato.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>Controllo ortografico completo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>Dettagli del documento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>Creato: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>Aggiornato: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>Posizione del file: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>Imposta come nome del documento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>Segui i Tag</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>Crea una nota per il Tag</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>Taglia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>Copia</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>Incolla</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>Seleziona tutto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>Seleziona parola</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>Seleziona paragrafo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>Suggerimento(i) ortografico(i)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>Nessun suggerimento</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>Aggiungi parola al dizionario</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>Per favore seleziona del testo prima di chiedere il cambio di virgolette.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>Vuoi creare una nuova nota di progetto per il tag '{0}'?</translation>
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>Markdown grassetto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>Markdown corsivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>Markdown barrato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>Shortcode grassetto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>Shortcode corsivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>Shortcode barrato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>Shortcode sottolineato</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation>Evidenziazione</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>Shortcode apice</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>Shortcode pendice</translation>
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>Compila manoscritto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>Formato di output</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>Tavola dei contenuti</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>Percorso</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>Nome file</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>Ripristina il nome del file predefinito</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>Apri cartella</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>&Compila</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>Seleziona cartella</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>La cartella di output non esiste.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>Questo file esiste già. Vuoi sovrascriverlo?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>Struttura di</translation>
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>Ripristina predefiniti</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>Torna indietro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< &Indietro</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>Continua</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&Successivo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>&Successivo ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>Esegui</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>Fatto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>&Termina</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>Cancella</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>Aiuto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&Aiuto</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>File di progetto di novelWriter o file Zip</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>File di progetto di novelWriter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>Apri progetto</translation>
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>Impostazioni</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>Valore</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>Nome</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>Selezione</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>Titolo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation>Nascosto</translation>
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>Informazioni</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>Attenzione</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>Errore</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>Domanda</translation>
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>Premi il tasto "Anteprima" per compilarla ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>In elaborazione ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>Fatto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>Sconosciuto</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>Realizzata</translation>
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation>Parole</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation>Caratteri</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation>Parole nelle intestazioni</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation>Parole nel testo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation>Intestazioni</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation>Paragrafi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation>Caratteri nelle intestazioni</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation>Caratteri nel testo</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation>Caratteri, esclusi gli spazi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation>Caratteri nelle intestazioni, esclusi gli spazi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation>Caratteri nel testo, esclusi gli spazi</translation>
|
||||
</message>
|
||||
|
||||
255
i18n/nw_ja_JP.ts
255
i18n/nw_ja_JP.ts
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>行: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>単語: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>単語: {0} 選択済み</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>ステータス</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>ツールバーの切り替え</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation>アウトライン</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>検索</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>フォーカスモードの切り替え</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>閉じる</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation>検索</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation>置換候補</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>検索</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>大文字と小文字を区別</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>完全一致のみ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>正規表現モード</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>ループ検索</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>次のファイルを検索</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>大文字と小文字を保持</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>検索を閉じる</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>現在のドキュメント内を検索</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>現在のドキュメント内を検索して置き換え</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>開かれたドキュメント: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>このドキュメントは、開いている間にnovelWriter以外で変更されました。ディスクにファイルを上書きしますか?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>ドキュメントを保存できませんでした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>保存済みドキュメント: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>スペルチェックにはPyEnchantパッケージが必要ですが、インストールされていないようです。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>スペルチェック完了</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>ドキュメントの詳細</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>作成済み: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>更新: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>ファイル場所: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>ドキュメント名として設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>タグをフォロー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>タグのメモを作成</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>切り取り</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>コピー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>貼り付け</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>すべて選択</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>単語を選択</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>段落を選択</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>スペルの提案</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>候補なし</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>単語を辞書に追加</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>置き換え引用符を呼び出す前にテキストを選択してください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>タグ '{0}' の新しいプロジェクトノートを作成しますか?</translation>
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>マークダウン 太字</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>マークダウン 斜体</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>マークダウン 取り消し線</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>ショートコード 太字</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>ショートコード 斜体</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>ショートコード 取り消し線</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>ショートコード 下線</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation>ショートコードハイライト</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>ショートコード 上付き文字</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>ショートコード 下付き文字</translation>
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>原稿をビルド</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>出力形式</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>目次</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>パス</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>ファイル名</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>ファイル名をデフォルトにリセット</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>フォルダーを開く</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>&ビルド</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>フォルダーを選択</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>出力フォルダが存在しません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>このファイルはすでに存在します。上書きしますか?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>アウトライン</translation>
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>既定値に戻す</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>戻る</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< &戻る</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>続行</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&次へ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>&次へ ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>コミット</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>完了</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>&終了</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>キャンセル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>ヘルプ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&ヘルプ</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>novelWriterプロジェクトファイルまたはZipファイル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>novelWriterプロジェクトファイル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>プロジェクトを開く</translation>
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>設定</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>値</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>名前</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>選択</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>タイトル</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation>非表示</translation>
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>情報</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>警告</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>エラー</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>質問</translation>
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>"プレビュー" ボタンを押して生成します ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>処理中…</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>完了</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>不明</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>ビルドされた</translation>
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation>単語数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation>文字数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation>見出し内の単語数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation>テキスト内の単語数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation>見出し</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation>段落</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation>見出し内の文字数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation>テキスト内の文字数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation>スペースなし文字数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation>見出し内のスペースなし文字数</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation>テキスト内のスペースなし文字数</translation>
|
||||
</message>
|
||||
|
||||
255
i18n/nw_nb_NO.ts
255
i18n/nw_nb_NO.ts
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>Linje: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>Ord: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>Ord: {0} valgt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>Status</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>Vis/skjul verktøylinje</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation>Disposisjon</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>Søk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>Slå av/på "Fokus-modus"</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>Lukk</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation>Søketekst</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation>Erstatt med</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>Søk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>Skill store/små bokstaver</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>Kun hele ord</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>RegEx-modus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>Søk rundt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>Søk i neste file</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>Behold store/små bokstaver</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>Lukk søk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>Søk i det åpne dokumentet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>Søk og erstatt i det åpne dokumentet</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>Åpnet dokument: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>Dette dokumentet er endret utenfor novelWriter mens det var åpent. Overskrive filen på disken?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>Kunne ikke lagre dokumentet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>Lagret dokument: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>Stavekontroll krever at pakken PyEnchant er installert. Det ser det ikke ut til at den er.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>Stavekontrollen er ferdig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>Dokumentdetaljer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>Opprettet: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>Oppdatert: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>Filplassering: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>Sett som dokumentnavn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>Følg knagg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>Opprett notat for knagg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>Klipp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>Kopier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>Lim inn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>Velg hele teksten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>Velg hele ordet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>Velg hele avsnittet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>Forslag fra stavekontrollen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>Ingen forslag</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>Legg til ord i ordbok</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>Venligst velg en del av teksten før du velger å erstatte sitattegn.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>Vil du opprette et nytt prosjektnotat for knaggen '{0}'?</translation>
|
||||
</message>
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>Fet skrift med Markdown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>Kursiv med Markdown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>Gjennomstrek med Markdown</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>Fet skrift med kortkode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>Kursiv med kortkode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>Gjennomstrek med kortkode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>Understrek med kortkode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation>Tekstutheving med kortkode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>Hevet skrift med kortkode</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>Senket skrift med kortkode</translation>
|
||||
</message>
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>Bygg manuskript</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>Dokumentformat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>Innholdsfortegnelse</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>Filbane</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>Filnavn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>Tilbakestill filnavn til standard</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>Åpne mappe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>&Bygg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>Velg mappe</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>Mappen eksisterer ikke.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>Filen eksisterer allerede. Vil du overskrive den?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>Disposisjon for</translation>
|
||||
</message>
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>Gjennopprett standard</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>Gå tilbake</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< &Tilbake</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>Fortsett</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&Neste</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>&Neste ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>Gjennomfør</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>Ferdig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>&Fullfør</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>Avbryt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>Hjelp</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&Hjelp</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>novelWriter prosjektfil eller Zip-fil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>novelWriter prosjektfil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>Åpne prosjekt</translation>
|
||||
</message>
|
||||
@@ -4041,32 +3982,32 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>Innstilling</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>Verdi</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>Navn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>Utvalg</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>Tittel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation>Skjult</translation>
|
||||
</message>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>Informasjon</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>Advarsel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>Feil</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>Spørsmål</translation>
|
||||
</message>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>Trykk på "Forhåndsvisning"-knappen for å generere ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>Behandler ...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>Ferdig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>Ukjent</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>Bygget</translation>
|
||||
</message>
|
||||
@@ -4557,59 +4498,59 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation>Ord</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation>Tegn</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation>Ord i overskrifter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation>Ord i tekst</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation>Overskrifter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation>Avsnitt</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation>Tegn i overskrifter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation>Tegn i tekst</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation>Tegn, utenom mellomrom</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation>Tegn i overskrifter, utenom mellomrom</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation>Tegn i tekst, utenom mellomrom</translation>
|
||||
</message>
|
||||
|
||||
365
i18n/nw_nl_NL.ts
365
i18n/nw_nl_NL.ts
@@ -31,32 +31,32 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="109" />
|
||||
<source>Partition Format</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Partitie indeling</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="110" />
|
||||
<source>Chapter Format</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Hoofdstuk indeling</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="111" />
|
||||
<source>Unnumbered Format</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Ongenummerde indeling</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="112" />
|
||||
<source>Scene Format</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Scène indeling</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="113" />
|
||||
<source>Alt. Scene Format</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Alt. Scène Formaat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="114" />
|
||||
<source>Section Format</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Sectie indeling</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="116" />
|
||||
@@ -86,7 +86,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="121" />
|
||||
<source>Ignore These Keywords</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Negeer deze sleutelwoorden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="122" />
|
||||
@@ -206,17 +206,17 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="147" />
|
||||
<source>First Line Indent</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Eerste regel inspringen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="149" />
|
||||
<source>Markdown (.md)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Markdown (.md)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="150" />
|
||||
<source>Preserve Hard Line Breaks</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Behoud harde regel afbrekingen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="152" />
|
||||
@@ -231,7 +231,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/core/buildsettings.py" line="154" />
|
||||
<source>Preserve Tab Characters</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Tab tekens behouden</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -791,22 +791,22 @@
|
||||
<context>
|
||||
<name>GuiDocEditFooter</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3007" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<source>Line: {0} ({1})</source>
|
||||
<translation>Regel: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3008" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<source>Words: {0} ({1})</source>
|
||||
<translation>Woorden: {0} ({1})</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3009" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3010" />
|
||||
<source>Words: {0} selected</source>
|
||||
<translation>Woorden: {0} geselecteerd</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3021" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="3022" />
|
||||
<source>Status</source>
|
||||
<translation>Status</translation>
|
||||
</message>
|
||||
@@ -814,27 +814,27 @@
|
||||
<context>
|
||||
<name>GuiDocEditHeader</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2805" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2806" />
|
||||
<source>Toggle Tool Bar</source>
|
||||
<translation>Toon/verberg werkbalk</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2810" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2811" />
|
||||
<source>Outline</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Samenvatting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2815" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2816" />
|
||||
<source>Search</source>
|
||||
<translation>Zoek</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2820" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2821" />
|
||||
<source>Toggle Focus Mode</source>
|
||||
<translation>Schakel focus modus in/uit</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2825" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2826" />
|
||||
<source>Close</source>
|
||||
<translation>Sluiten</translation>
|
||||
</message>
|
||||
@@ -842,62 +842,62 @@
|
||||
<context>
|
||||
<name>GuiDocEditSearch</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2413" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2414" />
|
||||
<source>Search for</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Zoek naar</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2418" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2419" />
|
||||
<source>Replace with</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Vervang door</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2426" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2427" />
|
||||
<source>Search</source>
|
||||
<translation>Zoek</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2434" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2435" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation>Hoofdlettergevoelig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2440" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2441" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation>Alleen hele woorden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2446" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2447" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation>RegEx modus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2452" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2453" />
|
||||
<source>Loop Search</source>
|
||||
<translation>Zoekopdracht lus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2458" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2459" />
|
||||
<source>Search Next File</source>
|
||||
<translation>Doorzoek volgend bestand</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2466" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2467" />
|
||||
<source>Preserve Case</source>
|
||||
<translation>Behoud hoofd/kleine letters</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2474" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2475" />
|
||||
<source>Close Search</source>
|
||||
<translation>Zoekopdracht afsluiten</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2485" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2486" />
|
||||
<source>Find in current document</source>
|
||||
<translation>Zoeken in huidige document</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2489" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2490" />
|
||||
<source>Find and replace in current document</source>
|
||||
<translation>Zoek en vervang in huidig document</translation>
|
||||
</message>
|
||||
@@ -905,122 +905,122 @@
|
||||
<context>
|
||||
<name>GuiDocEditor</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="441" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="442" />
|
||||
<source>Opened Document: {0}</source>
|
||||
<translation>Geopend document: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="484" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="485" />
|
||||
<source>This document has been changed outside of novelWriter while it was open. Overwrite the file on disk?</source>
|
||||
<translation>Dit document is gewijzigd buiten de openstaande novelWriter instantie. Het bestand op de schijf overschrijven?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="493" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="494" />
|
||||
<source>Could not save document.</source>
|
||||
<translation>Kon document niet opslaan.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="518" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="519" />
|
||||
<source>Saved Document: {0}</source>
|
||||
<translation>Document opgeslagen: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="687" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="688" />
|
||||
<source>Spell checking requires the package PyEnchant. It does not appear to be installed.</source>
|
||||
<translation>Spellingscontrole vereist het pakket PyEnchant. Het lijkt niet geïnstalleerd te zijn.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="713" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="714" />
|
||||
<source>Spell check complete</source>
|
||||
<translation>Spellingscontrole compleet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="833" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="834" />
|
||||
<source>Document Details</source>
|
||||
<translation>Document details</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="835" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<source>Created: {0}</source>
|
||||
<translation>Aangemaakt: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="836" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="837" />
|
||||
<source>Updated: {0}</source>
|
||||
<translation>Bijgewerkt: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="838" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="839" />
|
||||
<source>File Location: {0}</source>
|
||||
<translation>Bestandslocatie: {0}</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1112" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1113" />
|
||||
<source>Set as Document Name</source>
|
||||
<translation>Instellen als documentnaam</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1118" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1119" />
|
||||
<source>Follow Tag</source>
|
||||
<translation>Volg label</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1122" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1123" />
|
||||
<source>Create Note for Tag</source>
|
||||
<translation>Creëer notitie voor label</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1128" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1129" />
|
||||
<source>Cut</source>
|
||||
<translation>Knippen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1130" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1131" />
|
||||
<source>Copy</source>
|
||||
<translation>Kopiëren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1133" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1134" />
|
||||
<source>Paste</source>
|
||||
<translation>Plakken</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1138" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1139" />
|
||||
<source>Select All</source>
|
||||
<translation>Selecteer alles</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1140" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1141" />
|
||||
<source>Select Word</source>
|
||||
<translation>Selecteer woord</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1144" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1145" />
|
||||
<source>Select Paragraph</source>
|
||||
<translation>Selecteer paragraaf</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1160" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1161" />
|
||||
<source>Spelling Suggestion(s)</source>
|
||||
<translation>Spelling suggestie(s)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1167" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1168" />
|
||||
<source>No Suggestions</source>
|
||||
<translation>Geen suggesties</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1170" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1171" />
|
||||
<source>Add Word to Dictionary</source>
|
||||
<translation>Woord toevoegen aan woordenboek</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1596" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1597" />
|
||||
<source>Please select some text before calling replace quotes.</source>
|
||||
<translation>Selecteer a.u.b. een tekst voordat u vervang aanhalingstekens aanroept.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1903" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="1904" />
|
||||
<source>Do you want to create a new project note for the tag '{0}'?</source>
|
||||
<translation>Wilt u een nieuwe project notitie maken voor het label '{0}'?</translation>
|
||||
</message>
|
||||
@@ -1058,7 +1058,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/dialogs/docsplit.py" line="61" />
|
||||
<source>Document Headings</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Document koppen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/dialogs/docsplit.py" line="64" />
|
||||
@@ -1068,22 +1068,22 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/dialogs/docsplit.py" line="86" />
|
||||
<source>Split on Heading Level 1 (Partition)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Splits op kop niveau 1 (Partitie)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/dialogs/docsplit.py" line="87" />
|
||||
<source>Split up to Heading Level 2 (Chapter)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Opsplitsen tot kop niveau 2 (Hoofdstuk)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/dialogs/docsplit.py" line="88" />
|
||||
<source>Split up to Heading Level 3 (Scene)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Opsplitsen tot kop niveau 3 (Scène)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/dialogs/docsplit.py" line="89" />
|
||||
<source>Split up to Heading Level 4 (Section)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Opsplitsen tot kop niveau 4 (Sectie)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/dialogs/docsplit.py" line="96" />
|
||||
@@ -1104,52 +1104,52 @@
|
||||
<context>
|
||||
<name>GuiDocToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2270" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2271" />
|
||||
<source>Markdown Bold</source>
|
||||
<translation>Markdown vet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2276" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2277" />
|
||||
<source>Markdown Italic</source>
|
||||
<translation>Markdown cursief</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2282" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2283" />
|
||||
<source>Markdown Strikethrough</source>
|
||||
<translation>Markdown doorstrepen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2288" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2289" />
|
||||
<source>Shortcode Bold</source>
|
||||
<translation>Korte code vet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2294" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2295" />
|
||||
<source>Shortcode Italic</source>
|
||||
<translation>Korte code cursief</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2300" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2301" />
|
||||
<source>Shortcode Strikethrough</source>
|
||||
<translation>Korte code doorstrepen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2306" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2307" />
|
||||
<source>Shortcode Underline</source>
|
||||
<translation>Korte code onderstrepen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2312" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2313" />
|
||||
<source>Shortcode Highlight</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Snelkoppeling accentuering</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2318" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2319" />
|
||||
<source>Shortcode Superscript</source>
|
||||
<translation>Korte code superscript</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2324" />
|
||||
<location filename="../novelwriter/gui/doceditor.py" line="2325" />
|
||||
<source>Shortcode Subscript</source>
|
||||
<translation>Korte code subscript</translation>
|
||||
</message>
|
||||
@@ -1187,7 +1187,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/docviewer.py" line="659" />
|
||||
<source>Outline</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Samenvatting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/docviewer.py" line="664" />
|
||||
@@ -1854,7 +1854,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="676" />
|
||||
<source>Highlight</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Markeren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="682" />
|
||||
@@ -1869,22 +1869,22 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="697" />
|
||||
<source>Heading 1 (Partition)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Kop 1 (Partitie)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="704" />
|
||||
<source>Heading 2 (Chapter)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Kop 2 (Hoofdstuk)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="711" />
|
||||
<source>Heading 3 (Scene)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Kop 3 (Scène)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="718" />
|
||||
<source>Heading 4 (Section)</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Kop 4 (Sectie)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="728" />
|
||||
@@ -1899,7 +1899,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="740" />
|
||||
<source>Alternative Scene</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Alternatieve scène</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="749" />
|
||||
@@ -1944,12 +1944,12 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="814" />
|
||||
<source>Replace Straight Single Quotes</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Vervang rechte enkele aanhalingstekens</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="820" />
|
||||
<source>Replace Straight Double Quotes</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Vervang rechte dubbele aanhalingstekens</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="826" />
|
||||
@@ -1989,7 +1989,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="869" />
|
||||
<source>Find in Project</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Zoek in project</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/mainmenu.py" line="878" />
|
||||
@@ -2161,12 +2161,12 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="158" />
|
||||
<source>Details</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Details</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="159" />
|
||||
<source>Outline</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Samenvatting</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="173" />
|
||||
@@ -2198,57 +2198,57 @@
|
||||
<context>
|
||||
<name>GuiManuscriptBuild</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="72" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="70" />
|
||||
<source>Build Manuscript</source>
|
||||
<translation>Bouw manuscript</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="93" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="91" />
|
||||
<source>Output Format</source>
|
||||
<translation>Uitvoerformaat</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="119" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="117" />
|
||||
<source>Table of Contents</source>
|
||||
<translation>Inhoudsopgave</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="147" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="145" />
|
||||
<source>Path</source>
|
||||
<translation>Pad</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="157" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="155" />
|
||||
<source>File Name</source>
|
||||
<translation>Bestandsnaam</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="160" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="158" />
|
||||
<source>Reset file name to default</source>
|
||||
<translation>Herstel bestandsnaam naar standaard</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="182" />
|
||||
<source>Open Folder</source>
|
||||
<translation>Map openen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="186" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="184" />
|
||||
<source>&Build</source>
|
||||
<translation>&Bouwen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="281" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="279" />
|
||||
<source>Select Folder</source>
|
||||
<translation>Selecteer map</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="319" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="317" />
|
||||
<source>Output folder does not exist.</source>
|
||||
<translation>Uitvoermap bestaat niet.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="327" />
|
||||
<location filename="../novelwriter/tools/manusbuild.py" line="325" />
|
||||
<source>The file already exists. Do you want to overwrite it?</source>
|
||||
<translation>Het bestand bestaat al. Wil je het overschrijven?</translation>
|
||||
</message>
|
||||
@@ -2415,7 +2415,7 @@
|
||||
<context>
|
||||
<name>GuiOutlineToolBar</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/outline.py" line="223" />
|
||||
<location filename="../novelwriter/gui/outline.py" line="222" />
|
||||
<source>Outline of</source>
|
||||
<translation>Omlijning van</translation>
|
||||
</message>
|
||||
@@ -2997,27 +2997,27 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/search.py" line="74" />
|
||||
<source>Project Search</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Project zoeken</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/search.py" line="84" />
|
||||
<source>Case Sensitive</source>
|
||||
<translation type="unfinished">Hoofdlettergevoelig</translation>
|
||||
<translation>Hoofdlettergevoelig</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/search.py" line="89" />
|
||||
<source>Whole Words Only</source>
|
||||
<translation type="unfinished">Alleen hele woorden</translation>
|
||||
<translation>Alleen hele woorden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/search.py" line="94" />
|
||||
<source>RegEx Mode</source>
|
||||
<translation type="unfinished">RegEx modus</translation>
|
||||
<translation>RegEx modus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/search.py" line="101" />
|
||||
<source>Search for</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Zoek naar</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -3231,7 +3231,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/sidebar.py" line="73" />
|
||||
<source>Project Search</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Project zoeken</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/sidebar.py" line="77" />
|
||||
@@ -3860,79 +3860,20 @@
|
||||
<translation>Standaardwaarden herstellen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QWizard</name>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="54" />
|
||||
<source>Go Back</source>
|
||||
<translation>Ga terug</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="55" />
|
||||
<source>< &Back</source>
|
||||
<translation>< &Terug</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="56" />
|
||||
<source>Continue</source>
|
||||
<translation>Doorgaan</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="57" />
|
||||
<source>&Next</source>
|
||||
<translation>&Volgende</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="58" />
|
||||
<source>&Next ></source>
|
||||
<translation>&Volgende ></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="59" />
|
||||
<source>Commit</source>
|
||||
<translation>Vastleggen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="60" />
|
||||
<source>Done</source>
|
||||
<translation>Gereed</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="61" />
|
||||
<source>&Finish</source>
|
||||
<translation>Vol&tooien</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="63" />
|
||||
<location filename="qtbase.py" line="62" />
|
||||
<source>Cancel</source>
|
||||
<translation>Annuleer</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="64" />
|
||||
<source>Help</source>
|
||||
<translation>Help</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="qtbase.py" line="65" />
|
||||
<source>&Help</source>
|
||||
<translation>&Help</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>SharedData</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="249" />
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<source>novelWriter Project File or Zip File</source>
|
||||
<translation>novelWriter project- of zip bestand</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="250" />
|
||||
<location filename="../novelwriter/shared.py" line="251" />
|
||||
<source>novelWriter Project File</source>
|
||||
<translation>novelWriter Projectbestand</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="254" />
|
||||
<location filename="../novelwriter/shared.py" line="255" />
|
||||
<source>Open Project</source>
|
||||
<translation>Project openen</translation>
|
||||
</message>
|
||||
@@ -4041,34 +3982,34 @@
|
||||
<context>
|
||||
<name>_DetailsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Setting</source>
|
||||
<translation>Instelling</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="522" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="533" />
|
||||
<source>Value</source>
|
||||
<translation>Waarde</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="589" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="600" />
|
||||
<source>Name</source>
|
||||
<translation>Naam</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="595" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="606" />
|
||||
<source>Selection</source>
|
||||
<translation>Selectie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="611" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="622" />
|
||||
<source>Title</source>
|
||||
<translation>Titel</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="612" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="623" />
|
||||
<source>Hidden</source>
|
||||
<translation type="unfinished">Verborgen</translation>
|
||||
<translation>Verborgen</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -4112,22 +4053,22 @@
|
||||
<context>
|
||||
<name>_GuiAlert</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="410" />
|
||||
<location filename="../novelwriter/shared.py" line="422" />
|
||||
<source>Information</source>
|
||||
<translation>Informatie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="413" />
|
||||
<location filename="../novelwriter/shared.py" line="425" />
|
||||
<source>Warning</source>
|
||||
<translation>Waarschuwing</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="416" />
|
||||
<location filename="../novelwriter/shared.py" line="428" />
|
||||
<source>Error</source>
|
||||
<translation>Foutmelding</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/shared.py" line="419" />
|
||||
<location filename="../novelwriter/shared.py" line="431" />
|
||||
<source>Question</source>
|
||||
<translation>Vraag</translation>
|
||||
</message>
|
||||
@@ -4209,21 +4150,21 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manussettings.py" line="758" />
|
||||
<source>Additional Styling</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Extra opmaak</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manussettings.py" line="795" />
|
||||
<location filename="../novelwriter/tools/manussettings.py" line="780" />
|
||||
<location filename="../novelwriter/tools/manussettings.py" line="765" />
|
||||
<source>Centre</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Midden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manussettings.py" line="797" />
|
||||
<location filename="../novelwriter/tools/manussettings.py" line="782" />
|
||||
<location filename="../novelwriter/tools/manussettings.py" line="767" />
|
||||
<source>Page Break</source>
|
||||
<translation type="unfinished">Nieuwe pagina</translation>
|
||||
<translation>Nieuwe pagina</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -4438,27 +4379,27 @@
|
||||
<context>
|
||||
<name>_PreviewWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="757" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="769" />
|
||||
<source>Press the "Preview" button to generate ...</source>
|
||||
<translation>Druk op de knop "Preview" om te genereren...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="855" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="867" />
|
||||
<source>Processing ...</source>
|
||||
<translation>Wordt verwerkt...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="877" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="888" />
|
||||
<source>Done</source>
|
||||
<translation>Gereed</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="927" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="938" />
|
||||
<source>Unknown</source>
|
||||
<translation>Onbekend</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="928" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="939" />
|
||||
<source>Built</source>
|
||||
<translation>Gebouwd</translation>
|
||||
</message>
|
||||
@@ -4557,61 +4498,61 @@
|
||||
<context>
|
||||
<name>_StatsWidget</name>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1090" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1050" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1102" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1062" />
|
||||
<source>Words</source>
|
||||
<translation type="unfinished">Woorden</translation>
|
||||
<translation>Woorden</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1117" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1053" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1129" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1065" />
|
||||
<source>Characters</source>
|
||||
<translation type="unfinished">Tekens</translation>
|
||||
<translation>Tekens</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1091" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1103" />
|
||||
<source>Words in Headings</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Woorden in koppen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1092" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1104" />
|
||||
<source>Words in Text</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Woorden in tekst</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1094" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1106" />
|
||||
<source>Headings</source>
|
||||
<translation type="unfinished">Koppen</translation>
|
||||
<translation>Koppen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1095" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1107" />
|
||||
<source>Paragraphs</source>
|
||||
<translation type="unfinished">Paragrafen</translation>
|
||||
<translation>Paragrafen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1118" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1130" />
|
||||
<source>Characters in Headings</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Tekens in koppen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1119" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1131" />
|
||||
<source>Characters in Text</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Tekens in tekst</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1120" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1132" />
|
||||
<source>Characters, No Spaces</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Tekens, geen spaties</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1121" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1133" />
|
||||
<source>Characters in Headings, No Spaces</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Tekens in koppen, geen spaties</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1122" />
|
||||
<location filename="../novelwriter/tools/manuscript.py" line="1134" />
|
||||
<source>Characters in Text, No Spaces</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Tekens in tekst, geen spaties</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
@@ -4771,7 +4712,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/projtree.py" line="1932" />
|
||||
<source>Split Document by Headings</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Document splitsen op koppen</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/projtree.py" line="1942" />
|
||||
@@ -4786,7 +4727,7 @@
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/projtree.py" line="1947" />
|
||||
<source>Duplicate</source>
|
||||
<translation type="unfinished" />
|
||||
<translation>Dupliceren</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../novelwriter/gui/projtree.py" line="1963" />
|
||||
|
||||
895
i18n/nw_zh_CN.ts
895
i18n/nw_zh_CN.ts
File diff suppressed because it is too large
Load Diff
@@ -47,19 +47,3 @@ QT_TRANSLATE_NOOP("QPlatformTheme", "Help")
|
||||
QT_TRANSLATE_NOOP("QPlatformTheme", "Apply")
|
||||
QT_TRANSLATE_NOOP("QPlatformTheme", "Reset")
|
||||
QT_TRANSLATE_NOOP("QPlatformTheme", "Restore Defaults")
|
||||
|
||||
# QWizard
|
||||
# =======
|
||||
|
||||
QT_TRANSLATE_NOOP("QWizard", "Go Back")
|
||||
QT_TRANSLATE_NOOP("QWizard", "< &Back")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Continue")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Next")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Next >")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Commit")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Done")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Finish")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Cancel")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Cancel")
|
||||
QT_TRANSLATE_NOOP("QWizard", "Help")
|
||||
QT_TRANSLATE_NOOP("QWizard", "&Help")
|
||||
|
||||
@@ -32,7 +32,7 @@ from typing import TYPE_CHECKING
|
||||
from PyQt5.QtWidgets import QApplication, QErrorMessage
|
||||
|
||||
from novelwriter.config import Config
|
||||
from novelwriter.error import exceptionHandler, logException
|
||||
from novelwriter.error import exceptionHandler
|
||||
from novelwriter.shared import SharedData
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@@ -47,9 +47,9 @@ __license__ = "GPLv3"
|
||||
__author__ = "Veronica Berglyd Olsen"
|
||||
__maintainer__ = "Veronica Berglyd Olsen"
|
||||
__email__ = "code@vkbo.net"
|
||||
__version__ = "2.4"
|
||||
__hexversion__ = "0x020400f0"
|
||||
__date__ = "2024-04-20"
|
||||
__version__ = "2.5b1"
|
||||
__hexversion__ = "0x020500b1"
|
||||
__date__ = "2024-05-26"
|
||||
__status__ = "Stable"
|
||||
__domain__ = "novelwriter.io"
|
||||
|
||||
@@ -162,19 +162,19 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
# Check Packages and Versions
|
||||
errorData = []
|
||||
errorCode = 0
|
||||
if sys.hexversion < 0x030800f0:
|
||||
if sys.hexversion < 0x030900f0:
|
||||
errorData.append(
|
||||
"At least Python 3.8 is required, found %s" % CONFIG.verPyString
|
||||
"At least Python 3.9 is required, found %s" % CONFIG.verPyString
|
||||
)
|
||||
errorCode |= 0x04
|
||||
if CONFIG.verQtValue < 0x050a00:
|
||||
if CONFIG.verQtValue < 0x050f00:
|
||||
errorData.append(
|
||||
"At least Qt5 version 5.10 is required, found %s" % CONFIG.verQtString
|
||||
"At least Qt5 version 5.15.0 is required, found %s" % CONFIG.verQtString
|
||||
)
|
||||
errorCode |= 0x08
|
||||
if CONFIG.verPyQtValue < 0x050a00:
|
||||
if CONFIG.verPyQtValue < 0x050f00:
|
||||
errorData.append(
|
||||
"At least PyQt5 version 5.10 is required, found %s" % CONFIG.verPyQtString
|
||||
"At least PyQt5 version 5.15.0 is required, found %s" % CONFIG.verPyQtString
|
||||
)
|
||||
errorCode |= 0x10
|
||||
|
||||
@@ -198,52 +198,46 @@ def main(sysArgs: list | None = None) -> GuiMain | None:
|
||||
# Finish initialising config
|
||||
CONFIG.initConfig(confPath, dataPath)
|
||||
|
||||
if CONFIG.osDarwin:
|
||||
if sys.platform == "darwin":
|
||||
try:
|
||||
from Foundation import NSBundle # type: ignore
|
||||
bundle = NSBundle.mainBundle()
|
||||
info = bundle.localizedInfoDictionary() or bundle.infoDictionary()
|
||||
info["CFBundleName"] = "novelWriter"
|
||||
except Exception:
|
||||
logger.error("Failed to set application name")
|
||||
logException()
|
||||
|
||||
elif CONFIG.osWindows:
|
||||
pass # Quietly ignore error
|
||||
elif sys.platform == "win32":
|
||||
try:
|
||||
import ctypes
|
||||
appID = f"io.novelwriter.{__version__}"
|
||||
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appID) # type: ignore
|
||||
except Exception:
|
||||
logger.error("Failed to set application name")
|
||||
logException()
|
||||
pass # Quietly ignore error
|
||||
|
||||
# Import GUI (after dependency checks), and launch
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
if testMode:
|
||||
nwGUI = GuiMain()
|
||||
return nwGUI
|
||||
# Only used for testing where the test framework creates the app
|
||||
CONFIG.loadConfig()
|
||||
return GuiMain()
|
||||
|
||||
else:
|
||||
nwApp = QApplication([CONFIG.appName, (f"-style={qtStyle}")])
|
||||
nwApp.setApplicationName(CONFIG.appName)
|
||||
nwApp.setApplicationVersion(__version__)
|
||||
nwApp.setOrganizationDomain(__domain__)
|
||||
nwApp.setOrganizationName(__domain__)
|
||||
nwApp.setDesktopFileName(CONFIG.appName)
|
||||
app = QApplication([CONFIG.appName, (f"-style={qtStyle}")])
|
||||
app.setApplicationName(CONFIG.appName)
|
||||
app.setApplicationVersion(__version__)
|
||||
app.setOrganizationDomain(__domain__)
|
||||
app.setOrganizationName(__domain__)
|
||||
app.setDesktopFileName(CONFIG.appName)
|
||||
|
||||
# Connect the exception handler before making the main GUI
|
||||
sys.excepthook = exceptionHandler
|
||||
# Connect the exception handler before making the main GUI
|
||||
sys.excepthook = exceptionHandler
|
||||
|
||||
# Run Config steps that require the QApplication
|
||||
CONFIG.initLocalisation(nwApp)
|
||||
CONFIG.setTextFont(CONFIG.textFont, CONFIG.textSize) # Makes sure these are valid
|
||||
# Run Config steps that require the QApplication
|
||||
CONFIG.loadConfig()
|
||||
CONFIG.initLocalisation(app)
|
||||
|
||||
# Launch main GUI
|
||||
nwGUI = GuiMain()
|
||||
nwGUI.postLaunchTasks(cmdOpen)
|
||||
# Launch main GUI
|
||||
nwGUI = GuiMain()
|
||||
nwGUI.postLaunchTasks(cmdOpen)
|
||||
|
||||
sys.exit(nwApp.exec())
|
||||
|
||||
return None
|
||||
|
||||
# END Function main
|
||||
sys.exit(app.exec())
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"Synopsis": "Synopsis",
|
||||
"Short Description": "Short Description",
|
||||
"Footnotes": "Footnotes",
|
||||
"Comment": "Comment",
|
||||
"Notes": "Notes",
|
||||
"Tag": "Tag",
|
||||
|
||||
@@ -59,6 +59,7 @@ fmt_strike-md = nw_tb-strike-md.svg
|
||||
fmt_subscript = nw_tb-subscript.svg
|
||||
fmt_superscript = nw_tb-superscript.svg
|
||||
fmt_underline = nw_tb-underline.svg
|
||||
font = nw_font.svg
|
||||
forward = typ_chevron-right.svg
|
||||
import = mixed_import.svg
|
||||
list = typ_th-list.svg
|
||||
@@ -78,6 +79,7 @@ proj_scene = mixed_document-scene.svg
|
||||
proj_section = mixed_document-section.svg
|
||||
proj_stats = typ_chart-bar-grey.svg
|
||||
proj_title = mixed_document-title.svg
|
||||
quote = nw_quote.svg
|
||||
refresh = typ_refresh.svg
|
||||
remove = typ_minus.svg
|
||||
revert = typ_refresh-flipped.svg
|
||||
|
||||
4
novelwriter/assets/icons/typicons_dark/nw_font.svg
Normal file
4
novelwriter/assets/icons/typicons_dark/nw_font.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m2.5744 5.8208v-4.2853h-1.4527v-1.0064h4.1067v1.0064h-1.4527v4.2853z" fill="#aeaeae" stroke-width="1.1503"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 267 B |
4
novelwriter/assets/icons/typicons_dark/nw_quote.svg
Normal file
4
novelwriter/assets/icons/typicons_dark/nw_quote.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m1.3715 3.0659q-0.32092-0.25674-0.44928-0.44928-0.12836-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171zm2.7598 0q-0.32092-0.25674-0.44928-0.44928-0.12837-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171z" fill="#aeaeae" fill-opacity=".78039" stroke-width="1.8194"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -59,6 +59,7 @@ fmt_strike-md = nw_tb-strike-md.svg
|
||||
fmt_subscript = nw_tb-subscript.svg
|
||||
fmt_superscript = nw_tb-superscript.svg
|
||||
fmt_underline = nw_tb-underline.svg
|
||||
font = nw_font.svg
|
||||
forward = typ_chevron-right.svg
|
||||
import = mixed_import.svg
|
||||
list = typ_th-list.svg
|
||||
@@ -78,6 +79,7 @@ proj_scene = mixed_document-scene.svg
|
||||
proj_section = mixed_document-section.svg
|
||||
proj_stats = typ_chart-bar-grey.svg
|
||||
proj_title = mixed_document-title.svg
|
||||
quote = nw_quote.svg
|
||||
refresh = typ_refresh.svg
|
||||
remove = typ_minus.svg
|
||||
revert = typ_refresh-flipped.svg
|
||||
|
||||
4
novelwriter/assets/icons/typicons_light/nw_font.svg
Normal file
4
novelwriter/assets/icons/typicons_light/nw_font.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m2.5744 5.8208v-4.2853h-1.4527v-1.0064h4.1067v1.0064h-1.4527v4.2853z" fill-opacity=".78039" stroke-width="1.1503"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 274 B |
4
novelwriter/assets/icons/typicons_light/nw_quote.svg
Normal file
4
novelwriter/assets/icons/typicons_light/nw_quote.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="24" height="24" version="1.1" viewBox="0 0 6.35 6.35" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m1.3715 3.0659q-0.32092-0.25674-0.44928-0.44928-0.12836-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171zm2.7598 0q-0.32092-0.25674-0.44928-0.44928-0.12837-0.19255-0.12837-0.44928 0-0.42361 0.28241-0.69319 0.28241-0.28241 0.68035-0.28241 0.25674 0 0.44928 0.10269 0.19255 0.089858 0.3466 0.23106 0.24391 0.4878 0.24391 1.0141 0 0.42361-0.14121 0.82157-0.12837 0.38511-0.37227 0.71886-0.23106 0.33377-0.55199 0.61618-0.30808 0.26958-0.65467 0.46213l-0.25674-0.41078q0.29525-0.21822 0.57766-0.53914 0.28241-0.33375 0.46213-0.73171z" fill-opacity=".78039" stroke-width="1.8194"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.0 KiB |
@@ -12,15 +12,17 @@ link = 77, 077, 255
|
||||
headertext = 255, 255, 255
|
||||
headertag = 50, 0, 180
|
||||
emphasis = 0, 255, 255
|
||||
straightquotes = 7, 27, 219
|
||||
doublequotes = 0, 255, 0
|
||||
singlequotes = 0, 140, 255
|
||||
dialog = 0, 255, 0
|
||||
altdialog = 0, 140, 255
|
||||
note = 150, 150, 150
|
||||
hidden = 77, 77, 100
|
||||
shortcode = 255, 255, 0
|
||||
keyword = 255, 100, 255
|
||||
tag = 255, 150, 10
|
||||
value = 255, 150, 10
|
||||
spellcheckline = 242, 72, 23
|
||||
errorline = 186, 218, 4
|
||||
replacetag = 0, 0, 180
|
||||
modifier = 144, 142, 176
|
||||
optional = 180, 180, 180
|
||||
texthighlight = 255, 255, 132, 96
|
||||
|
||||
@@ -6,23 +6,37 @@ url = https://github.com/vkbo/novelWriter
|
||||
license = CC BY-SA 4.0
|
||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 2a2a2a : 42, 42, 42
|
||||
# Foreground = cccccc : 204, 204, 204
|
||||
# Comment = 969696 : 150, 150, 150
|
||||
# Red = e64250 : 230, 66, 80
|
||||
# Orange = f99157 : 249, 145, 87
|
||||
# Yellow = ffff84 : 255, 255, 132
|
||||
# Green = 99cc99 : 153, 204, 153
|
||||
# Blue = 288ed7 : 102, 153, 204
|
||||
# Purple = 8c56d7 : 140, 86, 215
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 54, 54, 54
|
||||
text = 199, 207, 208
|
||||
link = 184, 200, 0
|
||||
headertext = 0, 155, 200
|
||||
headertag = 0, 105, 135
|
||||
emphasis = 200, 120, 0
|
||||
straightquotes = 200, 46, 0
|
||||
doublequotes = 184, 200, 0
|
||||
singlequotes = 136, 200, 0
|
||||
background = 42, 42, 42
|
||||
text = 204, 204, 204
|
||||
link = 102, 153, 204
|
||||
headertext = 153, 204, 153
|
||||
headertag = 153, 204, 153, 160
|
||||
emphasis = 249, 145, 87
|
||||
dialog = 102, 153, 204
|
||||
altdialog = 102, 153, 204
|
||||
note = 255, 255, 216
|
||||
hidden = 150, 150, 150
|
||||
shortcode = 0, 155, 200
|
||||
keyword = 200, 46, 0
|
||||
value = 184, 200, 0
|
||||
optional = 0, 155, 200
|
||||
spellcheckline = 200, 46, 0
|
||||
errorline = 46, 200, 0
|
||||
replacetag = 0, 184, 46
|
||||
modifier = 200, 120, 0
|
||||
texthighlight = 136, 200, 0, 96
|
||||
shortcode = 153, 204, 153
|
||||
keyword = 230, 66, 80
|
||||
tag = 153, 204, 153
|
||||
value = 102, 153, 204
|
||||
optional = 153, 204, 153
|
||||
spellcheckline = 230, 66, 80
|
||||
errorline = 153, 204, 153
|
||||
replacetag = 153, 204, 153
|
||||
modifier = 153, 204, 153
|
||||
texthighlight = 255, 255, 132, 96
|
||||
|
||||
@@ -6,23 +6,37 @@ url = https://github.com/vkbo/novelWriter
|
||||
license = CC BY-SA 4.0
|
||||
licenseurl = https://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = ffffff : 255, 255, 255
|
||||
# Foreground = 000000 : 0, 0, 0
|
||||
# Comment = 646464 : 100, 100, 100
|
||||
# Red = c83232 : 200, 50, 50
|
||||
# Orange = ae6e1e : 174, 110, 30
|
||||
# Yellow = 969600 : 150, 150, 0
|
||||
# Green = 006400 : 0, 100, 0
|
||||
# Blue = 0000c8 : 0, 0, 200
|
||||
# Purple = 6400ae : 100, 0, 174
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 255, 255, 255
|
||||
text = 0, 0, 0
|
||||
link = 0, 0, 200
|
||||
headertext = 0, 100, 0
|
||||
headertag = 50, 100, 50
|
||||
emphasis = 150, 110, 30
|
||||
straightquotes = 200, 0, 0
|
||||
doublequotes = 0, 0, 200
|
||||
singlequotes = 0, 0, 200
|
||||
headertag = 0, 100, 0, 160
|
||||
emphasis = 174, 110, 30
|
||||
dialog = 0, 0, 200
|
||||
altdialog = 0, 0, 200
|
||||
note = 100, 100, 0
|
||||
hidden = 100, 100, 100
|
||||
shortcode = 0, 100, 0
|
||||
keyword = 200, 50, 50
|
||||
value = 50, 150, 50
|
||||
tag = 0, 100, 0
|
||||
value = 0, 0, 200
|
||||
optional = 0, 100, 0
|
||||
spellcheckline = 200, 0, 0
|
||||
errorline = 0, 150, 0
|
||||
replacetag = 0, 150, 0
|
||||
modifier = 150, 110, 30
|
||||
spellcheckline = 200, 50, 50
|
||||
errorline = 0, 100, 0
|
||||
replacetag = 0, 100, 0
|
||||
modifier = 0, 100, 0
|
||||
texthighlight = 150, 150, 0, 96
|
||||
|
||||
44
novelwriter/assets/syntax/dracula.conf
Normal file
44
novelwriter/assets/syntax/dracula.conf
Normal file
@@ -0,0 +1,44 @@
|
||||
[Main]
|
||||
name = Dracula
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
credit = Zeno Rocha
|
||||
url = https://draculatheme.com
|
||||
license = MIT
|
||||
licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 282a36 : 40, 42, 54
|
||||
# Foreground = f8f8f2 : 248, 248, 242
|
||||
# Comment = 6272a4 : 98, 114, 164
|
||||
# Cyan = 8be9fd : 139, 233, 253
|
||||
# Green = 50fa7b : 80, 250, 123
|
||||
# Orange = ffb86c : 255, 184, 108
|
||||
# Pink = ff79c6 : 255, 121, 198
|
||||
# Purple = bd93f9 : 189, 147, 249
|
||||
# Red = ff5555 : 255, 85, 85
|
||||
# Yellow = f1fa8c : 241, 250, 140
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
# See: https://spec.draculatheme.com/
|
||||
background = 40, 42, 54
|
||||
text = 248, 248, 242
|
||||
link = 255, 121, 198
|
||||
headertext = 189, 147, 249
|
||||
headertag = 189, 147, 249, 160
|
||||
emphasis = 255, 184, 108
|
||||
dialog = 80, 250, 123
|
||||
altdialog = 241, 250, 140
|
||||
note = 255, 204, 233
|
||||
hidden = 98, 114, 164
|
||||
shortcode = 139, 233, 253
|
||||
keyword = 255, 121, 198
|
||||
tag = 255, 184, 108
|
||||
value = 255, 184, 108
|
||||
optional = 80, 250, 123
|
||||
spellcheckline = 255, 85, 85
|
||||
errorline = 80, 250, 123
|
||||
replacetag = 241, 250, 140
|
||||
modifier = 139, 233, 253
|
||||
texthighlight = 241, 250, 140, 96
|
||||
@@ -11,14 +11,15 @@ background = 54, 54, 54
|
||||
text = 200, 200, 200
|
||||
link = 200, 200, 200
|
||||
headertext = 225, 225, 225
|
||||
headertag = 225, 225, 225
|
||||
headertag = 225, 225, 225, 160
|
||||
emphasis = 200, 200, 200
|
||||
straightquotes = 200, 200, 200
|
||||
doublequotes = 200, 200, 200
|
||||
singlequotes = 200, 200, 200
|
||||
dialog = 200, 200, 200
|
||||
altdialog = 200, 200, 200
|
||||
note = 200, 200, 200
|
||||
hidden = 150, 150, 150
|
||||
shortcode = 225, 225, 225
|
||||
keyword = 225, 225, 225
|
||||
tag = 200, 200, 200
|
||||
value = 200, 200, 200
|
||||
optional = 225, 225, 225
|
||||
spellcheckline = 200, 46, 0
|
||||
|
||||
@@ -11,14 +11,15 @@ background = 255, 255, 255
|
||||
text = 20, 20, 20
|
||||
link = 20, 20, 20
|
||||
headertext = 0, 0, 0
|
||||
headertag = 0, 0, 0
|
||||
headertag = 0, 0, 0, 160
|
||||
emphasis = 20, 20, 20
|
||||
straightquotes = 20, 20, 20
|
||||
doublequotes = 20, 20, 20
|
||||
singlequotes = 20, 20, 20
|
||||
dialog = 20, 20, 20
|
||||
altdialog = 20, 20, 20
|
||||
note = 20, 20, 20
|
||||
hidden = 100, 100, 100
|
||||
shortcode = 0, 0, 0
|
||||
keyword = 0, 0, 0
|
||||
tag = 20, 20, 20
|
||||
value = 20, 20, 20
|
||||
optional = 0, 0, 0
|
||||
spellcheckline = 200, 0, 0
|
||||
|
||||
@@ -31,18 +31,19 @@ background = 251, 251, 251
|
||||
text = 64, 63, 82
|
||||
link = 40, 142, 215
|
||||
headertext = 40, 142, 215
|
||||
headertag = 40, 142, 215
|
||||
headertag = 40, 142, 215, 160
|
||||
emphasis = 224, 175, 5
|
||||
straightquotes = 222, 61, 58
|
||||
doublequotes = 8, 145, 106
|
||||
singlequotes = 255, 235, 149
|
||||
dialog = 8, 145, 106
|
||||
altdialog = 218, 170, 1
|
||||
note = 128, 118, 75
|
||||
hidden = 152, 159, 177
|
||||
shortcode = 40, 142, 215
|
||||
keyword = 222, 61, 58
|
||||
value = 150, 74, 193
|
||||
tag = 150, 74, 193
|
||||
value = 224, 175, 5
|
||||
optional = 40, 142, 215
|
||||
spellcheckline = 222, 61, 58
|
||||
errorline = 8, 145, 106
|
||||
replacetag = 42, 162, 152
|
||||
modifier = 224, 175, 5
|
||||
modifier = 8, 145, 106
|
||||
texthighlight = 218, 170, 1, 96
|
||||
|
||||
@@ -31,18 +31,19 @@ background = 1, 22, 39
|
||||
text = 214, 222, 235
|
||||
link = 130, 170, 255
|
||||
headertext = 130, 170, 255
|
||||
headertag = 130, 170, 255
|
||||
headertag = 130, 170, 255, 160
|
||||
emphasis = 236, 196, 141
|
||||
straightquotes = 247, 140, 108
|
||||
doublequotes = 173, 219, 103
|
||||
singlequotes = 255, 235, 149
|
||||
dialog = 173, 219, 103
|
||||
altdialog = 255, 235, 149
|
||||
note = 255, 249, 202
|
||||
hidden = 99, 119, 119
|
||||
shortcode = 130, 170, 255
|
||||
keyword = 247, 140, 108
|
||||
value = 199, 146, 234
|
||||
tag = 199, 146, 234
|
||||
value = 255, 235, 149
|
||||
optional = 130, 170, 255
|
||||
spellcheckline = 247, 140, 108
|
||||
errorline = 173, 219, 103
|
||||
replacetag = 127, 219, 202
|
||||
modifier = 236, 196, 141
|
||||
modifier = 173, 219, 103
|
||||
texthighlight = 255, 235, 149, 96
|
||||
|
||||
42
novelwriter/assets/syntax/snazzy.conf
Normal file
42
novelwriter/assets/syntax/snazzy.conf
Normal file
@@ -0,0 +1,42 @@
|
||||
[Main]
|
||||
name = Snazzy Light
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
credit = Florian Reuschel (color theme)
|
||||
url = https://github.com/loilo/vscode-snazzy-light
|
||||
license = MIT License
|
||||
licenseurl = https://github.com/loilo/vscode-snazzy-light/blob/master/LICENSE
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = fafbfc : 250, 251, 252
|
||||
# Foreground = 565869 : 86, 88, 105
|
||||
# Comment = 9194a2 : 145, 148, 162
|
||||
# Yellow = cf9c00 : 207, 156, 0
|
||||
# Red = ff5c57 : 255, 92, 87
|
||||
# Pink = f767bb : 247, 103, 187
|
||||
# Blue = 09a1ed : 9, 161, 237
|
||||
# Cyan = 13bbb7 : 19, 187, 183
|
||||
# Green = 2dae58 : 45, 174, 88
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 250, 251, 252
|
||||
text = 86, 88, 105
|
||||
link = 9, 161, 237
|
||||
headertext = 45, 174, 88
|
||||
headertag = 45, 174, 88, 160
|
||||
emphasis = 19, 187, 183
|
||||
dialog = 207, 156, 0
|
||||
altdialog = 207, 156, 0
|
||||
note = 120, 187, 185
|
||||
hidden = 145, 148, 162
|
||||
shortcode = 247, 103, 187
|
||||
keyword = 9, 161, 237
|
||||
tag = 45, 174, 88
|
||||
value = 9, 161, 237
|
||||
optional = 207, 156, 0
|
||||
spellcheckline = 255, 92, 87
|
||||
errorline = 45, 174, 88
|
||||
replacetag = 19, 187, 183
|
||||
modifier = 247, 103, 187
|
||||
texthighlight = 207, 156, 0, 96
|
||||
@@ -13,12 +13,13 @@ link = 38, 139, 210
|
||||
headertext = 147, 161, 161
|
||||
headertag = 42, 161, 152
|
||||
emphasis = 38, 139, 210
|
||||
straightquotes = 211, 54, 130
|
||||
doublequotes = 42, 161, 152
|
||||
singlequotes = 42, 161, 152
|
||||
dialog = 42, 161, 152
|
||||
altdialog = 42, 161, 152
|
||||
note = 101, 161, 156
|
||||
hidden = 147, 161, 161
|
||||
shortcode = 147, 161, 161
|
||||
keyword = 133, 153, 0
|
||||
tag = 203, 75, 22
|
||||
value = 203, 75, 22
|
||||
optional = 147, 161, 161
|
||||
spellcheckline = 203, 75, 22
|
||||
|
||||
@@ -13,12 +13,13 @@ link = 38, 139, 210
|
||||
headertext = 88, 110, 117
|
||||
headertag = 42, 161, 152
|
||||
emphasis = 38, 139, 210
|
||||
straightquotes = 211, 54, 130
|
||||
doublequotes = 42, 161, 152
|
||||
singlequotes = 42, 161, 152
|
||||
dialog = 42, 161, 152
|
||||
altdialog = 42, 161, 152
|
||||
note = 27, 102, 96
|
||||
hidden = 88, 110, 117
|
||||
shortcode = 88, 110, 117
|
||||
keyword = 133, 153, 0
|
||||
tag = 203, 75, 22
|
||||
value = 203, 75, 22
|
||||
optional = 88, 110, 117
|
||||
spellcheckline = 203, 75, 22
|
||||
|
||||
@@ -2,22 +2,38 @@
|
||||
name = Tango
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 30302f : 48, 48, 47
|
||||
# Foreground = eeeeec : 238, 238, 236
|
||||
# Comment = 8f8f8d : 143, 143, 141
|
||||
# Red = ef2929 : 239, 41, 41
|
||||
# Orange = c4a000 : 196, 160, 0
|
||||
# Yellow = fce94f : 252, 233, 79
|
||||
# Green = 8ae234 : 138, 226, 52
|
||||
# Cyan = 34e2e2 : 52, 226, 226
|
||||
# Blue = 3465a4 : 114, 159, 207
|
||||
# Purple = ad7fa8 : 173, 127, 168
|
||||
##
|
||||
|
||||
[Syntax]
|
||||
background = 48, 48, 47
|
||||
text = 238, 238, 236
|
||||
link = 115, 159, 207
|
||||
headertext = 115, 159, 207
|
||||
headertag = 52, 101, 164
|
||||
link = 114, 159, 207
|
||||
headertext = 114, 159, 207
|
||||
headertag = 114, 159, 207, 160
|
||||
emphasis = 196, 160, 0
|
||||
straightquotes = 239, 41, 41
|
||||
doublequotes = 138, 226, 52
|
||||
singlequotes = 252, 233, 79
|
||||
dialog = 138, 226, 52
|
||||
altdialog = 252, 233, 79
|
||||
note = 252, 242, 164
|
||||
hidden = 143, 143, 141
|
||||
shortcode = 115, 159, 207
|
||||
shortcode = 114, 159, 207
|
||||
keyword = 239, 41, 41
|
||||
value = 173, 127, 168
|
||||
optional = 115, 159, 207
|
||||
tag = 173, 127, 168
|
||||
value = 239, 41, 41
|
||||
optional = 114, 159, 207
|
||||
spellcheckline = 239, 41, 41
|
||||
errorline = 138, 226, 52
|
||||
replacetag = 51, 226, 226
|
||||
modifier = 196, 160, 0
|
||||
replacetag = 52, 226, 226
|
||||
modifier = 114, 159, 207
|
||||
texthighlight = 252, 233, 79, 96
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 255, 255, 255
|
||||
text = 77, 77, 76
|
||||
link = 66, 113, 174
|
||||
headertext = 66, 113, 174
|
||||
headertag = 66, 113, 174
|
||||
headertag = 66, 113, 174, 160
|
||||
emphasis = 245, 135, 31
|
||||
straightquotes = 240, 40, 41
|
||||
doublequotes = 113, 140, 0
|
||||
singlequotes = 234, 183, 0
|
||||
dialog = 113, 140, 0
|
||||
altdialog = 234, 183, 0
|
||||
note = 115, 90, 0
|
||||
hidden = 142, 144, 140
|
||||
shortcode = 66, 113, 174
|
||||
keyword = 240, 40, 41
|
||||
value = 137, 89, 168
|
||||
tag = 137, 89, 168
|
||||
value = 234, 183, 0
|
||||
optional = 66, 113, 174
|
||||
spellcheckline = 240, 40, 41
|
||||
errorline = 113, 140, 0
|
||||
|
||||
@@ -29,17 +29,18 @@ licenseurl = https://github.com/chriskempson/tomorrow-theme/blob/master/LICENSE.
|
||||
[Syntax]
|
||||
background = 29, 31, 33
|
||||
text = 197, 200, 198
|
||||
link = 129, 162, 190
|
||||
link = 197, 200, 198, 160
|
||||
headertext = 129, 162, 190
|
||||
headertag = 129, 162, 190
|
||||
headertag = 94, 119, 139
|
||||
emphasis = 222, 147, 95
|
||||
straightquotes = 204, 102, 102
|
||||
doublequotes = 181, 189, 104
|
||||
singlequotes = 240, 198, 116
|
||||
dialog = 181, 189, 104
|
||||
altdialog = 240, 198, 116
|
||||
note = 240, 219, 178
|
||||
hidden = 150, 152, 150
|
||||
shortcode = 129, 162, 190
|
||||
keyword = 204, 102, 102
|
||||
value = 178, 148, 187
|
||||
tag = 178, 148, 187
|
||||
value = 240, 198, 116
|
||||
optional = 129, 162, 190
|
||||
spellcheckline = 204, 102, 102
|
||||
errorline = 181, 189, 104
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 0, 36, 81
|
||||
text = 255, 255, 255
|
||||
link = 187, 218, 255
|
||||
headertext = 187, 218, 255
|
||||
headertag = 187, 218, 255
|
||||
headertag = 187, 218, 255, 160
|
||||
emphasis = 255, 197, 143
|
||||
straightquotes = 255, 157, 164
|
||||
doublequotes = 209, 241, 169
|
||||
singlequotes = 255, 238, 173
|
||||
dialog = 209, 241, 169
|
||||
altdialog = 255, 238, 173
|
||||
note = 255, 247, 214
|
||||
hidden = 114, 133, 183
|
||||
shortcode = 187, 218, 255
|
||||
keyword = 255, 157, 164
|
||||
value = 235, 187, 255
|
||||
tag = 235, 187, 255
|
||||
value = 255, 238, 173
|
||||
optional = 187, 218, 255
|
||||
spellcheckline = 255, 157, 164
|
||||
errorline = 209, 241, 169
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 0, 0, 0
|
||||
text = 234, 234, 234
|
||||
link = 122, 166, 218
|
||||
headertext = 122, 166, 218
|
||||
headertag = 122, 166, 218
|
||||
headertag = 122, 166, 218, 160
|
||||
emphasis = 231, 140, 69
|
||||
straightquotes = 213, 78, 83
|
||||
doublequotes = 185, 202, 74
|
||||
singlequotes = 231, 197, 71
|
||||
dialog = 185, 202, 74
|
||||
altdialog = 231, 197, 71
|
||||
note = 231, 214, 150
|
||||
hidden = 150, 152, 150
|
||||
shortcode = 122, 166, 218
|
||||
keyword = 213, 78, 83
|
||||
value = 195, 151, 216
|
||||
tag = 195, 151, 216
|
||||
value = 231, 197, 71
|
||||
optional = 122, 166, 218
|
||||
spellcheckline = 213, 78, 83
|
||||
errorline = 185, 202, 74
|
||||
|
||||
@@ -31,15 +31,16 @@ background = 45, 45, 45
|
||||
text = 204, 204, 204
|
||||
link = 102, 153, 204
|
||||
headertext = 102, 153, 204
|
||||
headertag = 102, 153, 204
|
||||
headertag = 102, 153, 204, 160
|
||||
emphasis = 249, 145, 57
|
||||
straightquotes = 242, 119, 122
|
||||
doublequotes = 153, 204, 153
|
||||
singlequotes = 255, 204, 102
|
||||
dialog = 153, 204, 153
|
||||
altdialog = 255, 204, 102
|
||||
note = 255, 230, 179
|
||||
hidden = 153, 153, 153
|
||||
shortcode = 102, 153, 204
|
||||
keyword = 242, 119, 122
|
||||
value = 204, 153, 204
|
||||
tag = 204, 153, 204
|
||||
value = 255, 204, 102
|
||||
optional = 102, 153, 204
|
||||
spellcheckline = 242, 119, 122
|
||||
errorline = 153, 204, 153
|
||||
|
||||
@@ -60,7 +60,10 @@ more contributions are listed on the project's <a href="https://crowdin.com/proj
|
||||
• <a href="https://github.com/stephenhutchings/typicons.font">Typicons</a> icons by Stephen Hutchings (CC BY-SA 4.0)<br>
|
||||
• <a href="https://github.com/chriskempson/base16">Tomorrow</a> syntax themes by Chris Kempson (MIT License)<br>
|
||||
• <a href="https://github.com/sdras/night-owl-vscode-theme">Owl</a> syntax themes by Sarah Drasner (MIT License)<br>
|
||||
• <a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)
|
||||
• <a href="https://github.com/altercation/solarized">Solarized</a> themes by Ethan Schoonover (MIT License)<br>
|
||||
• <a href="https://github.com/alemvigh">Cyberpunk Night</a> theme by Anders Lemvigh (CC BY-SA 4.0)<br>
|
||||
• <a href="https://draculatheme.com">Dracula</a> theme by Zeno Rocha (MIT License)<br>
|
||||
• <a href="https://github.com/loilo/vscode-snazzy-light">Snazzy Light</a> theme by Florian Reuschel (MIT License)
|
||||
</p>
|
||||
|
||||
<h3>Fonts</h3>
|
||||
|
||||
@@ -24,6 +24,8 @@ link = 77, 77, 255
|
||||
linkvisited = 50, 0, 80
|
||||
|
||||
[GUI]
|
||||
helptext = 97, 97, 97
|
||||
errortext = 255, 77, 77
|
||||
statusnone = 50, 50, 50
|
||||
statussaved = 77, 255, 77
|
||||
statusunsaved = 255, 77, 77
|
||||
|
||||
@@ -26,6 +26,7 @@ linkvisited = 102, 153, 204
|
||||
|
||||
[GUI]
|
||||
helptext = 164, 164, 164
|
||||
errortext = 255, 164, 164
|
||||
statusnone = 150, 152, 150
|
||||
statussaved = 39, 135, 78
|
||||
statusunsaved = 138, 32, 32
|
||||
|
||||
@@ -26,6 +26,7 @@ linkvisited = 66, 113, 174
|
||||
|
||||
[GUI]
|
||||
helptext = 92, 92, 92
|
||||
errortext = 255, 92, 92
|
||||
statusnone = 120, 120, 120
|
||||
statussaved = 200, 15, 39
|
||||
statusunsaved = 2, 133, 37
|
||||
|
||||
47
novelwriter/assets/themes/dracula.conf
Normal file
47
novelwriter/assets/themes/dracula.conf
Normal file
@@ -0,0 +1,47 @@
|
||||
[Main]
|
||||
name = Dracula
|
||||
description = A dark theme with bright colours
|
||||
author = Veronica Berglyd Olsen (adaptation)
|
||||
credit = Zeno Rocha
|
||||
url = https://draculatheme.com
|
||||
license = MIT
|
||||
licenseurl = https://github.com/dracula/dracula-theme/blob/main/LICENSE
|
||||
icontheme = typicons_dark
|
||||
|
||||
##
|
||||
# Colours:
|
||||
# Background = 282a36 : 40, 42, 54
|
||||
# Foreground = f8f8f2 : 248, 248, 242
|
||||
# Current Line = 44475A : 68, 71, 90
|
||||
# Comment = 6272a4 : 98, 114, 164
|
||||
# Cyan = 8be9fd : 139, 233, 253
|
||||
# Green = 50fa7b : 80, 250, 123
|
||||
# Orange = ffb86c : 255, 184, 108
|
||||
# Pink = ff79c6 : 255, 121, 198
|
||||
# Purple = bd93f9 : 189, 147, 249
|
||||
# Red = ff5555 : 255, 85, 85
|
||||
# Yellow = f1fa8c : 241, 250, 140
|
||||
##
|
||||
|
||||
[Palette]
|
||||
window = 68, 71, 90
|
||||
windowtext = 248, 248, 242
|
||||
base = 40, 42, 54
|
||||
alternatebase = 51, 54, 69
|
||||
text = 248, 248, 242
|
||||
tooltipbase = 241, 250, 140
|
||||
tooltiptext = 40, 42, 54
|
||||
button = 80, 83, 105
|
||||
buttontext = 248, 248, 242
|
||||
brighttext = 68, 71, 90
|
||||
highlight = 166, 129, 218
|
||||
highlightedtext = 248, 248, 242
|
||||
link = 139, 233, 253
|
||||
linkvisited = 139, 233, 253
|
||||
|
||||
[GUI]
|
||||
helptext = 204, 172, 249
|
||||
errortext = 255, 85, 85
|
||||
statusnone = 98, 114, 164
|
||||
statussaved = 80, 250, 123
|
||||
statusunsaved = 255, 85, 85
|
||||
@@ -25,6 +25,7 @@ linkvisited = 38, 139, 210
|
||||
|
||||
[GUI]
|
||||
helptext = 166, 161, 149
|
||||
errortext = 255, 161, 149
|
||||
statusnone = 88, 110, 117
|
||||
statussaved = 42, 161, 152
|
||||
statusunsaved = 203, 75, 22
|
||||
|
||||
@@ -25,6 +25,7 @@ linkvisited = 38, 139, 210
|
||||
|
||||
[GUI]
|
||||
helptext = 78, 91, 95
|
||||
errortext = 255, 91, 95
|
||||
statusnone = 88, 110, 117
|
||||
statussaved = 42, 161, 152
|
||||
statusunsaved = 203, 75, 22
|
||||
|
||||
@@ -24,30 +24,32 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
import unicodedata
|
||||
import uuid
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Literal
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from configparser import ConfigParser
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Literal, TypeVar
|
||||
from urllib.parse import urljoin
|
||||
from urllib.request import pathname2url
|
||||
|
||||
from PyQt5.QtGui import QColor, QDesktopServices
|
||||
from PyQt5.QtCore import QCoreApplication, QUrl
|
||||
from PyQt5.QtGui import QColor, QDesktopServices, QFont, QFontInfo
|
||||
|
||||
from novelwriter.enum import nwItemClass, nwItemType, nwItemLayout
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.constants import nwConst, nwLabels, nwUnicode, trConst
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from typing import TypeGuard # Requires Python 3.10
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_Type = TypeVar("_Type")
|
||||
|
||||
|
||||
##
|
||||
# Checker Functions
|
||||
@@ -172,6 +174,11 @@ def isItemLayout(value: Any) -> TypeGuard[str]:
|
||||
return isinstance(value, str) and value in nwItemLayout.__members__
|
||||
|
||||
|
||||
def isListInstance(data: Any, check: type[_Type]) -> TypeGuard[list[_Type]]:
|
||||
"""Check that all items of a list is of a given type."""
|
||||
return isinstance(data, list) and all(isinstance(item, check) for item in data)
|
||||
|
||||
|
||||
def hexToInt(value: Any, default: int = 0) -> int:
|
||||
"""Convert a hex string to an integer."""
|
||||
if isinstance(value, str):
|
||||
@@ -272,6 +279,13 @@ def simplified(text: str) -> str:
|
||||
return " ".join(str(text).strip().split())
|
||||
|
||||
|
||||
def elide(text: str, length: int) -> str:
|
||||
"""Elide a piece of text to a maximum length."""
|
||||
if len(text) > (cut := max(4, length)):
|
||||
return f"{text[:cut-4].rstrip()} ..."
|
||||
return text
|
||||
|
||||
|
||||
def yesNo(value: int | bool | None) -> Literal["yes", "no"]:
|
||||
"""Convert a boolean evaluated variable to a yes or no."""
|
||||
return "yes" if value else "no"
|
||||
@@ -387,6 +401,16 @@ def cssCol(col: QColor, alpha: int | None = None) -> str:
|
||||
return f"rgba({col.red()}, {col.green()}, {col.blue()}, {alpha or col.alpha()})"
|
||||
|
||||
|
||||
def describeFont(font: QFont) -> str:
|
||||
"""Describe a font in a way that can be displayed on the GUI."""
|
||||
if isinstance(font, QFont):
|
||||
info = QFontInfo(font)
|
||||
family = info.family()
|
||||
styles = [v for v in info.styleName().split() if v not in family]
|
||||
return " ".join([f"{info.pointSize()} pt", family] + styles)
|
||||
return "Error"
|
||||
|
||||
|
||||
##
|
||||
# Encoder Functions
|
||||
##
|
||||
@@ -589,5 +613,3 @@ class NWConfigParser(ConfigParser):
|
||||
for i in range(min(len(data), len(result))):
|
||||
result[i] = checkInt(data[i].strip(), result[i])
|
||||
return result
|
||||
|
||||
# END Class NWConfigParser
|
||||
|
||||
@@ -24,24 +24,24 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import json
|
||||
import logging
|
||||
import sys
|
||||
|
||||
from time import time
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtGui import QFontDatabase
|
||||
from PyQt5.QtCore import (
|
||||
PYQT_VERSION, PYQT_VERSION_STR, QT_VERSION, QT_VERSION_STR, QLibraryInfo,
|
||||
QLocale, QStandardPaths, QSysInfo, QTranslator
|
||||
)
|
||||
from PyQt5.QtGui import QFont, QFontDatabase
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.common import NWConfigParser, checkInt, checkPath, formatTimeStamp
|
||||
from novelwriter.common import NWConfigParser, checkInt, checkPath, describeFont, formatTimeStamp
|
||||
from novelwriter.constants import nwFiles, nwUnicode
|
||||
from novelwriter.error import formatException, logException
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -106,15 +106,15 @@ class Config:
|
||||
self._recentObj = RecentProjects(self)
|
||||
|
||||
# General GUI Settings
|
||||
self.guiLocale = self._qLocale.name()
|
||||
self.guiTheme = "default" # GUI theme
|
||||
self.guiSyntax = "default_light" # Syntax theme
|
||||
self.guiFont = "" # Defaults to system default font in theme class
|
||||
self.guiFontSize = 11 # Is overridden if system default is loaded
|
||||
self.guiScale = 1.0 # Set automatically by Theme class
|
||||
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
||||
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
||||
self.lastNotes = "0x0" # The latest release notes that have been shown
|
||||
self.guiLocale = self._qLocale.name()
|
||||
self.guiTheme = "default" # GUI theme
|
||||
self.guiSyntax = "default_light" # Syntax theme
|
||||
self.guiFont = QFont() # Main GUI font
|
||||
self.guiScale = 1.0 # Set automatically by Theme class
|
||||
self.hideVScroll = False # Hide vertical scroll bars on main widgets
|
||||
self.hideHScroll = False # Hide horizontal scroll bars on main widgets
|
||||
self.lastNotes = "0x0" # The latest release notes that have been shown
|
||||
self.nativeFont = True # Use native font dialog
|
||||
|
||||
# Size Settings
|
||||
self._mainWinSize = [1200, 650] # Last size of the main GUI window
|
||||
@@ -132,40 +132,42 @@ class Config:
|
||||
self.askBeforeBackup = True # Flag for asking before running automatic backup
|
||||
|
||||
# Text Editor Settings
|
||||
self.textFont = "" # Editor font
|
||||
self.textSize = 12 # Editor font size
|
||||
self.textWidth = 700 # Editor text width
|
||||
self.textMargin = 40 # Editor/viewer text margin
|
||||
self.tabWidth = 40 # Editor tabulator width
|
||||
self.textFont = QFont() # Editor font
|
||||
self.textWidth = 700 # Editor text width
|
||||
self.textMargin = 40 # Editor/viewer text margin
|
||||
self.tabWidth = 40 # Editor tabulator width
|
||||
|
||||
self.focusWidth = 800 # Focus Mode text width
|
||||
self.hideFocusFooter = False # Hide document footer in Focus Mode
|
||||
self.showFullPath = True # Show full document path in editor header
|
||||
self.autoSelect = True # Auto-select word when applying format with no selection
|
||||
self.focusWidth = 800 # Focus Mode text width
|
||||
self.hideFocusFooter = False # Hide document footer in Focus Mode
|
||||
self.showFullPath = True # Show full document path in editor header
|
||||
self.autoSelect = True # Auto-select word when applying format with no selection
|
||||
|
||||
self.doJustify = False # Justify text
|
||||
self.showTabsNSpaces = False # Show tabs and spaces in editor
|
||||
self.showLineEndings = False # Show line endings in editor
|
||||
self.showMultiSpaces = True # Highlight multiple spaces in the text
|
||||
self.doJustify = False # Justify text
|
||||
self.showTabsNSpaces = False # Show tabs and spaces in editor
|
||||
self.showLineEndings = False # Show line endings in editor
|
||||
self.showMultiSpaces = True # Highlight multiple spaces in the text
|
||||
|
||||
self.doReplace = True # Enable auto-replace as you type
|
||||
self.doReplaceSQuote = True # Smart single quotes
|
||||
self.doReplaceDQuote = True # Smart double quotes
|
||||
self.doReplaceDash = True # Replace multiple hyphens with dashes
|
||||
self.doReplaceDots = True # Replace three dots with ellipsis
|
||||
self.doReplace = True # Enable auto-replace as you type
|
||||
self.doReplaceSQuote = True # Smart single quotes
|
||||
self.doReplaceDQuote = True # Smart double quotes
|
||||
self.doReplaceDash = True # Replace multiple hyphens with dashes
|
||||
self.doReplaceDots = True # Replace three dots with ellipsis
|
||||
|
||||
self.autoScroll = False # Typewriter-like scrolling
|
||||
self.autoScrollPos = 30 # Start point for typewriter-like scrolling
|
||||
self.scrollPastEnd = True # Scroll past end of document, and centre cursor
|
||||
self.autoScroll = False # Typewriter-like scrolling
|
||||
self.autoScrollPos = 30 # Start point for typewriter-like scrolling
|
||||
self.scrollPastEnd = True # Scroll past end of document, and centre cursor
|
||||
|
||||
self.highlightQuotes = True # Highlight text in quotes
|
||||
self.allowOpenSQuote = False # Allow open-ended single quotes
|
||||
self.allowOpenDQuote = True # Allow open-ended double quotes
|
||||
self.highlightEmph = True # Add colour to text emphasis
|
||||
self.dialogStyle = 2 # Quote type to use for dialogue
|
||||
self.allowOpenDial = True # Allow open-ended dialogue quotes
|
||||
self.narratorBreak = "" # Symbol to use for narrator break
|
||||
self.dialogLine = "" # Symbol to use for dialogue line
|
||||
self.altDialogOpen = "" # Alternative dialog symbol, open
|
||||
self.altDialogClose = "" # Alternative dialog symbol, close
|
||||
self.highlightEmph = True # Add colour to text emphasis
|
||||
|
||||
self.stopWhenIdle = True # Stop the status bar clock when the user is idle
|
||||
self.userIdleTime = 300 # Time of inactivity to consider user idle
|
||||
self.incNotesWCount = True # The status bar word count includes notes
|
||||
self.stopWhenIdle = True # Stop the status bar clock when the user is idle
|
||||
self.userIdleTime = 300 # Time of inactivity to consider user idle
|
||||
self.incNotesWCount = True # The status bar word count includes notes
|
||||
|
||||
# User-Selected Symbol Settings
|
||||
self.fmtApostrophe = nwUnicode.U_RSQUO
|
||||
@@ -359,23 +361,53 @@ class Config:
|
||||
self._backupPath = checkPath(path, self._backPath)
|
||||
return
|
||||
|
||||
def setTextFont(self, family: str | None, pointSize: int = 12) -> None:
|
||||
def setGuiFont(self, value: QFont | str | None) -> None:
|
||||
"""Update the GUI's font style from settings."""
|
||||
if isinstance(value, QFont):
|
||||
self.guiFont = value
|
||||
elif value and isinstance(value, str):
|
||||
self.guiFont = QFont()
|
||||
self.guiFont.fromString(value)
|
||||
else:
|
||||
font = QFont()
|
||||
fontDB = QFontDatabase()
|
||||
if self.osWindows and "Arial" in fontDB.families():
|
||||
# On Windows we default to Arial if possible
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(10)
|
||||
else:
|
||||
font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
||||
self.guiFont = font
|
||||
logger.debug("GUI font set to: %s", describeFont(font))
|
||||
|
||||
QApplication.setFont(self.guiFont)
|
||||
|
||||
return
|
||||
|
||||
def setTextFont(self, value: QFont | str | None) -> None:
|
||||
"""Set the text font if it exists. If it doesn't, or is None,
|
||||
set to default font.
|
||||
"""
|
||||
fontDB = QFontDatabase()
|
||||
fontFam = fontDB.families()
|
||||
self.textSize = pointSize
|
||||
if family is None or family not in fontFam:
|
||||
logger.warning("Unknown font '%s'", family)
|
||||
if self.osWindows and "Arial" in fontFam:
|
||||
self.textFont = "Arial"
|
||||
elif self.osDarwin and "Helvetica" in fontFam:
|
||||
self.textFont = "Helvetica"
|
||||
else:
|
||||
self.textFont = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont).family()
|
||||
if isinstance(value, QFont):
|
||||
self.textFont = value
|
||||
elif value and isinstance(value, str):
|
||||
self.textFont = QFont()
|
||||
self.textFont.fromString(value)
|
||||
else:
|
||||
self.textFont = family
|
||||
fontDB = QFontDatabase()
|
||||
fontFam = fontDB.families()
|
||||
if self.osWindows and "Arial" in fontFam:
|
||||
font = QFont()
|
||||
font.setFamily("Arial")
|
||||
font.setPointSize(12)
|
||||
elif self.osDarwin and "Helvetica" in fontFam:
|
||||
font = QFont()
|
||||
font.setFamily("Helvetica")
|
||||
font.setPointSize(12)
|
||||
else:
|
||||
font = fontDB.systemFont(QFontDatabase.SystemFont.GeneralFont)
|
||||
self.textFont = font
|
||||
logger.debug("Text font set to: %s", describeFont(font))
|
||||
return
|
||||
|
||||
##
|
||||
@@ -499,12 +531,6 @@ class Config:
|
||||
(self._dataPath / "syntax").mkdir(exist_ok=True)
|
||||
(self._dataPath / "themes").mkdir(exist_ok=True)
|
||||
|
||||
# Check if config file exists, and load it. If not, we save defaults
|
||||
if (self._confPath / nwFiles.CONF_FILE).is_file():
|
||||
self.loadConfig()
|
||||
else:
|
||||
self.saveConfig()
|
||||
|
||||
self._recentObj.loadCache()
|
||||
self._checkOptionalPackages()
|
||||
|
||||
@@ -545,6 +571,14 @@ class Config:
|
||||
|
||||
conf = NWConfigParser()
|
||||
cnfPath = self._confPath / nwFiles.CONF_FILE
|
||||
|
||||
if not cnfPath.exists():
|
||||
# Initial file, so we just create one from defaults
|
||||
self.setGuiFont(None)
|
||||
self.setTextFont(None)
|
||||
self.saveConfig()
|
||||
return True
|
||||
|
||||
try:
|
||||
with open(cnfPath, mode="r", encoding="utf-8") as inFile:
|
||||
conf.read_file(inFile)
|
||||
@@ -558,14 +592,14 @@ class Config:
|
||||
|
||||
# Main
|
||||
sec = "Main"
|
||||
self.setGuiFont(conf.rdStr(sec, "font", ""))
|
||||
self.guiTheme = conf.rdStr(sec, "theme", self.guiTheme)
|
||||
self.guiSyntax = conf.rdStr(sec, "syntax", self.guiSyntax)
|
||||
self.guiFont = conf.rdStr(sec, "font", self.guiFont)
|
||||
self.guiFontSize = conf.rdInt(sec, "fontsize", self.guiFontSize)
|
||||
self.guiLocale = conf.rdStr(sec, "localisation", self.guiLocale)
|
||||
self.hideVScroll = conf.rdBool(sec, "hidevscroll", self.hideVScroll)
|
||||
self.hideHScroll = conf.rdBool(sec, "hidehscroll", self.hideHScroll)
|
||||
self.lastNotes = conf.rdStr(sec, "lastnotes", self.lastNotes)
|
||||
self.nativeFont = conf.rdBool(sec, "nativefont", self.nativeFont)
|
||||
self._lastPath = conf.rdPath(sec, "lastpath", self._lastPath)
|
||||
|
||||
# Sizes
|
||||
@@ -588,8 +622,7 @@ class Config:
|
||||
|
||||
# Editor
|
||||
sec = "Editor"
|
||||
self.textFont = conf.rdStr(sec, "textfont", self.textFont)
|
||||
self.textSize = conf.rdInt(sec, "textsize", self.textSize)
|
||||
self.setTextFont(conf.rdStr(sec, "textfont", ""))
|
||||
self.textWidth = conf.rdInt(sec, "width", self.textWidth)
|
||||
self.textMargin = conf.rdInt(sec, "margin", self.textMargin)
|
||||
self.tabWidth = conf.rdInt(sec, "tabwidth", self.tabWidth)
|
||||
@@ -618,9 +651,12 @@ class Config:
|
||||
self.showMultiSpaces = conf.rdBool(sec, "showmultispaces", self.showMultiSpaces)
|
||||
self.incNotesWCount = conf.rdBool(sec, "incnoteswcount", self.incNotesWCount)
|
||||
self.showFullPath = conf.rdBool(sec, "showfullpath", self.showFullPath)
|
||||
self.highlightQuotes = conf.rdBool(sec, "highlightquotes", self.highlightQuotes)
|
||||
self.allowOpenSQuote = conf.rdBool(sec, "allowopensquote", self.allowOpenSQuote)
|
||||
self.allowOpenDQuote = conf.rdBool(sec, "allowopendquote", self.allowOpenDQuote)
|
||||
self.dialogStyle = conf.rdInt(sec, "dialogstyle", self.dialogStyle)
|
||||
self.allowOpenDial = conf.rdBool(sec, "allowopendial", self.allowOpenDial)
|
||||
self.narratorBreak = conf.rdStr(sec, "narratorbreak", self.narratorBreak)
|
||||
self.altDialogOpen = conf.rdStr(sec, "altdialogopen", self.altDialogOpen)
|
||||
self.altDialogClose = conf.rdStr(sec, "altdialogclose", self.altDialogClose)
|
||||
self.dialogLine = conf.rdStr(sec, "dialogline", self.dialogLine)
|
||||
self.highlightEmph = conf.rdBool(sec, "highlightemph", self.highlightEmph)
|
||||
self.stopWhenIdle = conf.rdBool(sec, "stopwhenidle", self.stopWhenIdle)
|
||||
self.userIdleTime = conf.rdInt(sec, "useridletime", self.userIdleTime)
|
||||
@@ -666,14 +702,14 @@ class Config:
|
||||
}
|
||||
|
||||
conf["Main"] = {
|
||||
"font": self.guiFont.toString(),
|
||||
"theme": str(self.guiTheme),
|
||||
"syntax": str(self.guiSyntax),
|
||||
"font": str(self.guiFont),
|
||||
"fontsize": str(self.guiFontSize),
|
||||
"localisation": str(self.guiLocale),
|
||||
"hidevscroll": str(self.hideVScroll),
|
||||
"hidehscroll": str(self.hideHScroll),
|
||||
"lastnotes": str(self.lastNotes),
|
||||
"nativefont": str(self.nativeFont),
|
||||
"lastpath": str(self._lastPath),
|
||||
}
|
||||
|
||||
@@ -696,8 +732,7 @@ class Config:
|
||||
}
|
||||
|
||||
conf["Editor"] = {
|
||||
"textfont": str(self.textFont),
|
||||
"textsize": str(self.textSize),
|
||||
"textfont": self.textFont.toString(),
|
||||
"width": str(self.textWidth),
|
||||
"margin": str(self.textMargin),
|
||||
"tabwidth": str(self.tabWidth),
|
||||
@@ -726,9 +761,12 @@ class Config:
|
||||
"showmultispaces": str(self.showMultiSpaces),
|
||||
"incnoteswcount": str(self.incNotesWCount),
|
||||
"showfullpath": str(self.showFullPath),
|
||||
"highlightquotes": str(self.highlightQuotes),
|
||||
"allowopensquote": str(self.allowOpenSQuote),
|
||||
"allowopendquote": str(self.allowOpenDQuote),
|
||||
"dialogstyle": str(self.dialogStyle),
|
||||
"allowopendial": str(self.allowOpenDial),
|
||||
"narratorbreak": str(self.narratorBreak),
|
||||
"altdialogopen": str(self.altDialogOpen),
|
||||
"altdialogclose": str(self.altDialogClose),
|
||||
"dialogline": str(self.dialogLine),
|
||||
"highlightemph": str(self.highlightEmph),
|
||||
"stopwhenidle": str(self.stopWhenIdle),
|
||||
"useridletime": str(self.userIdleTime),
|
||||
@@ -787,8 +825,6 @@ class Config:
|
||||
logger.debug("Checking package 'pyenchant': OK")
|
||||
return
|
||||
|
||||
# END Class Config
|
||||
|
||||
|
||||
class RecentProjects:
|
||||
|
||||
@@ -857,5 +893,3 @@ class RecentProjects:
|
||||
logger.debug("Removed recent: %s", path)
|
||||
self.saveCache()
|
||||
return
|
||||
|
||||
# END Class RecentProjects
|
||||
|
||||
@@ -23,9 +23,11 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
|
||||
from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||
|
||||
from novelwriter.enum import nwBuildFmt, nwItemClass, nwItemLayout, nwOutline
|
||||
from novelwriter.enum import (
|
||||
nwBuildFmt, nwComment, nwItemClass, nwItemLayout, nwOutline, nwStatusShape
|
||||
)
|
||||
|
||||
|
||||
def trConst(text: str) -> str:
|
||||
@@ -58,8 +60,6 @@ class nwConst:
|
||||
# Dialogs
|
||||
DLG_FINISHED = 2
|
||||
|
||||
# END Class nwConst
|
||||
|
||||
|
||||
class nwRegEx:
|
||||
|
||||
@@ -67,9 +67,7 @@ class nwRegEx:
|
||||
FMT_EB = r"(?<![\w\\])([\*]{2})(?![\s\*])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_ST = r"(?<![\w\\])([~]{2})(?![\s~])(.+?)(?<![\s\\])(\1)(?!\w)"
|
||||
FMT_SC = r"(?i)(?<!\\)(\[[\/\!]?(?:i|b|s|u|m|sup|sub)\])"
|
||||
FMT_SV = r"(?<!\\)(\[(?i)(?:fn|footnote):)(.+?)(?<!\\)(\])"
|
||||
|
||||
# END Class nwRegEx
|
||||
FMT_SV = r"(?<!\\)(\[(?i)(?:footnote):)(.+?)(?<!\\)(\])"
|
||||
|
||||
|
||||
class nwShortcode:
|
||||
@@ -89,15 +87,19 @@ class nwShortcode:
|
||||
SUB_O = "[sub]"
|
||||
SUB_C = "[/sub]"
|
||||
|
||||
# END Class nwShortcode
|
||||
FOOTNOTE_B = "[footnote:"
|
||||
|
||||
COMMENT_STYLES = {
|
||||
nwComment.FOOTNOTE: "[footnote:{0}]",
|
||||
nwComment.COMMENT: "[comment:{0}]",
|
||||
}
|
||||
|
||||
|
||||
class nwHeaders:
|
||||
|
||||
H_VALID = ("H0", "H1", "H2", "H3", "H4")
|
||||
H_LEVEL = {"H0": 0, "H1": 1, "H2": 2, "H3": 3, "H4": 4}
|
||||
|
||||
# END Class nwHeaders
|
||||
H_SIZES = {0: 2.50, 1: 2.00, 2: 1.75, 3: 1.50, 4: 1.25}
|
||||
|
||||
|
||||
class nwFiles:
|
||||
@@ -118,8 +120,6 @@ class nwFiles:
|
||||
DICT_FILE = "userdict.json"
|
||||
SESS_FILE = "sessions.jsonl"
|
||||
|
||||
# END Class nwFiles
|
||||
|
||||
|
||||
class nwKeyWords:
|
||||
|
||||
@@ -153,8 +153,6 @@ class nwKeyWords:
|
||||
CUSTOM_KEY: nwItemClass.CUSTOM,
|
||||
}
|
||||
|
||||
# END Class nwKeyWords
|
||||
|
||||
|
||||
class nwLists:
|
||||
|
||||
@@ -168,8 +166,6 @@ class nwLists:
|
||||
nwItemClass.CUSTOM,
|
||||
]
|
||||
|
||||
# END Class nwLists
|
||||
|
||||
|
||||
class nwLabels:
|
||||
|
||||
@@ -268,6 +264,34 @@ class nwLabels:
|
||||
nwBuildFmt.J_HTML: ".json",
|
||||
nwBuildFmt.J_NWD: ".json",
|
||||
}
|
||||
SHAPES_PLAIN = {
|
||||
nwStatusShape.SQUARE: QT_TRANSLATE_NOOP("Constant", "Square"),
|
||||
nwStatusShape.TRIANGLE: QT_TRANSLATE_NOOP("Constant", "Triangle"),
|
||||
nwStatusShape.NABLA: QT_TRANSLATE_NOOP("Constant", "Nabla"),
|
||||
nwStatusShape.DIAMOND: QT_TRANSLATE_NOOP("Constant", "Diamond"),
|
||||
nwStatusShape.PENTAGON: QT_TRANSLATE_NOOP("Constant", "Pentagon"),
|
||||
nwStatusShape.HEXAGON: QT_TRANSLATE_NOOP("Constant", "Hexagon"),
|
||||
nwStatusShape.STAR: QT_TRANSLATE_NOOP("Constant", "Star"),
|
||||
nwStatusShape.PACMAN: QT_TRANSLATE_NOOP("Constant", "Pacman"),
|
||||
}
|
||||
SHAPES_CIRCLE = {
|
||||
nwStatusShape.CIRCLE_Q: QT_TRANSLATE_NOOP("Constant", "1/4 Circle"),
|
||||
nwStatusShape.CIRCLE_H: QT_TRANSLATE_NOOP("Constant", "Half Circle"),
|
||||
nwStatusShape.CIRCLE_T: QT_TRANSLATE_NOOP("Constant", "3/4 Circle"),
|
||||
nwStatusShape.CIRCLE: QT_TRANSLATE_NOOP("Constant", "Full Circle"),
|
||||
}
|
||||
SHAPES_BARS = {
|
||||
nwStatusShape.BARS_1: QT_TRANSLATE_NOOP("Constant", "1 Bar"),
|
||||
nwStatusShape.BARS_2: QT_TRANSLATE_NOOP("Constant", "2 Bars"),
|
||||
nwStatusShape.BARS_3: QT_TRANSLATE_NOOP("Constant", "3 Bars"),
|
||||
nwStatusShape.BARS_4: QT_TRANSLATE_NOOP("Constant", "4 Bars"),
|
||||
}
|
||||
SHAPES_BLOCKS = {
|
||||
nwStatusShape.BLOCK_1: QT_TRANSLATE_NOOP("Constant", "1 Block"),
|
||||
nwStatusShape.BLOCK_2: QT_TRANSLATE_NOOP("Constant", "2 Blocks"),
|
||||
nwStatusShape.BLOCK_3: QT_TRANSLATE_NOOP("Constant", "3 Blocks"),
|
||||
nwStatusShape.BLOCK_4: QT_TRANSLATE_NOOP("Constant", "4 Blocks"),
|
||||
}
|
||||
FILE_FILTERS = {
|
||||
"*.txt": QT_TRANSLATE_NOOP("Constant", "Text files"),
|
||||
"*.md": QT_TRANSLATE_NOOP("Constant", "Markdown files"),
|
||||
@@ -302,8 +326,6 @@ class nwLabels:
|
||||
"Custom": (-1.0, -1.0),
|
||||
}
|
||||
|
||||
# END Class nwLabels
|
||||
|
||||
|
||||
class nwHeadFmt:
|
||||
|
||||
@@ -329,8 +351,6 @@ class nwHeadFmt:
|
||||
ODT_PAGE = "{Page}"
|
||||
ODT_AUTO = "{Project} / {Author} / {Page}"
|
||||
|
||||
# END Class nwHeadFmt
|
||||
|
||||
|
||||
class nwQuotes:
|
||||
"""Allowed quotation marks.
|
||||
@@ -361,8 +381,6 @@ class nwQuotes:
|
||||
"\u300f": QT_TRANSLATE_NOOP("Constant", "Right white corner bracket"),
|
||||
}
|
||||
|
||||
# END Class nwQuotes
|
||||
|
||||
|
||||
class nwUnicode:
|
||||
"""Supported unicode character constants and their HTML equivalents."""
|
||||
@@ -497,8 +515,6 @@ class nwUnicode:
|
||||
H_LTRI = "◀"
|
||||
H_LTRIS = "◂"
|
||||
|
||||
# END Class nwUnicode
|
||||
|
||||
|
||||
class nwHtmlUnicode():
|
||||
|
||||
@@ -554,5 +570,3 @@ class nwHtmlUnicode():
|
||||
nwUnicode.U_TIMES: nwUnicode.H_TIMES,
|
||||
nwUnicode.U_DIVIDE: nwUnicode.H_DIVIDE,
|
||||
}
|
||||
|
||||
# END Class nwHtmlUnicode
|
||||
|
||||
@@ -25,21 +25,21 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import uuid
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from collections.abc import Iterable
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from collections.abc import Iterable
|
||||
|
||||
from PyQt5.QtCore import QT_TRANSLATE_NOOP, QCoreApplication
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import checkUuid, isHandle, jsonEncode
|
||||
from novelwriter.constants import nwFiles, nwHeadFmt
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.error import logException
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -76,12 +76,15 @@ SETTINGS_TEMPLATE = {
|
||||
"text.includeBodyText": (bool, True),
|
||||
"text.ignoredKeywords": (str, ""),
|
||||
"text.addNoteHeadings": (bool, True),
|
||||
"format.textFont": (str, CONFIG.textFont),
|
||||
"format.textSize": (int, 12),
|
||||
"format.textFont": (str, CONFIG.textFont.toString()),
|
||||
"format.lineHeight": (float, 1.15, 0.75, 3.0),
|
||||
"format.justifyText": (bool, False),
|
||||
"format.stripUnicode": (bool, False),
|
||||
"format.replaceTabs": (bool, False),
|
||||
"format.keepBreaks": (bool, True),
|
||||
"format.firstLineIndent": (bool, False),
|
||||
"format.firstIndentWidth": (float, 1.4),
|
||||
"format.indentFirstPar": (bool, False),
|
||||
"format.pageUnit": (str, "cm"),
|
||||
"format.pageSize": (str, "A4"),
|
||||
"format.pageWidth": (float, 21.0),
|
||||
@@ -93,65 +96,65 @@ SETTINGS_TEMPLATE = {
|
||||
"odt.addColours": (bool, True),
|
||||
"odt.pageHeader": (str, nwHeadFmt.ODT_AUTO),
|
||||
"odt.pageCountOffset": (int, 0),
|
||||
"odt.firstLineIndent": (bool, False),
|
||||
"md.preserveBreaks": (bool, True),
|
||||
"html.addStyles": (bool, True),
|
||||
"html.preserveTabs": (bool, False),
|
||||
}
|
||||
|
||||
SETTINGS_LABELS = {
|
||||
"filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"),
|
||||
"filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"),
|
||||
"filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"),
|
||||
"filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"),
|
||||
"filter": QT_TRANSLATE_NOOP("Builds", "Document Filters"),
|
||||
"filter.includeNovel": QT_TRANSLATE_NOOP("Builds", "Novel Documents"),
|
||||
"filter.includeNotes": QT_TRANSLATE_NOOP("Builds", "Project Notes"),
|
||||
"filter.includeInactive": QT_TRANSLATE_NOOP("Builds", "Inactive Documents"),
|
||||
|
||||
"headings": QT_TRANSLATE_NOOP("Builds", "Headings"),
|
||||
"headings.fmtTitle": QT_TRANSLATE_NOOP("Builds", "Partition Format"),
|
||||
"headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Format"),
|
||||
"headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Format"),
|
||||
"headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Format"),
|
||||
"headings.fmtAltScene": QT_TRANSLATE_NOOP("Builds", "Alt. Scene Format"),
|
||||
"headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Format"),
|
||||
"headings": QT_TRANSLATE_NOOP("Builds", "Headings"),
|
||||
"headings.fmtTitle": QT_TRANSLATE_NOOP("Builds", "Partition Format"),
|
||||
"headings.fmtChapter": QT_TRANSLATE_NOOP("Builds", "Chapter Format"),
|
||||
"headings.fmtUnnumbered": QT_TRANSLATE_NOOP("Builds", "Unnumbered Format"),
|
||||
"headings.fmtScene": QT_TRANSLATE_NOOP("Builds", "Scene Format"),
|
||||
"headings.fmtAltScene": QT_TRANSLATE_NOOP("Builds", "Alt. Scene Format"),
|
||||
"headings.fmtSection": QT_TRANSLATE_NOOP("Builds", "Section Format"),
|
||||
|
||||
"text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
|
||||
"text.includeSynopsis": QT_TRANSLATE_NOOP("Builds", "Include Synopsis"),
|
||||
"text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
|
||||
"text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
|
||||
"text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
|
||||
"text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
|
||||
"text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"),
|
||||
"text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
|
||||
"text.grpContent": QT_TRANSLATE_NOOP("Builds", "Text Content"),
|
||||
"text.includeSynopsis": QT_TRANSLATE_NOOP("Builds", "Include Synopsis"),
|
||||
"text.includeComments": QT_TRANSLATE_NOOP("Builds", "Include Comments"),
|
||||
"text.includeKeywords": QT_TRANSLATE_NOOP("Builds", "Include Keywords"),
|
||||
"text.includeBodyText": QT_TRANSLATE_NOOP("Builds", "Include Body Text"),
|
||||
"text.ignoredKeywords": QT_TRANSLATE_NOOP("Builds", "Ignore These Keywords"),
|
||||
"text.grpInsert": QT_TRANSLATE_NOOP("Builds", "Insert Content"),
|
||||
"text.addNoteHeadings": QT_TRANSLATE_NOOP("Builds", "Add Titles for Notes"),
|
||||
|
||||
"format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
|
||||
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Font Family"),
|
||||
"format.textSize": QT_TRANSLATE_NOOP("Builds", "Font Size"),
|
||||
"format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
|
||||
"format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"),
|
||||
"format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
|
||||
"format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"),
|
||||
"format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"),
|
||||
"format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
|
||||
"format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
|
||||
"format.pageSize": QT_TRANSLATE_NOOP("Builds", "Page Size"),
|
||||
"format.pageWidth": QT_TRANSLATE_NOOP("Builds", "Page Width"),
|
||||
"format.pageHeight": QT_TRANSLATE_NOOP("Builds", "Page Height"),
|
||||
"format.topMargin": QT_TRANSLATE_NOOP("Builds", "Top Margin"),
|
||||
"format.bottomMargin": QT_TRANSLATE_NOOP("Builds", "Bottom Margin"),
|
||||
"format.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"),
|
||||
"format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right Margin"),
|
||||
"format.grpFormat": QT_TRANSLATE_NOOP("Builds", "Text Format"),
|
||||
"format.textFont": QT_TRANSLATE_NOOP("Builds", "Text Font"),
|
||||
"format.lineHeight": QT_TRANSLATE_NOOP("Builds", "Line Height"),
|
||||
"format.grpOptions": QT_TRANSLATE_NOOP("Builds", "Text Options"),
|
||||
"format.justifyText": QT_TRANSLATE_NOOP("Builds", "Justify Text Margins"),
|
||||
"format.stripUnicode": QT_TRANSLATE_NOOP("Builds", "Replace Unicode Characters"),
|
||||
"format.replaceTabs": QT_TRANSLATE_NOOP("Builds", "Replace Tabs with Spaces"),
|
||||
"format.keepBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"),
|
||||
|
||||
"odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"),
|
||||
"odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
|
||||
"odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
|
||||
"odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
|
||||
"odt.firstLineIndent": QT_TRANSLATE_NOOP("Builds", "First Line Indent"),
|
||||
"format.grpParIndent": QT_TRANSLATE_NOOP("Builds", "First Line Indent"),
|
||||
"format.firstLineIndent": QT_TRANSLATE_NOOP("Builds", "Enable Indent"),
|
||||
"format.firstIndentWidth": QT_TRANSLATE_NOOP("Builds", "Indent Width"),
|
||||
"format.indentFirstPar": QT_TRANSLATE_NOOP("Builds", "Indent First Paragraph"),
|
||||
|
||||
"md": QT_TRANSLATE_NOOP("Builds", "Markdown (.md)"),
|
||||
"md.preserveBreaks": QT_TRANSLATE_NOOP("Builds", "Preserve Hard Line Breaks"),
|
||||
"format.grpPage": QT_TRANSLATE_NOOP("Builds", "Page Layout"),
|
||||
"format.pageUnit": QT_TRANSLATE_NOOP("Builds", "Unit"),
|
||||
"format.pageSize": QT_TRANSLATE_NOOP("Builds", "Page Size"),
|
||||
"format.pageWidth": QT_TRANSLATE_NOOP("Builds", "Page Width"),
|
||||
"format.pageHeight": QT_TRANSLATE_NOOP("Builds", "Page Height"),
|
||||
"format.topMargin": QT_TRANSLATE_NOOP("Builds", "Top Margin"),
|
||||
"format.bottomMargin": QT_TRANSLATE_NOOP("Builds", "Bottom Margin"),
|
||||
"format.leftMargin": QT_TRANSLATE_NOOP("Builds", "Left Margin"),
|
||||
"format.rightMargin": QT_TRANSLATE_NOOP("Builds", "Right Margin"),
|
||||
|
||||
"html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
|
||||
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
|
||||
"html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
|
||||
"odt": QT_TRANSLATE_NOOP("Builds", "Open Document (.odt)"),
|
||||
"odt.addColours": QT_TRANSLATE_NOOP("Builds", "Add Highlight Colours"),
|
||||
"odt.pageHeader": QT_TRANSLATE_NOOP("Builds", "Page Header"),
|
||||
"odt.pageCountOffset": QT_TRANSLATE_NOOP("Builds", "Page Counter Offset"),
|
||||
|
||||
"html": QT_TRANSLATE_NOOP("Builds", "HTML (.html)"),
|
||||
"html.addStyles": QT_TRANSLATE_NOOP("Builds", "Add CSS Styles"),
|
||||
"html.preserveTabs": QT_TRANSLATE_NOOP("Builds", "Preserve Tab Characters"),
|
||||
}
|
||||
|
||||
|
||||
@@ -165,8 +168,6 @@ class FilterMode(Enum):
|
||||
SKIPPED = 4
|
||||
ROOT = 5
|
||||
|
||||
# END Enum FilterMode
|
||||
|
||||
|
||||
class BuildSettings:
|
||||
"""Core: Build Settings Class
|
||||
@@ -481,8 +482,6 @@ class BuildSettings:
|
||||
|
||||
return
|
||||
|
||||
# END Class BuildSettings
|
||||
|
||||
|
||||
class BuildCollection:
|
||||
"""Core: Build Collection Class
|
||||
@@ -630,5 +629,3 @@ class BuildCollection:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# END Class BuildCollection
|
||||
|
||||
@@ -104,7 +104,7 @@ class DocMerger:
|
||||
docText = self._project.storage.getDocumentText(srcHandle).rstrip("\n")
|
||||
if addComment:
|
||||
docInfo = srcItem.describeMe()
|
||||
docSt, _ = srcItem.getImportStatus(incIcon=False)
|
||||
docSt, _ = srcItem.getImportStatus()
|
||||
cmtLine = f"% {cmtPrefix} {docInfo}: {srcItem.itemName} [{docSt}]\n\n"
|
||||
docText = cmtLine + docText
|
||||
|
||||
@@ -129,8 +129,6 @@ class DocMerger:
|
||||
|
||||
return status
|
||||
|
||||
# END Class DocMerger
|
||||
|
||||
|
||||
class DocSplitter:
|
||||
"""Document tool for splitting a document into a set of new
|
||||
@@ -257,8 +255,6 @@ class DocSplitter:
|
||||
|
||||
return
|
||||
|
||||
# END Class DocSplitter
|
||||
|
||||
|
||||
class DocDuplicator:
|
||||
"""A class that will duplicate all documents and folders starting
|
||||
@@ -297,8 +293,6 @@ class DocDuplicator:
|
||||
nHandle = None
|
||||
return
|
||||
|
||||
# END Class DocDuplicator
|
||||
|
||||
|
||||
class DocSearch:
|
||||
|
||||
@@ -370,23 +364,11 @@ class DocSearch:
|
||||
def _buildPattern(self, search: str) -> str:
|
||||
"""Build the search pattern string."""
|
||||
if self._escape:
|
||||
if CONFIG.verQtValue >= 0x050f00:
|
||||
search = QRegularExpression.escape(search)
|
||||
else:
|
||||
# For older Qt versions, we escape manually
|
||||
escaped = ""
|
||||
for c in search:
|
||||
if c.isalnum() or c == "_":
|
||||
escaped += c
|
||||
else:
|
||||
escaped += f"\\{c}"
|
||||
search = escaped
|
||||
search = QRegularExpression.escape(search)
|
||||
if self._words:
|
||||
search = f"(?:^|\\b){search}(?:$|\\b)"
|
||||
return search
|
||||
|
||||
# END Class DocSearch
|
||||
|
||||
|
||||
class ProjectBuilder:
|
||||
"""A class to build a new project from a set of user-defined
|
||||
@@ -619,5 +601,3 @@ class ProjectBuilder:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# END Class ProjectBuilder
|
||||
|
||||
@@ -25,22 +25,23 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtGui import QFont, QFontInfo
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tohtml import ToHtml
|
||||
from novelwriter.core.tokenizer import Tokenizer
|
||||
from novelwriter.core.tomarkdown import ToMarkdown
|
||||
from novelwriter.core.toodt import ToOdt
|
||||
from novelwriter.core.toqdoc import TextDocumentTheme, ToQTextDocument
|
||||
from novelwriter.enum import nwBuildFmt
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.tomd import ToMarkdown
|
||||
from novelwriter.core.toodt import ToOdt
|
||||
from novelwriter.core.tohtml import ToHtml
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer
|
||||
from novelwriter.core.buildsettings import BuildSettings
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -54,7 +55,7 @@ class NWBuildDocument:
|
||||
|
||||
__slots__ = (
|
||||
"_project", "_build", "_queue", "_error", "_cache", "_count",
|
||||
"_outline", "_preview"
|
||||
"_outline",
|
||||
)
|
||||
|
||||
def __init__(self, project: NWProject, build: BuildSettings) -> None:
|
||||
@@ -65,7 +66,6 @@ class NWBuildDocument:
|
||||
self._cache = None
|
||||
self._count = False
|
||||
self._outline = False
|
||||
self._preview = False
|
||||
return
|
||||
|
||||
##
|
||||
@@ -99,15 +99,6 @@ class NWBuildDocument:
|
||||
self._outline = state
|
||||
return
|
||||
|
||||
def setPreviewMode(self, state: bool) -> None:
|
||||
"""Set the preview mode of the build. This also enables stats
|
||||
count and outline mode.
|
||||
"""
|
||||
self._preview = state
|
||||
self._outline = state
|
||||
self._count = state
|
||||
return
|
||||
|
||||
##
|
||||
# Special Methods
|
||||
##
|
||||
@@ -134,6 +125,32 @@ class NWBuildDocument:
|
||||
self._queue.append(item.itemHandle)
|
||||
return
|
||||
|
||||
def iterBuildPreview(self, theme: TextDocumentTheme) -> Iterable[tuple[int, bool]]:
|
||||
"""Build a preview QTextDocument."""
|
||||
makeObj = ToQTextDocument(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
|
||||
self._outline = True
|
||||
self._count = True
|
||||
|
||||
font = QFont()
|
||||
font.fromString(self._build.getStr("format.textFont"))
|
||||
|
||||
makeObj.initDocument(font, theme)
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
yield i, self._doBuild(makeObj, tHandle)
|
||||
else:
|
||||
yield i, False
|
||||
|
||||
makeObj.appendFootnotes()
|
||||
|
||||
self._error = None
|
||||
self._cache = makeObj
|
||||
|
||||
return
|
||||
|
||||
def iterBuild(self, path: Path, bFormat: nwBuildFmt) -> Iterable[tuple[int, bool]]:
|
||||
"""Wrapper for builders based on format."""
|
||||
if bFormat in (nwBuildFmt.ODT, nwBuildFmt.FODT):
|
||||
@@ -182,8 +199,6 @@ class NWBuildDocument:
|
||||
makeObj = ToHtml(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
|
||||
makeObj.setPreview(self._preview)
|
||||
makeObj.setLinkHeadings(self._preview)
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
@@ -191,7 +206,9 @@ class NWBuildDocument:
|
||||
else:
|
||||
yield i, False
|
||||
|
||||
if not (self._build.getBool("html.preserveTabs") or self._preview):
|
||||
makeObj.appendFootnotes()
|
||||
|
||||
if not self._build.getBool("html.preserveTabs"):
|
||||
makeObj.replaceTabs()
|
||||
|
||||
self._error = None
|
||||
@@ -214,16 +231,10 @@ class NWBuildDocument:
|
||||
makeObj = ToMarkdown(self._project)
|
||||
filtered = self._setupBuild(makeObj)
|
||||
|
||||
if extendedMd:
|
||||
makeObj.setExtendedMarkdown()
|
||||
else:
|
||||
makeObj.setStandardMarkdown()
|
||||
|
||||
makeObj.setExtendedMarkdown(extendedMd)
|
||||
if self._build.getBool("format.replaceTabs"):
|
||||
makeObj.replaceTabs(nSpaces=4, spaceChar=" ")
|
||||
|
||||
makeObj.setPreserveBreaks(self._build.getBool("md.preserveBreaks"))
|
||||
|
||||
for i, tHandle in enumerate(self._queue):
|
||||
self._error = None
|
||||
if filtered.get(tHandle, (False, 0))[0]:
|
||||
@@ -231,6 +242,8 @@ class NWBuildDocument:
|
||||
else:
|
||||
yield i, False
|
||||
|
||||
makeObj.appendFootnotes()
|
||||
|
||||
self._error = None
|
||||
self._cache = makeObj
|
||||
|
||||
@@ -281,13 +294,9 @@ class NWBuildDocument:
|
||||
def _setupBuild(self, bldObj: Tokenizer) -> dict:
|
||||
"""Configure the build object."""
|
||||
# Get Settings
|
||||
textFont = self._build.getStr("format.textFont")
|
||||
textSize = self._build.getInt("format.textSize")
|
||||
|
||||
fontFamily = textFont or CONFIG.textFont
|
||||
bldFont = QFont(fontFamily, textSize)
|
||||
fontInfo = QFontInfo(bldFont)
|
||||
textFixed = fontInfo.fixedPitch()
|
||||
textFont = QFont(CONFIG.textFont)
|
||||
textFont.fromString(self._build.getStr("format.textFont"))
|
||||
bldObj.setFont(textFont)
|
||||
|
||||
bldObj.setTitleFormat(
|
||||
self._build.getStr("headings.fmtTitle"),
|
||||
@@ -326,9 +335,14 @@ class NWBuildDocument:
|
||||
self._build.getBool("headings.breakScene")
|
||||
)
|
||||
|
||||
bldObj.setFont(fontFamily, textSize, textFixed)
|
||||
bldObj.setJustify(self._build.getBool("format.justifyText"))
|
||||
bldObj.setLineHeight(self._build.getFloat("format.lineHeight"))
|
||||
bldObj.setKeepLineBreaks(self._build.getBool("format.keepBreaks"))
|
||||
bldObj.setFirstLineIndent(
|
||||
self._build.getBool("format.firstLineIndent"),
|
||||
self._build.getFloat("format.firstIndentWidth"),
|
||||
self._build.getBool("format.indentFirstPar"),
|
||||
)
|
||||
|
||||
bldObj.setBodyText(self._build.getBool("text.includeBodyText"))
|
||||
bldObj.setSynopsis(self._build.getBool("text.includeSynopsis"))
|
||||
@@ -346,7 +360,6 @@ class NWBuildDocument:
|
||||
bldObj.setHeaderFormat(
|
||||
self._build.getStr("odt.pageHeader"), self._build.getInt("odt.pageCountOffset")
|
||||
)
|
||||
bldObj.setFirstLineIndent(self._build.getBool("odt.firstLineIndent"))
|
||||
|
||||
scale = nwLabels.UNIT_SCALE.get(self._build.getStr("format.pageUnit"), 1.0)
|
||||
pW, pH = nwLabels.PAPER_SIZE.get(self._build.getStr("format.pageSize"), (-1.0, -1.0))
|
||||
@@ -397,5 +410,3 @@ class NWBuildDocument:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# END Class NWBuildDocument
|
||||
|
||||
@@ -26,14 +26,14 @@ from __future__ import annotations
|
||||
import hashlib
|
||||
import logging
|
||||
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter.enum import nwItemLayout, nwItemClass
|
||||
from novelwriter.error import formatException, logException
|
||||
from novelwriter.common import formatTimeStamp, isHandle
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout
|
||||
from novelwriter.error import formatException, logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
@@ -359,5 +359,3 @@ class NWDocument:
|
||||
logger.debug("Unknown meta data: '%s'", metaLine.strip())
|
||||
|
||||
return
|
||||
|
||||
# END Class NWDocument
|
||||
|
||||
@@ -29,17 +29,20 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
import random
|
||||
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
from collections.abc import ItemsView, Iterable
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.enum import nwComment, nwItemClass, nwItemType, nwItemLayout
|
||||
from novelwriter.common import (
|
||||
checkInt, isHandle, isItemClass, isListInstance, isTitleTag, jsonEncode
|
||||
)
|
||||
from novelwriter.constants import nwFiles, nwHeaders, nwKeyWords
|
||||
from novelwriter.enum import nwComment, nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import checkInt, isHandle, isItemClass, isTitleTag, jsonEncode
|
||||
from novelwriter.constants import nwFiles, nwKeyWords, nwHeaders
|
||||
from novelwriter.text.counting import standardCounter
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@@ -48,7 +51,12 @@ if TYPE_CHECKING: # pragma: no cover
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
TT_NONE = "T0000"
|
||||
T_NoteTypes = Literal["footnotes", "comments"]
|
||||
|
||||
TT_NONE = "T0000" # Default title key
|
||||
MAX_RETRY = 1000 # Key generator recursion limit
|
||||
KEY_SOURCE = "0123456789bcdfghjklmnpqrstvwxz"
|
||||
NOTE_TYPES: list[T_NoteTypes] = ["footnotes", "comments"]
|
||||
|
||||
|
||||
class NWIndex:
|
||||
@@ -301,9 +309,9 @@ class NWIndex:
|
||||
|
||||
def _scanActive(self, tHandle: str, nwItem: NWItem, text: str, tags: dict[str, bool]) -> None:
|
||||
"""Scan an active document for meta data."""
|
||||
nTitle = 0 # Line Number of the previous title
|
||||
cTitle = TT_NONE # Tag of the current title
|
||||
pTitle = TT_NONE # Tag of the previous title
|
||||
nTitle = 0 # Line Number of the previous title
|
||||
cTitle = TT_NONE # Tag of the current title
|
||||
pTitle = TT_NONE # Tag of the previous title
|
||||
canSetHead = True # First heading has not yet been set
|
||||
|
||||
lines = text.splitlines()
|
||||
@@ -335,10 +343,11 @@ class NWIndex:
|
||||
self._indexKeyword(tHandle, line, cTitle, nwItem.itemClass, tags)
|
||||
|
||||
elif line.startswith("%"):
|
||||
if cTitle != TT_NONE:
|
||||
cStyle, cText, _ = processComment(line)
|
||||
if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT):
|
||||
self._itemIndex.setHeadingSynopsis(tHandle, cTitle, cText)
|
||||
cStyle, cKey, cText, _, _ = processComment(line)
|
||||
if cStyle in (nwComment.SYNOPSIS, nwComment.SHORT):
|
||||
self._itemIndex.setHeadingSynopsis(tHandle, cTitle, cText)
|
||||
elif cStyle == nwComment.FOOTNOTE:
|
||||
self._itemIndex.addNoteKey(tHandle, "footnotes", cKey)
|
||||
|
||||
# Count words for remaining text after last heading
|
||||
if pTitle != TT_NONE:
|
||||
@@ -506,6 +515,14 @@ class NWIndex:
|
||||
name, _, display = text.partition("|")
|
||||
return name.rstrip(), display.lstrip()
|
||||
|
||||
def newCommentKey(self, tHandle: str, style: nwComment) -> str:
|
||||
"""Generate a new key for a comment style."""
|
||||
if style == nwComment.FOOTNOTE:
|
||||
return self._itemIndex.genNewNoteKey(tHandle, "footnotes")
|
||||
elif style == nwComment.COMMENT:
|
||||
return self._itemIndex.genNewNoteKey(tHandle, "comments")
|
||||
return "err"
|
||||
|
||||
##
|
||||
# Extract Data
|
||||
##
|
||||
@@ -690,12 +707,9 @@ class NWIndex:
|
||||
return tName, tClass, iItem, None if iItem is None else iItem[tHeading]
|
||||
return "", "", None, None
|
||||
|
||||
# END Class NWIndex
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# The Tags Index Object
|
||||
# =============================================================================================== #
|
||||
# The Tags Index Object
|
||||
# =====================
|
||||
|
||||
class TagsIndex:
|
||||
"""Core: Tags Index Wrapper Class
|
||||
@@ -790,7 +804,7 @@ class TagsIndex:
|
||||
|
||||
for key, entry in data.items():
|
||||
if not isinstance(key, str):
|
||||
raise ValueError("tagsIndex keys must be a string")
|
||||
raise ValueError("tagsIndex key must be a string")
|
||||
if not isinstance(entry, dict):
|
||||
raise ValueError("tagsIndex entry is not a dict")
|
||||
|
||||
@@ -815,12 +829,9 @@ class TagsIndex:
|
||||
|
||||
return
|
||||
|
||||
# END Class TagsIndex
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# The Item Index Objects
|
||||
# =============================================================================================== #
|
||||
# The Item Index Objects
|
||||
# ======================
|
||||
|
||||
class ItemIndex:
|
||||
"""Core: Item Index Wrapper Class
|
||||
@@ -950,6 +961,25 @@ class ItemIndex:
|
||||
self._items[tHandle].addHeadingRef(sTitle, tagKeys, refType)
|
||||
return
|
||||
|
||||
def addNoteKey(self, tHandle: str, style: T_NoteTypes, key: str) -> None:
|
||||
"""Set notes key for a given item."""
|
||||
if tHandle in self._items:
|
||||
self._items[tHandle].addNoteKey(style, key)
|
||||
return
|
||||
|
||||
def genNewNoteKey(self, tHandle: str, style: T_NoteTypes) -> str:
|
||||
"""Set notes key for a given item."""
|
||||
if style in NOTE_TYPES and (item := self._items.get(tHandle)):
|
||||
keys = set()
|
||||
for entry in self._items.values():
|
||||
keys.update(entry.noteKeys(style))
|
||||
for _ in range(MAX_RETRY):
|
||||
key = style[:1] + "".join(random.choices(KEY_SOURCE, k=4))
|
||||
if key not in keys:
|
||||
item.addNoteKey(style, key)
|
||||
return key
|
||||
return "err"
|
||||
|
||||
##
|
||||
# Pack/Unpack
|
||||
##
|
||||
@@ -978,8 +1008,6 @@ class ItemIndex:
|
||||
|
||||
return
|
||||
|
||||
# END Class ItemIndex
|
||||
|
||||
|
||||
class IndexItem:
|
||||
"""Core: Single Index Item Class
|
||||
@@ -991,12 +1019,13 @@ class IndexItem:
|
||||
must be reset each time the item is re-indexed.
|
||||
"""
|
||||
|
||||
__slots__ = ("_handle", "_item", "_headings", "_count")
|
||||
__slots__ = ("_handle", "_item", "_headings", "_count", "_notes")
|
||||
|
||||
def __init__(self, tHandle: str, nwItem: NWItem) -> None:
|
||||
self._handle = tHandle
|
||||
self._item = nwItem
|
||||
self._headings: dict[str, IndexHeading] = {TT_NONE: IndexHeading(TT_NONE)}
|
||||
self._notes: dict[str, set[str]] = {}
|
||||
self._count = 0
|
||||
return
|
||||
|
||||
@@ -1064,6 +1093,13 @@ class IndexItem:
|
||||
self._headings[sTitle].addReference(tagKey, refType)
|
||||
return
|
||||
|
||||
def addNoteKey(self, style: T_NoteTypes, key: str) -> None:
|
||||
"""Add a note key to the index."""
|
||||
if style not in self._notes:
|
||||
self._notes[style] = set()
|
||||
self._notes[style].add(key)
|
||||
return
|
||||
|
||||
##
|
||||
# Data Methods
|
||||
##
|
||||
@@ -1085,6 +1121,10 @@ class IndexItem:
|
||||
self._count += 1
|
||||
return f"T{self._count:04d}"
|
||||
|
||||
def noteKeys(self, style: T_NoteTypes) -> set[str]:
|
||||
"""Return a set of all note keys."""
|
||||
return self._notes.get(style, set())
|
||||
|
||||
##
|
||||
# Pack/Unpack
|
||||
##
|
||||
@@ -1103,6 +1143,8 @@ class IndexItem:
|
||||
data["headings"] = heads
|
||||
if refs:
|
||||
data["references"] = refs
|
||||
if self._notes:
|
||||
data["notes"] = {style: list(keys) for style, keys in self._notes.items()}
|
||||
|
||||
return data
|
||||
|
||||
@@ -1116,9 +1158,15 @@ class IndexItem:
|
||||
tHeading.unpackData(hData)
|
||||
tHeading.unpackReferences(references.get(sTitle, {}))
|
||||
self.addHeading(tHeading)
|
||||
return
|
||||
|
||||
# END Class IndexItem
|
||||
for style, keys in data.get("notes", {}).items():
|
||||
if style not in NOTE_TYPES:
|
||||
raise ValueError("The notes style is invalid")
|
||||
if not isListInstance(keys, str):
|
||||
raise ValueError("The notes keys must be a list of strings")
|
||||
self._notes[style] = set(keys)
|
||||
|
||||
return
|
||||
|
||||
|
||||
class IndexHeading:
|
||||
@@ -1295,25 +1343,47 @@ class IndexHeading:
|
||||
raise ValueError("The itemIndex contains an invalid reference type")
|
||||
return
|
||||
|
||||
# END Class IndexHeading
|
||||
|
||||
# Text Processing Functions
|
||||
# =========================
|
||||
|
||||
# =============================================================================================== #
|
||||
# Text Processing Functions
|
||||
# =============================================================================================== #
|
||||
|
||||
CLASSIFIERS = {
|
||||
"short": nwComment.SHORT,
|
||||
MODIFIERS = {
|
||||
"synopsis": nwComment.SYNOPSIS,
|
||||
"short": nwComment.SHORT,
|
||||
"note": nwComment.NOTE,
|
||||
"footnote": nwComment.FOOTNOTE,
|
||||
}
|
||||
KEY_REQ = {
|
||||
"synopsis": 0, # Key not allowed
|
||||
"short": 0, # Key not allowed
|
||||
"note": 1, # Key optional
|
||||
"footnote": 2, # Key required
|
||||
}
|
||||
|
||||
|
||||
def processComment(text: str) -> tuple[nwComment, str, int]:
|
||||
"""Extract comment style and text. Should only be called on text
|
||||
starting with a %.
|
||||
def _checkModKey(modifier: str, key: str) -> bool:
|
||||
"""Check if a modifier and key set are ok."""
|
||||
if modifier in MODIFIERS:
|
||||
if key == "":
|
||||
return KEY_REQ[modifier] < 2
|
||||
elif key.replace("_", "").isalnum():
|
||||
return KEY_REQ[modifier] > 0
|
||||
return False
|
||||
|
||||
|
||||
def processComment(text: str) -> tuple[nwComment, str, str, int, int]:
|
||||
"""Extract comment style, key and text. Should only be called on
|
||||
text starting with a %.
|
||||
"""
|
||||
check = text[1:].lstrip()
|
||||
classifier, _, content = check.partition(":")
|
||||
if content and (clean := classifier.strip().lower()) in CLASSIFIERS:
|
||||
return CLASSIFIERS[clean], content.strip(), text.find(":") + 1
|
||||
return nwComment.PLAIN, check, 0
|
||||
if text[:2] == "%~":
|
||||
return nwComment.IGNORE, "", text[2:].lstrip(), 0, 0
|
||||
|
||||
check = text[1:].strip()
|
||||
start, _, content = check.partition(":")
|
||||
modifier, _, key = start.rstrip().partition(".")
|
||||
if content and (clean := modifier.lower()) and _checkModKey(clean, key):
|
||||
col = text.find(":") + 1
|
||||
dot = text.find(".", 0, col) + 1
|
||||
return MODIFIERS[clean], key, content.lstrip(), dot, col
|
||||
|
||||
return nwComment.PLAIN, "", check, 0, 0
|
||||
|
||||
@@ -25,15 +25,16 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from typing import TYPE_CHECKING, Any, Literal, overload
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from PyQt5.QtGui import QIcon
|
||||
|
||||
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
|
||||
from novelwriter.common import (
|
||||
checkInt, isHandle, isItemClass, isItemLayout, isItemType, simplified, yesNo
|
||||
checkInt, isHandle, isItemClass, isItemLayout, isItemType, simplified,
|
||||
yesNo
|
||||
)
|
||||
from novelwriter.constants import nwHeaders, nwLabels, trConst
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
@@ -308,25 +309,15 @@ class NWItem:
|
||||
|
||||
return trConst(nwLabels.ITEM_DESCRIPTION.get(descKey, ""))
|
||||
|
||||
@overload # pragma: no cover
|
||||
def getImportStatus(self, incIcon: Literal[True] = True) -> tuple[str, QIcon]:
|
||||
pass
|
||||
|
||||
@overload # pragma: no cover
|
||||
def getImportStatus(self, incIcon: Literal[False]) -> tuple[str, None]:
|
||||
pass
|
||||
|
||||
def getImportStatus(self, incIcon=True):
|
||||
def getImportStatus(self) -> tuple[str, QIcon]:
|
||||
"""Return the relevant importance or status label and icon for
|
||||
the current item based on its class.
|
||||
"""
|
||||
if self.isNovelLike():
|
||||
stName = self._project.data.itemStatus.name(self._status)
|
||||
stIcon = self._project.data.itemStatus.icon(self._status) if incIcon else None
|
||||
entry = self._project.data.itemStatus[self._status]
|
||||
else:
|
||||
stName = self._project.data.itemImport.name(self._import)
|
||||
stIcon = self._project.data.itemImport.icon(self._import) if incIcon else None
|
||||
return stName, stIcon
|
||||
entry = self._project.data.itemImport[self._import]
|
||||
return entry.name, entry.icon
|
||||
|
||||
##
|
||||
# Checker Methods
|
||||
@@ -567,5 +558,3 @@ class NWItem:
|
||||
"""Save the initial word count."""
|
||||
self._initCount = self._wordCount
|
||||
return
|
||||
|
||||
# END Class NWItem
|
||||
|
||||
@@ -28,12 +28,12 @@ import json
|
||||
import logging
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, TypeVar
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, TypeVar
|
||||
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import checkBool, checkFloat, checkInt, checkString, jsonEncode
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
@@ -218,5 +218,3 @@ class OptionState:
|
||||
if value in lookup.__members__:
|
||||
return lookup[value]
|
||||
return default
|
||||
|
||||
# END Class OptionState
|
||||
|
||||
@@ -26,33 +26,33 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from collections.abc import Iterable
|
||||
from enum import Enum
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
from functools import partial
|
||||
from collections.abc import Iterable
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication
|
||||
|
||||
from novelwriter import CONFIG, SHARED, __version__, __hexversion__
|
||||
from novelwriter.enum import nwItemType, nwItemClass, nwItemLayout
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.constants import trConst, nwLabels
|
||||
from novelwriter.core.tree import NWTree
|
||||
from novelwriter import CONFIG, SHARED, __hexversion__, __version__
|
||||
from novelwriter.common import (
|
||||
checkStringNone, formatInt, formatTimeStamp, getFileSize, hexToInt,
|
||||
makeFileNameSafe, minmax
|
||||
)
|
||||
from novelwriter.constants import nwLabels, trConst
|
||||
from novelwriter.core.index import NWIndex
|
||||
from novelwriter.core.options import OptionState
|
||||
from novelwriter.core.storage import NWStorage, NWStorageOpen
|
||||
from novelwriter.core.sessions import NWSessionLog
|
||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
|
||||
from novelwriter.core.projectdata import NWProjectData
|
||||
from novelwriter.common import (
|
||||
checkStringNone, formatInt, formatTimeStamp, getFileSize, hexToInt, makeFileNameSafe, minmax
|
||||
)
|
||||
from novelwriter.core.projectxml import ProjectXMLReader, ProjectXMLWriter, XMLReadState
|
||||
from novelwriter.core.sessions import NWSessionLog
|
||||
from novelwriter.core.storage import NWStorage, NWStorageOpen
|
||||
from novelwriter.core.tree import NWTree
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.core.status import NWStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -64,8 +64,6 @@ class NWProjectState(Enum):
|
||||
RECOVERY = 2
|
||||
READY = 3
|
||||
|
||||
# END Enum NWProjectState
|
||||
|
||||
|
||||
class NWProject:
|
||||
|
||||
@@ -461,14 +459,14 @@ class NWProject:
|
||||
|
||||
def setDefaultStatusImport(self) -> None:
|
||||
"""Set the default status and importance values."""
|
||||
self._data.itemStatus.write(None, self.tr("New"), (100, 100, 100))
|
||||
self._data.itemStatus.write(None, self.tr("Note"), (200, 50, 0))
|
||||
self._data.itemStatus.write(None, self.tr("Draft"), (200, 150, 0))
|
||||
self._data.itemStatus.write(None, self.tr("Finished"), (50, 200, 0))
|
||||
self._data.itemImport.write(None, self.tr("New"), (100, 100, 100))
|
||||
self._data.itemImport.write(None, self.tr("Minor"), (200, 50, 0))
|
||||
self._data.itemImport.write(None, self.tr("Major"), (200, 150, 0))
|
||||
self._data.itemImport.write(None, self.tr("Main"), (50, 200, 0))
|
||||
self._data.itemStatus.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
|
||||
self._data.itemStatus.add(None, self.tr("Note"), (200, 50, 0), "SQUARE", 0)
|
||||
self._data.itemStatus.add(None, self.tr("Draft"), (200, 150, 0), "SQUARE", 0)
|
||||
self._data.itemStatus.add(None, self.tr("Finished"), (50, 200, 0), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("New"), (100, 100, 100), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("Minor"), (200, 50, 0), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("Major"), (200, 150, 0), "SQUARE", 0)
|
||||
self._data.itemImport.add(None, self.tr("Main"), (50, 200, 0), "SQUARE", 0)
|
||||
return
|
||||
|
||||
def setProjectLang(self, language: str | None) -> None:
|
||||
@@ -491,14 +489,6 @@ class NWProject:
|
||||
self.setProjectChanged(True)
|
||||
return
|
||||
|
||||
def setStatusColours(self, new: list[dict], deleted: list[str]) -> bool:
|
||||
"""Update the list of novel file status flags."""
|
||||
return self._setStatusImport(new, deleted, self._data.itemStatus)
|
||||
|
||||
def setImportColours(self, new: list[dict], deleted: list[str]) -> bool:
|
||||
"""Update the list of note file importance flags."""
|
||||
return self._setStatusImport(new, deleted, self._data.itemImport)
|
||||
|
||||
def setProjectChanged(self, status: bool) -> bool:
|
||||
"""Toggle the project changed flag, and propagate the
|
||||
information to the GUI statusbar.
|
||||
@@ -584,28 +574,6 @@ class NWProject:
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _setStatusImport(self, new: list[dict], delete: list[str], target: NWStatus) -> bool:
|
||||
"""Update the list of novel file status or importance flags, and
|
||||
delete those that have been requested deleted.
|
||||
"""
|
||||
if not (new or delete):
|
||||
return False
|
||||
|
||||
order = []
|
||||
for entry in new:
|
||||
key = entry.get("key", None)
|
||||
name = entry.get("name", "")
|
||||
cols = entry.get("cols", (100, 100, 100))
|
||||
if name:
|
||||
order.append(target.write(key, name, cols))
|
||||
|
||||
for key in delete:
|
||||
target.remove(key)
|
||||
|
||||
target.reorder(order)
|
||||
|
||||
return True
|
||||
|
||||
def _loadProjectLocalisation(self) -> bool:
|
||||
"""Load the language data for the current project language."""
|
||||
if self._data.language is None or CONFIG._nwLangPath is None:
|
||||
@@ -626,5 +594,3 @@ class NWProject:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
# END Class NWProject
|
||||
|
||||
@@ -23,8 +23,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
import logging
|
||||
import uuid
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
@@ -322,5 +322,3 @@ class NWProjectData:
|
||||
self._autoReplace[key] = simplified(entry)
|
||||
self._project.setProjectChanged(True)
|
||||
return
|
||||
|
||||
# END Class NWProjectData
|
||||
|
||||
@@ -29,24 +29,24 @@ import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from enum import Enum
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
|
||||
from novelwriter import __version__, __hexversion__
|
||||
from novelwriter import __hexversion__, __version__
|
||||
from novelwriter.common import (
|
||||
checkBool, checkInt, checkString, checkStringNone, formatTimeStamp,
|
||||
hexToInt, simplified, xmlIndent, yesNo
|
||||
)
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.status import NWStatus
|
||||
from novelwriter.core.projectdata import NWProjectData
|
||||
from novelwriter.core.status import NWStatus
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
FILE_VERSION = "1.5" # The current project file format version
|
||||
FILE_REVISION = "3" # The current project file format revision
|
||||
FILE_REVISION = "4" # The current project file format revision
|
||||
HEX_VERSION = 0x0105
|
||||
|
||||
NUM_VERSION = {
|
||||
@@ -70,8 +70,6 @@ class XMLReadState(Enum):
|
||||
PARSED_OK = 5
|
||||
WAS_LEGACY = 6
|
||||
|
||||
# END Class XMLReadState
|
||||
|
||||
|
||||
class ProjectXMLReader:
|
||||
"""Core: Project XML Reader
|
||||
@@ -109,6 +107,8 @@ class ProjectXMLReader:
|
||||
Rev 2: Drops the title node from project and adds the TEMPLATE
|
||||
class for items. 2.3 Beta 1.
|
||||
Rev 3: Added TEMPLATE class. 2.3.
|
||||
Rev 4: Added shape attribute to status and importance entry
|
||||
nodes. 2.5.
|
||||
"""
|
||||
|
||||
def __init__(self, path: str | Path) -> None:
|
||||
@@ -356,8 +356,8 @@ class ProjectXMLReader:
|
||||
logger.debug("Parsing <content> section (legacy format)")
|
||||
|
||||
# Create maps to look up name -> key for status and importance
|
||||
statusMap = {entry.get("name"): key for key, entry in data.itemStatus.items()}
|
||||
importMap = {entry.get("name"): key for key, entry in data.itemImport.items()}
|
||||
sMap: dict[str | None, str] = {e.name: k for k, e in data.itemStatus.iterItems()}
|
||||
iMap: dict[str | None, str] = {e.name: k for k, e in data.itemImport.iterItems()}
|
||||
|
||||
for xItem in xSection:
|
||||
if xItem.tag != "item":
|
||||
@@ -404,9 +404,9 @@ class ProjectXMLReader:
|
||||
|
||||
# Status was split into separate status/import with a key in 1.4
|
||||
if item.get("class", "") in ("NOVEL", "ARCHIVE"):
|
||||
name["status"] = statusMap.get(tmpStatus, None)
|
||||
name["status"] = sMap.get(tmpStatus, None)
|
||||
else:
|
||||
name["import"] = importMap.get(tmpStatus, None)
|
||||
name["import"] = iMap.get(tmpStatus, None)
|
||||
|
||||
# A number of layouts were removed in 1.3
|
||||
if item.get("layout", "") in (
|
||||
@@ -436,7 +436,8 @@ class ProjectXMLReader:
|
||||
green = checkInt(xEntry.attrib.get("green", 0), 0)
|
||||
blue = checkInt(xEntry.attrib.get("blue", 0), 0)
|
||||
count = checkInt(xEntry.attrib.get("count", 0), 0)
|
||||
sObject.write(key, xEntry.text or "", (red, green, blue), count)
|
||||
shape = xEntry.attrib.get("shape", "")
|
||||
sObject.add(key, xEntry.text or "", (red, green, blue), shape, count)
|
||||
return
|
||||
|
||||
def _parseDictKeyText(self, xItem: ET.Element) -> dict:
|
||||
@@ -455,8 +456,6 @@ class ProjectXMLReader:
|
||||
"""
|
||||
return {xNode.tag: checkString(xNode.text, "") for xNode in xItem}
|
||||
|
||||
# END Class ProjectXMLReader
|
||||
|
||||
|
||||
class ProjectXMLWriter:
|
||||
"""Core: Project XML Writer
|
||||
@@ -576,5 +575,3 @@ class ProjectXMLWriter:
|
||||
xEntry = ET.SubElement(xItem, "entry", attrib={"key": key})
|
||||
xEntry.text = str(value) or ""
|
||||
return
|
||||
|
||||
# END Class ProjectXMLWriter
|
||||
|
||||
@@ -26,14 +26,14 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from collections.abc import Iterable
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
from collections.abc import Iterable
|
||||
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import formatTimeStamp
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
@@ -135,5 +135,3 @@ class NWSessionLog:
|
||||
"novel": novel, "notes": notes, "idle": idle,
|
||||
})
|
||||
return f"{data}\n"
|
||||
|
||||
# END Class NWSessionLog
|
||||
|
||||
@@ -27,14 +27,14 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
from collections.abc import Iterator
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import QLocale
|
||||
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
@@ -164,11 +164,10 @@ class NWSpellEnchant:
|
||||
name = ""
|
||||
return tag, name
|
||||
|
||||
# END Class NWSpellEnchant
|
||||
|
||||
|
||||
class FakeEnchant:
|
||||
"""Fallback for when Enchant is selected, but not installed."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
class FakeProvider:
|
||||
@@ -188,8 +187,6 @@ class FakeEnchant:
|
||||
def add_to_session(self, word: str) -> None:
|
||||
return
|
||||
|
||||
# END Class FakeEnchant
|
||||
|
||||
|
||||
class UserDictionary:
|
||||
|
||||
@@ -240,5 +237,3 @@ class UserDictionary:
|
||||
logger.error("Failed to save user dictionary")
|
||||
logException()
|
||||
return
|
||||
|
||||
# END Class UserDictionary
|
||||
|
||||
@@ -24,17 +24,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import dataclasses
|
||||
import logging
|
||||
import random
|
||||
|
||||
from collections.abc import Iterable
|
||||
from typing import TYPE_CHECKING, Literal
|
||||
from collections.abc import ItemsView, Iterable, Iterator, KeysView, ValuesView
|
||||
|
||||
from PyQt5.QtGui import QIcon, QPainter, QPainterPath, QPixmap, QColor
|
||||
from PyQt5.QtCore import QRectF
|
||||
from PyQt5.QtCore import QPointF, Qt
|
||||
from PyQt5.QtGui import QColor, QIcon, QPainter, QPainterPath, QPixmap, QPolygonF
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import minmax, simplified
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.common import simplified
|
||||
from novelwriter.enum import nwStatusShape
|
||||
from novelwriter.types import QtPaintAnitAlias, QtTransparent
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@@ -43,83 +45,92 @@ if TYPE_CHECKING: # pragma: no cover
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclasses.dataclass
|
||||
class StatusEntry:
|
||||
|
||||
name: str
|
||||
color: QColor
|
||||
shape: nwStatusShape
|
||||
icon: QIcon
|
||||
count: int = 0
|
||||
|
||||
@classmethod
|
||||
def duplicate(cls, source: StatusEntry) -> StatusEntry:
|
||||
"""Create a deep copy of the source object."""
|
||||
cls = dataclasses.replace(source)
|
||||
cls.color = QColor(source.color)
|
||||
cls.icon = QIcon(source.icon)
|
||||
return cls
|
||||
|
||||
|
||||
NO_ENTRY = StatusEntry("", QColor(0, 0, 0), nwStatusShape.SQUARE, QIcon(), 0)
|
||||
|
||||
|
||||
class NWStatus:
|
||||
|
||||
STATUS = 1
|
||||
IMPORT = 2
|
||||
STATUS = "s"
|
||||
IMPORT = "i"
|
||||
|
||||
def __init__(self, kind: Literal[1, 2]) -> None:
|
||||
__slots__ = ("_store", "_default", "_prefix", "_height")
|
||||
|
||||
self._type = kind
|
||||
self._store = {}
|
||||
def __init__(self, prefix: Literal["s", "i"]) -> None:
|
||||
self._store: dict[str, StatusEntry] = {}
|
||||
self._default = None
|
||||
|
||||
self._iPX = CONFIG.pxInt(24)
|
||||
|
||||
pA = CONFIG.pxInt(2)
|
||||
pB = CONFIG.pxInt(20)
|
||||
pR = float(CONFIG.pxInt(4))
|
||||
self._iconPath = QPainterPath()
|
||||
self._iconPath.addRoundedRect(QRectF(pA, pA, pB, pB), pR, pR)
|
||||
|
||||
self._defaultIcon = self._createIcon(100, 100, 100)
|
||||
|
||||
if self._type == self.STATUS:
|
||||
self._prefix = "s"
|
||||
elif self._type == self.IMPORT:
|
||||
self._prefix = "i"
|
||||
else:
|
||||
raise Exception("This is a bug!")
|
||||
|
||||
self._prefix = prefix[:1]
|
||||
self._height = SHARED.theme.baseIconHeight
|
||||
return
|
||||
|
||||
def write(self, key: str | None, name: str, col: tuple, count: int | None = None) -> str:
|
||||
def __len__(self) -> int:
|
||||
return len(self._store)
|
||||
|
||||
def __getitem__(self, key: str | None) -> StatusEntry:
|
||||
"""Return the entry associated with a given key."""
|
||||
if key and key in self._store:
|
||||
return self._store[key]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]
|
||||
return NO_ENTRY
|
||||
|
||||
##
|
||||
# Methods
|
||||
##
|
||||
|
||||
def add(self, key: str | None, name: str, color: tuple[int, int, int],
|
||||
shape: str, count: int) -> str:
|
||||
"""Add or update a status entry. If the key is invalid, a new
|
||||
key is generated.
|
||||
"""
|
||||
if not self._isKey(key):
|
||||
key = self._newKey()
|
||||
if not isinstance(col, tuple):
|
||||
col = (100, 100, 100)
|
||||
if len(col) != 3:
|
||||
col = (100, 100, 100)
|
||||
if isinstance(color, tuple) and len(color) == 3:
|
||||
qColor = QColor(*color)
|
||||
else:
|
||||
qColor = QColor(100, 100, 100)
|
||||
|
||||
cR = minmax(col[0], 0, 255)
|
||||
cG = minmax(col[1], 0, 255)
|
||||
cB = minmax(col[2], 0, 255)
|
||||
try:
|
||||
iShape = nwStatusShape[shape]
|
||||
except KeyError:
|
||||
iShape = nwStatusShape.SQUARE
|
||||
|
||||
key = self._checkKey(key)
|
||||
name = simplified(name)
|
||||
if count is None:
|
||||
count = self._store.get(key, {}).get("count", 0)
|
||||
|
||||
self._store[key] = {
|
||||
"name": name,
|
||||
"icon": self._createIcon(cR, cG, cB),
|
||||
"cols": (cR, cG, cB),
|
||||
"count": count,
|
||||
}
|
||||
icon = self.createIcon(self._height, qColor, iShape)
|
||||
self._store[key] = StatusEntry(name, qColor, iShape, icon, count)
|
||||
|
||||
if self._default is None:
|
||||
self._default = key
|
||||
|
||||
return key
|
||||
|
||||
def remove(self, key: str) -> bool:
|
||||
"""Remove an entry in the list, except if the count > 0."""
|
||||
if key not in self._store:
|
||||
return False
|
||||
if self._store[key]["count"] > 0:
|
||||
return False
|
||||
def update(self, update: list[tuple[str | None, StatusEntry]]) -> None:
|
||||
"""Update the list of statuses, and from removed list."""
|
||||
self._store.clear()
|
||||
for key, entry in update:
|
||||
self._store[self._checkKey(key)] = entry
|
||||
|
||||
del self._store[key]
|
||||
# Check if we need a new default
|
||||
if self._default not in self._store:
|
||||
self._default = next(iter(self._store)) if self._store else None
|
||||
|
||||
keys = list(self._store.keys())
|
||||
if key == self._default:
|
||||
if len(keys) > 0:
|
||||
self._default = keys[0]
|
||||
else:
|
||||
self._default = None
|
||||
|
||||
return True
|
||||
return
|
||||
|
||||
def check(self, value: str) -> str:
|
||||
"""Check the key against the stored status names."""
|
||||
@@ -129,93 +140,51 @@ class NWStatus:
|
||||
return self._default
|
||||
return ""
|
||||
|
||||
def name(self, key: str | None) -> str:
|
||||
"""Return the name associated with a given key."""
|
||||
if key and key in self._store:
|
||||
return self._store[key]["name"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["name"]
|
||||
return ""
|
||||
|
||||
def cols(self, key: str | None) -> tuple[int, int, int]:
|
||||
"""Return the colours associated with a given key."""
|
||||
if key and key in self._store:
|
||||
return self._store[key]["cols"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["cols"]
|
||||
return 100, 100, 100
|
||||
|
||||
def count(self, key: str | None) -> int:
|
||||
"""Return the count associated with a given key."""
|
||||
if key and key in self._store:
|
||||
return self._store[key]["count"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["count"]
|
||||
return 0
|
||||
|
||||
def icon(self, key: str | None) -> QIcon:
|
||||
"""Return the icon associated with a given key."""
|
||||
if key and key in self._store:
|
||||
return self._store[key]["icon"]
|
||||
elif self._default is not None:
|
||||
return self._store[self._default]["icon"]
|
||||
return self._defaultIcon
|
||||
|
||||
def reorder(self, order: list[str]) -> bool:
|
||||
"""Reorder the items according to list."""
|
||||
if len(order) != len(self._store):
|
||||
logger.error("Length mismatch between new and old order")
|
||||
return False
|
||||
|
||||
if order == list(self._store.keys()):
|
||||
return False
|
||||
|
||||
store = {}
|
||||
for key in order:
|
||||
if key in self._store:
|
||||
store[key] = self._store[key]
|
||||
else:
|
||||
logger.error("Unknown key '%s' in order", key)
|
||||
return False
|
||||
|
||||
self._store = store
|
||||
|
||||
return True
|
||||
|
||||
def resetCounts(self) -> None:
|
||||
"""Clear the counts of references to the status entries."""
|
||||
for key in self._store:
|
||||
self._store[key]["count"] = 0
|
||||
for entry in self._store.values():
|
||||
entry.count = 0
|
||||
return
|
||||
|
||||
def increment(self, key: str | None) -> None:
|
||||
"""Increment the counter for a given entry."""
|
||||
if key and key in self._store:
|
||||
self._store[key]["count"] += 1
|
||||
self._store[key].count += 1
|
||||
return
|
||||
|
||||
def pack(self) -> Iterable[tuple[str, dict]]:
|
||||
"""Pack the status entries into a dictionary."""
|
||||
for key, data in self._store.items():
|
||||
yield (data["name"], {
|
||||
for key, entry in self._store.items():
|
||||
yield (entry.name, {
|
||||
"key": key,
|
||||
"count": str(data["count"]),
|
||||
"red": str(data["cols"][0]),
|
||||
"green": str(data["cols"][1]),
|
||||
"blue": str(data["cols"][2]),
|
||||
"count": str(entry.count),
|
||||
"red": str(entry.color.red()),
|
||||
"green": str(entry.color.green()),
|
||||
"blue": str(entry.color.blue()),
|
||||
"shape": entry.shape.name,
|
||||
})
|
||||
return
|
||||
|
||||
def unpack(self, data: dict) -> None:
|
||||
"""Unpack a data dictionary and set the class values."""
|
||||
self._store = {}
|
||||
self._default = None
|
||||
for key, entry in data.items():
|
||||
label = entry.get("label", "")
|
||||
colour = entry.get("colour", (100, 100, 100))
|
||||
count = entry.get("count", 0)
|
||||
self.write(key, label, colour, count)
|
||||
return
|
||||
def iterItems(self) -> Iterable[tuple[str, StatusEntry]]:
|
||||
"""Yield entries from the status icons."""
|
||||
yield from self._store.items()
|
||||
|
||||
@staticmethod
|
||||
def createIcon(height: int, color: QColor, shape: nwStatusShape) -> QIcon:
|
||||
"""Generate an icon for a status label."""
|
||||
pixmap = QPixmap(48, 48)
|
||||
pixmap.fill(QtTransparent)
|
||||
|
||||
painter = QPainter(pixmap)
|
||||
painter.setRenderHint(QtPaintAnitAlias)
|
||||
painter.fillPath(_SHAPES.getShape(shape), color)
|
||||
painter.end()
|
||||
|
||||
return QIcon(pixmap.scaled(
|
||||
height, height,
|
||||
Qt.AspectRatioMode.IgnoreAspectRatio,
|
||||
Qt.TransformationMode.SmoothTransformation
|
||||
))
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
@@ -246,38 +215,116 @@ class NWStatus:
|
||||
return False
|
||||
return True
|
||||
|
||||
def _createIcon(self, red: int, green: int, blue: int) -> QIcon:
|
||||
"""Generate an icon for a status label."""
|
||||
pixmap = QPixmap(self._iPX, self._iPX)
|
||||
pixmap.fill(QtTransparent)
|
||||
def _checkKey(self, key: str | None) -> str:
|
||||
"""Check key is valid, and if not, generate one."""
|
||||
return key if self._isKey(key) else self._newKey()
|
||||
|
||||
painter = QPainter(pixmap)
|
||||
painter.setRenderHint(QtPaintAnitAlias)
|
||||
painter.fillPath(self._iconPath, QColor(red, green, blue))
|
||||
painter.end()
|
||||
|
||||
return QIcon(pixmap)
|
||||
class _ShapeCache:
|
||||
|
||||
##
|
||||
# Iterator Bits
|
||||
##
|
||||
def __init__(self) -> None:
|
||||
self._cache: dict[nwStatusShape, QPainterPath] = {}
|
||||
return
|
||||
|
||||
def __len__(self) -> int:
|
||||
return len(self._store)
|
||||
def getShape(self, shape: nwStatusShape) -> QPainterPath:
|
||||
"""Return a painter shape for an icon."""
|
||||
if shape in self._cache:
|
||||
return self._cache[shape]
|
||||
|
||||
def __getitem__(self, key: str) -> dict:
|
||||
return self._store[key]
|
||||
path = QPainterPath()
|
||||
if shape == nwStatusShape.SQUARE:
|
||||
path.addRoundedRect(2.0, 2.0, 44.0, 44.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.TRIANGLE:
|
||||
path.addPolygon(QPolygonF([
|
||||
QPointF(24.00, 3.00),
|
||||
QPointF(43.92, 37.50),
|
||||
QPointF(4.08, 37.50),
|
||||
]))
|
||||
elif shape == nwStatusShape.NABLA:
|
||||
path.addPolygon(QPolygonF([
|
||||
QPointF(24.00, 48.00),
|
||||
QPointF(4.08, 14.50),
|
||||
QPointF(43.92, 14.50),
|
||||
]))
|
||||
elif shape == nwStatusShape.DIAMOND:
|
||||
path.addPolygon(QPolygonF([
|
||||
QPointF(24.00, 2.00),
|
||||
QPointF(44.00, 24.00),
|
||||
QPointF(24.00, 46.00),
|
||||
QPointF(4.00, 24.00),
|
||||
]))
|
||||
elif shape == nwStatusShape.PENTAGON:
|
||||
path.addPolygon(QPolygonF([
|
||||
QPointF(24.00, 1.50),
|
||||
QPointF(45.87, 17.39),
|
||||
QPointF(37.52, 43.11),
|
||||
QPointF(10.48, 43.11),
|
||||
QPointF(2.13, 17.39),
|
||||
]))
|
||||
elif shape == nwStatusShape.HEXAGON:
|
||||
path.addPolygon(QPolygonF([
|
||||
QPointF(24.00, 1.50),
|
||||
QPointF(43.92, 13.00),
|
||||
QPointF(43.92, 36.00),
|
||||
QPointF(24.00, 47.50),
|
||||
QPointF(4.08, 36.00),
|
||||
QPointF(4.08, 13.00),
|
||||
]))
|
||||
elif shape == nwStatusShape.STAR:
|
||||
path.addPolygon(QPolygonF([
|
||||
QPointF(24.00, 0.50), QPointF(31.05, 14.79),
|
||||
QPointF(46.83, 17.08), QPointF(35.41, 28.21),
|
||||
QPointF(38.11, 43.92), QPointF(24.00, 36.50),
|
||||
QPointF(9.89, 43.92), QPointF(12.59, 28.21),
|
||||
QPointF(1.17, 17.08), QPointF(15.37, 16.16),
|
||||
]))
|
||||
elif shape == nwStatusShape.PACMAN:
|
||||
path.moveTo(24.0, 24.0)
|
||||
path.arcTo(2.0, 2.0, 44.0, 44.0, 40.0, 280.0)
|
||||
elif shape == nwStatusShape.CIRCLE_Q:
|
||||
path.moveTo(24.0, 24.0)
|
||||
path.arcTo(2.0, 2.0, 44.0, 44.0, 0.0, 90.0)
|
||||
elif shape == nwStatusShape.CIRCLE_H:
|
||||
path.moveTo(24.0, 24.0)
|
||||
path.arcTo(2.0, 2.0, 44.0, 44.0, -90.0, 180.0)
|
||||
elif shape == nwStatusShape.CIRCLE_T:
|
||||
path.moveTo(24.0, 24.0)
|
||||
path.arcTo(2.0, 2.0, 44.0, 44.0, -180.0, 270.0)
|
||||
elif shape == nwStatusShape.CIRCLE:
|
||||
path.addEllipse(2.0, 2.0, 44.0, 44.0)
|
||||
elif shape == nwStatusShape.BARS_1:
|
||||
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.BARS_2:
|
||||
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
path.addRoundedRect(14.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.BARS_3:
|
||||
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
path.addRoundedRect(14.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
path.addRoundedRect(26.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.BARS_4:
|
||||
path.addRoundedRect(2.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
path.addRoundedRect(14.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
path.addRoundedRect(26.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
path.addRoundedRect(38.0, 2.0, 8.0, 44.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.BLOCK_1:
|
||||
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.BLOCK_2:
|
||||
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
|
||||
path.addRoundedRect(24.0, 2.0, 20.0, 20.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.BLOCK_3:
|
||||
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
|
||||
path.addRoundedRect(2.0, 24.0, 20.0, 20.0, 4.0, 4.0)
|
||||
path.addRoundedRect(24.0, 2.0, 20.0, 20.0, 4.0, 4.0)
|
||||
elif shape == nwStatusShape.BLOCK_4:
|
||||
path.addRoundedRect(2.0, 2.0, 20.0, 20.0, 4.0, 4.0)
|
||||
path.addRoundedRect(2.0, 24.0, 20.0, 20.0, 4.0, 4.0)
|
||||
path.addRoundedRect(24.0, 2.0, 20.0, 20.0, 4.0, 4.0)
|
||||
path.addRoundedRect(24.0, 24.0, 20.0, 20.0, 4.0, 4.0)
|
||||
|
||||
def __iter__(self) -> Iterator[dict]:
|
||||
return iter(self._store)
|
||||
self._cache[shape] = path
|
||||
|
||||
def keys(self) -> KeysView[str]:
|
||||
return self._store.keys()
|
||||
return path
|
||||
|
||||
def items(self) -> ItemsView[str, dict]:
|
||||
return self._store.items()
|
||||
|
||||
def values(self) -> ValuesView[dict]:
|
||||
return self._store.values()
|
||||
|
||||
# END Class NWStatus
|
||||
# Create Singleton
|
||||
_SHAPES = _ShapeCache()
|
||||
|
||||
@@ -54,8 +54,6 @@ class NWStorageOpen(Enum):
|
||||
FAILED = 3
|
||||
READY = 4
|
||||
|
||||
# END Enum NWStorageOpen
|
||||
|
||||
|
||||
class NWStorageCreate(Enum):
|
||||
|
||||
@@ -63,8 +61,6 @@ class NWStorageCreate(Enum):
|
||||
OS_ERROR = 1
|
||||
READY = 2
|
||||
|
||||
# END Enum NWStorageCreate
|
||||
|
||||
|
||||
class NWStorage:
|
||||
"""Core: Project Storage Class
|
||||
@@ -391,8 +387,6 @@ class NWStorage:
|
||||
self._lockedBy = None
|
||||
return True
|
||||
|
||||
# END Class NWStorage
|
||||
|
||||
|
||||
class _LegacyStorage:
|
||||
"""Core: Legacy Storage Converter Utils
|
||||
@@ -590,5 +584,3 @@ class _LegacyStorage:
|
||||
logException()
|
||||
|
||||
return
|
||||
|
||||
# END Class _LegacyStorage
|
||||
|
||||
@@ -26,17 +26,36 @@ from __future__ import annotations
|
||||
import json
|
||||
import logging
|
||||
|
||||
from time import time
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.common import formatTimeStamp
|
||||
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels, nwHtmlUnicode
|
||||
from novelwriter.constants import nwHeadFmt, nwHtmlUnicode, nwKeyWords, nwLabels
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer, stripEscape
|
||||
from novelwriter.core.tokenizer import T_Formats, Tokenizer, stripEscape
|
||||
from novelwriter.types import FONT_STYLE, FONT_WEIGHTS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
HTML5_TAGS = {
|
||||
Tokenizer.FMT_B_B: "<strong>",
|
||||
Tokenizer.FMT_B_E: "</strong>",
|
||||
Tokenizer.FMT_I_B: "<em>",
|
||||
Tokenizer.FMT_I_E: "</em>",
|
||||
Tokenizer.FMT_D_B: "<del>",
|
||||
Tokenizer.FMT_D_E: "</del>",
|
||||
Tokenizer.FMT_U_B: "<span style='text-decoration: underline;'>",
|
||||
Tokenizer.FMT_U_E: "</span>",
|
||||
Tokenizer.FMT_M_B: "<mark>",
|
||||
Tokenizer.FMT_M_E: "</mark>",
|
||||
Tokenizer.FMT_SUP_B: "<sup>",
|
||||
Tokenizer.FMT_SUP_E: "</sup>",
|
||||
Tokenizer.FMT_SUB_B: "<sub>",
|
||||
Tokenizer.FMT_SUB_E: "</sub>",
|
||||
Tokenizer.FMT_STRIP: "",
|
||||
}
|
||||
|
||||
|
||||
class ToHtml(Tokenizer):
|
||||
"""Core: HTML Document Writer
|
||||
@@ -45,19 +64,15 @@ class ToHtml(Tokenizer):
|
||||
also used by the Document Viewer, and Manuscript Build Preview.
|
||||
"""
|
||||
|
||||
M_PREVIEW = 0 # Tweak output for the DocViewer
|
||||
M_EXPORT = 1 # Tweak output for saving to HTML or printing
|
||||
M_EBOOK = 2 # Tweak output for converting to epub
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
super().__init__(project)
|
||||
|
||||
self._genMode = self.M_EXPORT
|
||||
self._cssStyles = True
|
||||
self._fullHTML: list[str] = []
|
||||
|
||||
# Internals
|
||||
self._trMap = {}
|
||||
self._usedNotes: dict[str, int] = {}
|
||||
self.setReplaceUnicode(False)
|
||||
|
||||
return
|
||||
@@ -74,11 +89,6 @@ class ToHtml(Tokenizer):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setPreview(self, state: bool) -> None:
|
||||
"""Set to preview generator mode."""
|
||||
self._genMode = self.M_PREVIEW if state else self.M_EXPORT
|
||||
return
|
||||
|
||||
def setStyles(self, cssStyles: bool) -> None:
|
||||
"""Enable or disable CSS styling. Some elements may still have
|
||||
class tags.
|
||||
@@ -117,39 +127,9 @@ class ToHtml(Tokenizer):
|
||||
|
||||
def doConvert(self) -> None:
|
||||
"""Convert the list of text tokens into an HTML document."""
|
||||
if self._genMode == self.M_PREVIEW:
|
||||
htmlTags = { # HTML4 + CSS2 (for Qt)
|
||||
self.FMT_B_B: "<b>",
|
||||
self.FMT_B_E: "</b>",
|
||||
self.FMT_I_B: "<i>",
|
||||
self.FMT_I_E: "</i>",
|
||||
self.FMT_D_B: "<span style='text-decoration: line-through;'>",
|
||||
self.FMT_D_E: "</span>",
|
||||
self.FMT_U_B: "<u>",
|
||||
self.FMT_U_E: "</u>",
|
||||
self.FMT_M_B: "<mark>",
|
||||
self.FMT_M_E: "</mark>",
|
||||
}
|
||||
else:
|
||||
htmlTags = { # HTML5 (for export)
|
||||
self.FMT_B_B: "<strong>",
|
||||
self.FMT_B_E: "</strong>",
|
||||
self.FMT_I_B: "<em>",
|
||||
self.FMT_I_E: "</em>",
|
||||
self.FMT_D_B: "<del>",
|
||||
self.FMT_D_E: "</del>",
|
||||
self.FMT_U_B: "<span style='text-decoration: underline;'>",
|
||||
self.FMT_U_E: "</span>",
|
||||
self.FMT_M_B: "<mark>",
|
||||
self.FMT_M_E: "</mark>",
|
||||
}
|
||||
self._result = ""
|
||||
|
||||
htmlTags[self.FMT_SUP_B] = "<sup>"
|
||||
htmlTags[self.FMT_SUP_E] = "</sup>"
|
||||
htmlTags[self.FMT_SUB_B] = "<sub>"
|
||||
htmlTags[self.FMT_SUB_E] = "</sub>"
|
||||
|
||||
if self._isNovel and self._genMode != self.M_PREVIEW:
|
||||
if self._isNovel:
|
||||
# For story files, we bump the titles one level up
|
||||
h1Cl = " class='title'"
|
||||
h1 = "h1"
|
||||
@@ -163,12 +143,7 @@ class ToHtml(Tokenizer):
|
||||
h3 = "h3"
|
||||
h4 = "h4"
|
||||
|
||||
self._result = ""
|
||||
|
||||
para = []
|
||||
pStyle = None
|
||||
lines = []
|
||||
|
||||
tHandle = self._handle
|
||||
|
||||
for tType, nHead, tText, tFormat, tStyle in self._tokens:
|
||||
@@ -181,11 +156,11 @@ class ToHtml(Tokenizer):
|
||||
for c in tText:
|
||||
if c == "<":
|
||||
cText.append("<")
|
||||
tFormat = [[p + 3 if p > i else p, f] for p, f in tFormat]
|
||||
tFormat = [(p + 3 if p > i else p, f, k) for p, f, k in tFormat]
|
||||
i += 4
|
||||
elif c == ">":
|
||||
cText.append(">")
|
||||
tFormat = [[p + 3 if p > i else p, f] for p, f in tFormat]
|
||||
tFormat = [(p + 3 if p > i else p, f, k) for p, f, k in tFormat]
|
||||
i += 4
|
||||
else:
|
||||
cText.append(c)
|
||||
@@ -235,37 +210,27 @@ class ToHtml(Tokenizer):
|
||||
aNm = ""
|
||||
|
||||
# Process Text Type
|
||||
if tType == self.T_EMPTY:
|
||||
if pStyle is None:
|
||||
pStyle = ""
|
||||
if len(para) > 1 and self._cssStyles:
|
||||
pClass = " class='break'"
|
||||
else:
|
||||
pClass = ""
|
||||
if len(para) > 0:
|
||||
tTemp = "<br/>".join(para)
|
||||
lines.append(f"<p{pClass+pStyle}>{tTemp.rstrip()}</p>\n")
|
||||
para = []
|
||||
pStyle = None
|
||||
if tType == self.T_TEXT:
|
||||
lines.append(f"<p{hStyle}>{self._formatText(tText, tFormat)}</p>\n")
|
||||
|
||||
elif tType == self.T_TITLE:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br>")
|
||||
lines.append(f"<h1 class='title'{hStyle}>{aNm}{tHead}</h1>\n")
|
||||
|
||||
elif tType == self.T_HEAD1:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br>")
|
||||
lines.append(f"<{h1}{h1Cl}{hStyle}>{aNm}{tHead}</{h1}>\n")
|
||||
|
||||
elif tType == self.T_HEAD2:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br>")
|
||||
lines.append(f"<{h2}{hStyle}>{aNm}{tHead}</{h2}>\n")
|
||||
|
||||
elif tType == self.T_HEAD3:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br>")
|
||||
lines.append(f"<{h3}{hStyle}>{aNm}{tHead}</{h3}>\n")
|
||||
|
||||
elif tType == self.T_HEAD4:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br/>")
|
||||
tHead = tText.replace(nwHeadFmt.BR, "<br>")
|
||||
lines.append(f"<{h4}{hStyle}>{aNm}{tHead}</{h4}>\n")
|
||||
|
||||
elif tType == self.T_SEP:
|
||||
@@ -274,22 +239,14 @@ class ToHtml(Tokenizer):
|
||||
elif tType == self.T_SKIP:
|
||||
lines.append(f"<p class='skip'{hStyle}> </p>\n")
|
||||
|
||||
elif tType == self.T_TEXT:
|
||||
tTemp = tText
|
||||
if pStyle is None:
|
||||
pStyle = hStyle
|
||||
for pos, fmt in reversed(tFormat):
|
||||
tTemp = f"{tTemp[:pos]}{htmlTags[fmt]}{tTemp[pos:]}"
|
||||
para.append(stripEscape(tTemp.rstrip()))
|
||||
|
||||
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||
lines.append(self._formatSynopsis(tText, True))
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), True))
|
||||
|
||||
elif tType == self.T_SHORT and self._doSynopsis:
|
||||
lines.append(self._formatSynopsis(tText, False))
|
||||
lines.append(self._formatSynopsis(self._formatText(tText, tFormat), False))
|
||||
|
||||
elif tType == self.T_COMMENT and self._doComments:
|
||||
lines.append(self._formatComments(tText))
|
||||
lines.append(self._formatComments(self._formatText(tText, tFormat)))
|
||||
|
||||
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||
tag, text = self._formatKeywords(tText)
|
||||
@@ -302,6 +259,26 @@ class ToHtml(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def appendFootnotes(self) -> None:
|
||||
"""Append the footnotes in the buffer."""
|
||||
if self._usedNotes:
|
||||
footnotes = self._localLookup("Footnotes")
|
||||
|
||||
lines = []
|
||||
lines.append(f"<h3>{footnotes}</h3>\n")
|
||||
lines.append("<ol>\n")
|
||||
for key, index in self._usedNotes.items():
|
||||
if content := self._footnotes.get(key):
|
||||
text = self._formatText(*content)
|
||||
lines.append(f"<li id='footnote_{index}'><p>{text}</p></li>\n")
|
||||
lines.append("</ol>\n")
|
||||
|
||||
result = "".join(lines)
|
||||
self._result += result
|
||||
self._fullHTML.append(result)
|
||||
|
||||
return
|
||||
|
||||
def saveHtml5(self, path: str | Path) -> None:
|
||||
"""Save the data to an HTML file."""
|
||||
with open(path, mode="w", encoding="utf-8") as fObj:
|
||||
@@ -367,8 +344,16 @@ class ToHtml(Tokenizer):
|
||||
mScale = self._lineHeight/1.15
|
||||
|
||||
styles = []
|
||||
styles.append("body {{font-family: '{0:s}'; font-size: {1:d}pt;}}".format(
|
||||
self._textFont, self._textSize
|
||||
font = self._textFont
|
||||
styles.append((
|
||||
"body {{"
|
||||
"font-family: '{0:s}'; font-size: {1:d}pt; "
|
||||
"font-weight: {2:d}; font-style: {3:s};"
|
||||
"}}"
|
||||
).format(
|
||||
font.family(), font.pointSize(),
|
||||
FONT_WEIGHTS.get(font.weight(), 400),
|
||||
FONT_STYLE.get(font.style(), "normal"),
|
||||
))
|
||||
styles.append((
|
||||
"p {{"
|
||||
@@ -442,7 +427,7 @@ class ToHtml(Tokenizer):
|
||||
|
||||
styles.append("a {color: rgb(66, 113, 174);}")
|
||||
styles.append("mark {background: rgb(255, 255, 166);}")
|
||||
styles.append(".tags {color: rgb(245, 135, 31); font-weight: bold;}")
|
||||
styles.append(".keyword {color: rgb(245, 135, 31); font-weight: bold;}")
|
||||
styles.append(".break {text-align: left;}")
|
||||
styles.append(".synopsis {font-style: italic;}")
|
||||
styles.append(".comment {font-style: italic; color: rgb(100, 100, 100);}")
|
||||
@@ -453,24 +438,36 @@ class ToHtml(Tokenizer):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatText(self, text: str, tFmt: T_Formats) -> str:
|
||||
"""Apply formatting tags to text."""
|
||||
temp = text
|
||||
for pos, fmt, data in reversed(tFmt):
|
||||
html = ""
|
||||
if fmt == self.FMT_FNOTE:
|
||||
if data in self._footnotes:
|
||||
index = len(self._usedNotes) + 1
|
||||
self._usedNotes[data] = index
|
||||
html = f"<sup><a href='#footnote_{index}'>{index}</a></sup>"
|
||||
else:
|
||||
html = "<sup>ERR</sup>"
|
||||
else:
|
||||
html = HTML5_TAGS.get(fmt, "ERR")
|
||||
temp = f"{temp[:pos]}{html}{temp[pos:]}"
|
||||
temp = temp.replace("\n", "<br>")
|
||||
return stripEscape(temp)
|
||||
|
||||
def _formatSynopsis(self, text: str, synopsis: bool) -> str:
|
||||
"""Apply HTML formatting to synopsis."""
|
||||
if synopsis:
|
||||
sSynop = self._localLookup("Synopsis")
|
||||
else:
|
||||
sSynop = self._localLookup("Short Description")
|
||||
if self._genMode == self.M_PREVIEW:
|
||||
return f"<p class='comment'><span class='synopsis'>{sSynop}:</span> {text}</p>\n"
|
||||
else:
|
||||
return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
|
||||
return f"<p class='synopsis'><strong>{sSynop}:</strong> {text}</p>\n"
|
||||
|
||||
def _formatComments(self, text: str) -> str:
|
||||
"""Apply HTML formatting to comments."""
|
||||
if self._genMode == self.M_PREVIEW:
|
||||
return f"<p class='comment'>{text}</p>\n"
|
||||
else:
|
||||
sComm = self._localLookup("Comment")
|
||||
return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
|
||||
sComm = self._localLookup("Comment")
|
||||
return f"<p class='comment'><strong>{sComm}:</strong> {text}</p>\n"
|
||||
|
||||
def _formatKeywords(self, text: str) -> tuple[str, str]:
|
||||
"""Apply HTML formatting to keywords."""
|
||||
@@ -478,19 +475,16 @@ class ToHtml(Tokenizer):
|
||||
if not valid or not bits or bits[0] not in nwLabels.KEY_NAME:
|
||||
return "", ""
|
||||
|
||||
result = f"<span class='tags'>{self._localLookup(nwLabels.KEY_NAME[bits[0]])}:</span> "
|
||||
result = f"<span class='keyword'>{self._localLookup(nwLabels.KEY_NAME[bits[0]])}:</span> "
|
||||
if len(bits) > 1:
|
||||
if bits[0] == nwKeyWords.TAG_KEY:
|
||||
one, two = self._project.index.parseValue(bits[1])
|
||||
result += f"<a name='tag_{one}'>{one}</a>"
|
||||
result += f"<a class='tag' name='tag_{one}'>{one}</a>"
|
||||
if two:
|
||||
result += f" | <span class='optional'>{two}</a>"
|
||||
else:
|
||||
if self._genMode == self.M_PREVIEW:
|
||||
result += ", ".join(f"<a href='#{bits[0][1:]}={t}'>{t}</a>" for t in bits[1:])
|
||||
else:
|
||||
result += ", ".join(f"<a href='#tag_{t}'>{t}</a>" for t in bits[1:])
|
||||
result += ", ".join(
|
||||
f"<a class='tag' href='#tag_{t}'>{t}</a>" for t in bits[1:]
|
||||
)
|
||||
|
||||
return bits[0][1:], result
|
||||
|
||||
# END Class ToHtml
|
||||
|
||||
@@ -24,18 +24,19 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import re
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
|
||||
from abc import ABC, abstractmethod
|
||||
from time import time
|
||||
from pathlib import Path
|
||||
from functools import partial
|
||||
from pathlib import Path
|
||||
from time import time
|
||||
|
||||
from PyQt5.QtCore import QCoreApplication, QRegularExpression
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
from novelwriter.common import formatTimeStamp, numberToRoman, checkInt
|
||||
from novelwriter.common import checkInt, formatTimeStamp, numberToRoman
|
||||
from novelwriter.constants import (
|
||||
nwHeadFmt, nwKeyWords, nwLabels, nwRegEx, nwShortcode, nwUnicode, trConst
|
||||
)
|
||||
@@ -48,6 +49,10 @@ logger = logging.getLogger(__name__)
|
||||
ESCAPES = {r"\*": "*", r"\~": "~", r"\_": "_", r"\[": "[", r"\]": "]", r"\ ": ""}
|
||||
RX_ESC = re.compile("|".join([re.escape(k) for k in ESCAPES.keys()]), flags=re.DOTALL)
|
||||
|
||||
T_Formats = list[tuple[int, int, str]]
|
||||
T_Comment = tuple[str, T_Formats]
|
||||
T_Token = tuple[int, int, str, T_Formats, int]
|
||||
|
||||
|
||||
def stripEscape(text: str) -> str:
|
||||
"""Strip escaped Markdown characters from paragraph text."""
|
||||
@@ -80,6 +85,8 @@ class Tokenizer(ABC):
|
||||
FMT_SUP_E = 12 # End superscript
|
||||
FMT_SUB_B = 13 # Begin subscript
|
||||
FMT_SUB_E = 14 # End subscript
|
||||
FMT_FNOTE = 15 # Footnote marker
|
||||
FMT_STRIP = 16 # Strip the format code
|
||||
|
||||
# Block Type
|
||||
T_EMPTY = 1 # Empty line (new paragraph)
|
||||
@@ -111,45 +118,53 @@ class Tokenizer(ABC):
|
||||
|
||||
# Lookups
|
||||
L_HEADINGS = [T_TITLE, T_HEAD1, T_HEAD2, T_HEAD3, T_HEAD4]
|
||||
L_SKIP_INDENT = [T_TITLE, T_HEAD1, T_HEAD2, T_HEAD2, T_HEAD3, T_HEAD4, T_SEP, T_SKIP]
|
||||
L_SUMMARY = [T_SYNOPSIS, T_SHORT]
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
|
||||
self._project = project
|
||||
|
||||
# Data Variables
|
||||
self._text = "" # The raw text to be tokenized
|
||||
self._handle = None # The item handle currently being processed
|
||||
self._result = "" # The result of the last document
|
||||
self._text = "" # The raw text to be tokenized
|
||||
self._handle = None # The item handle currently being processed
|
||||
self._result = "" # The result of the last document
|
||||
self._keepMD = False # Whether to keep the markdown text
|
||||
|
||||
self._keepMarkdown = False # Whether to keep the markdown text
|
||||
self._allMarkdown = [] # The result novelWriter markdown of all documents
|
||||
# Tokens and Meta Data (Per Document)
|
||||
self._tokens: list[T_Token] = []
|
||||
self._footnotes: dict[str, T_Comment] = {}
|
||||
|
||||
# Processed Tokens and Meta Data
|
||||
self._tokens: list[tuple[int, int, str, list[tuple[int, int]], int]] = []
|
||||
# Tokens and Meta Data (Per Instance)
|
||||
self._counts: dict[str, int] = {}
|
||||
self._outline: dict[str, str] = {}
|
||||
self._markdown: list[str] = []
|
||||
|
||||
# User Settings
|
||||
self._textFont = "Serif" # Output text font
|
||||
self._textSize = 11 # Output text size
|
||||
self._textFixed = False # Fixed width text
|
||||
self._textFont = QFont("Serif", 11) # Output text font
|
||||
self._lineHeight = 1.15 # Line height in units of em
|
||||
self._blockIndent = 4.00 # Block indent in units of em
|
||||
self._firstIndent = False # Enable first line indent
|
||||
self._firstWidth = 1.40 # First line indent in units of em
|
||||
self._indentFirst = False # Indent first paragraph
|
||||
self._doJustify = False # Justify text
|
||||
self._doBodyText = True # Include body text
|
||||
self._doSynopsis = False # Also process synopsis comments
|
||||
self._doComments = False # Also process comments
|
||||
self._doKeywords = False # Also process keywords like tags and references
|
||||
self._skipKeywords = set() # Keywords to ignore
|
||||
self._keepBreaks = True # Keep line breaks in paragraphs
|
||||
|
||||
# Margins
|
||||
self._marginTitle = (1.000, 0.500)
|
||||
self._marginHead1 = (1.000, 0.500)
|
||||
self._marginHead2 = (0.834, 0.500)
|
||||
self._marginHead3 = (0.584, 0.500)
|
||||
self._marginHead4 = (0.584, 0.500)
|
||||
self._marginTitle = (1.417, 0.500)
|
||||
self._marginHead1 = (1.417, 0.500)
|
||||
self._marginHead2 = (1.668, 0.500)
|
||||
self._marginHead3 = (1.168, 0.500)
|
||||
self._marginHead4 = (1.168, 0.500)
|
||||
self._marginText = (0.000, 0.584)
|
||||
self._marginMeta = (0.000, 0.584)
|
||||
self._marginFoot = (1.417, 0.467)
|
||||
self._marginSep = (1.168, 1.168)
|
||||
|
||||
# Title Formats
|
||||
self._fmtTitle = nwHeadFmt.TITLE # Formatting for titles
|
||||
@@ -205,6 +220,9 @@ class Tokenizer(ABC):
|
||||
nwShortcode.SUP_O: self.FMT_SUP_B, nwShortcode.SUP_C: self.FMT_SUP_E,
|
||||
nwShortcode.SUB_O: self.FMT_SUB_B, nwShortcode.SUB_C: self.FMT_SUB_E,
|
||||
}
|
||||
self._shortCodeVals = {
|
||||
nwShortcode.FOOTNOTE_B: self.FMT_FNOTE,
|
||||
}
|
||||
|
||||
return
|
||||
|
||||
@@ -220,7 +238,7 @@ class Tokenizer(ABC):
|
||||
@property
|
||||
def allMarkdown(self) -> list[str]:
|
||||
"""The combined novelWriter Markdown text."""
|
||||
return self._allMarkdown
|
||||
return self._markdown
|
||||
|
||||
@property
|
||||
def textStats(self) -> dict[str, int]:
|
||||
@@ -298,11 +316,9 @@ class Tokenizer(ABC):
|
||||
)
|
||||
return
|
||||
|
||||
def setFont(self, family: str, size: int, isFixed: bool = False) -> None:
|
||||
def setFont(self, font: QFont) -> None:
|
||||
"""Set the build font."""
|
||||
self._textFont = family
|
||||
self._textSize = round(int(size))
|
||||
self._textFixed = isFixed
|
||||
self._textFont = font
|
||||
return
|
||||
|
||||
def setLineHeight(self, height: float) -> None:
|
||||
@@ -315,6 +331,15 @@ class Tokenizer(ABC):
|
||||
self._blockIndent = min(max(float(indent), 0.0), 10.0)
|
||||
return
|
||||
|
||||
def setFirstLineIndent(self, state: bool, indent: float, first: bool) -> None:
|
||||
"""Set first line indent and whether to also indent first
|
||||
paragraph after a heading.
|
||||
"""
|
||||
self._firstIndent = state
|
||||
self._firstWidth = indent
|
||||
self._indentFirst = first
|
||||
return
|
||||
|
||||
def setJustify(self, state: bool) -> None:
|
||||
"""Enable or disable text justification."""
|
||||
self._doJustify = state
|
||||
@@ -355,6 +380,11 @@ class Tokenizer(ABC):
|
||||
self._marginMeta = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setSeparatorMargins(self, upper: float, lower: float) -> None:
|
||||
"""Set the upper and lower meta text margin."""
|
||||
self._marginSep = (float(upper), float(lower))
|
||||
return
|
||||
|
||||
def setLinkHeadings(self, state: bool) -> None:
|
||||
"""Enable or disable adding an anchor before headings."""
|
||||
self._linkHeadings = state
|
||||
@@ -385,9 +415,14 @@ class Tokenizer(ABC):
|
||||
self._skipKeywords = set(x.lower().strip() for x in keywords.split(","))
|
||||
return
|
||||
|
||||
def setKeepLineBreaks(self, state: bool) -> None:
|
||||
"""Keep line breaks in paragraphs."""
|
||||
self._keepBreaks = state
|
||||
return
|
||||
|
||||
def setKeepMarkdown(self, state: bool) -> None:
|
||||
"""Keep original markdown during build."""
|
||||
self._keepMarkdown = state
|
||||
self._keepMD = state
|
||||
return
|
||||
|
||||
##
|
||||
@@ -417,8 +452,8 @@ class Tokenizer(ABC):
|
||||
self._tokens.append((
|
||||
self.T_TITLE, 1, title, [], textAlign
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
self._allMarkdown.append(f"#! {title}\n\n")
|
||||
if self._keepMD:
|
||||
self._markdown.append(f"#! {title}\n\n")
|
||||
|
||||
return
|
||||
|
||||
@@ -466,22 +501,23 @@ class Tokenizer(ABC):
|
||||
4: The internal formatting map of the text, self.FMT_*
|
||||
5: The style of the block, self.A_*
|
||||
"""
|
||||
self._tokens = []
|
||||
if self._isNovel:
|
||||
self._hFormatter.setHandle(self._handle)
|
||||
|
||||
nHead = 0
|
||||
breakNext = False
|
||||
tmpMarkdown = []
|
||||
tHandle = self._handle or ""
|
||||
tokens: list[T_Token] = []
|
||||
for aLine in self._text.splitlines():
|
||||
sLine = aLine.strip().lower()
|
||||
|
||||
# Check for blank lines
|
||||
if len(sLine) == 0:
|
||||
self._tokens.append((
|
||||
tokens.append((
|
||||
self.T_EMPTY, nHead, "", [], self.A_NONE
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append("\n")
|
||||
|
||||
continue
|
||||
@@ -507,7 +543,7 @@ class Tokenizer(ABC):
|
||||
continue
|
||||
|
||||
elif sLine == "[vspace]":
|
||||
self._tokens.append(
|
||||
tokens.append(
|
||||
(self.T_SKIP, nHead, "", [], sAlign)
|
||||
)
|
||||
continue
|
||||
@@ -515,11 +551,11 @@ class Tokenizer(ABC):
|
||||
elif sLine.startswith("[vspace:") and sLine.endswith("]"):
|
||||
nSkip = checkInt(sLine[8:-1], 0)
|
||||
if nSkip >= 1:
|
||||
self._tokens.append(
|
||||
tokens.append(
|
||||
(self.T_SKIP, nHead, "", [], sAlign)
|
||||
)
|
||||
if nSkip > 1:
|
||||
self._tokens += (nSkip - 1) * [
|
||||
tokens += (nSkip - 1) * [
|
||||
(self.T_SKIP, nHead, "", [], self.A_NONE)
|
||||
]
|
||||
continue
|
||||
@@ -533,24 +569,32 @@ class Tokenizer(ABC):
|
||||
if aLine.startswith("%~"):
|
||||
continue
|
||||
|
||||
cStyle, cText, _ = processComment(aLine)
|
||||
cStyle, cKey, cText, _, _ = processComment(aLine)
|
||||
if cStyle == nwComment.SYNOPSIS:
|
||||
self._tokens.append((
|
||||
self.T_SYNOPSIS, nHead, cText, [], sAlign
|
||||
tLine, tFmt = self._extractFormats(cText)
|
||||
tokens.append((
|
||||
self.T_SYNOPSIS, nHead, tLine, tFmt, sAlign
|
||||
))
|
||||
if self._doSynopsis and self._keepMarkdown:
|
||||
if self._doSynopsis and self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
elif cStyle == nwComment.SHORT:
|
||||
self._tokens.append((
|
||||
self.T_SHORT, nHead, cText, [], sAlign
|
||||
tLine, tFmt = self._extractFormats(cText)
|
||||
tokens.append((
|
||||
self.T_SHORT, nHead, tLine, tFmt, sAlign
|
||||
))
|
||||
if self._doSynopsis and self._keepMarkdown:
|
||||
if self._doSynopsis and self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
elif cStyle == nwComment.FOOTNOTE:
|
||||
tLine, tFmt = self._extractFormats(cText, skip=self.FMT_FNOTE)
|
||||
self._footnotes[f"{tHandle}:{cKey}"] = (tLine, tFmt)
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
else:
|
||||
self._tokens.append((
|
||||
self.T_COMMENT, nHead, cText, [], sAlign
|
||||
tLine, tFmt = self._extractFormats(cText)
|
||||
tokens.append((
|
||||
self.T_COMMENT, nHead, tLine, tFmt, sAlign
|
||||
))
|
||||
if self._doComments and self._keepMarkdown:
|
||||
if self._doComments and self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
elif aLine.startswith("@"):
|
||||
@@ -560,11 +604,14 @@ class Tokenizer(ABC):
|
||||
# are automatically skipped.
|
||||
|
||||
valid, bits, _ = self._project.index.scanThis(aLine)
|
||||
if valid and bits and bits[0] not in self._skipKeywords:
|
||||
self._tokens.append((
|
||||
if (
|
||||
valid and bits and bits[0] in nwLabels.KEY_NAME
|
||||
and bits[0] not in self._skipKeywords
|
||||
):
|
||||
tokens.append((
|
||||
self.T_KEYWORD, nHead, aLine[1:].strip(), [], sAlign
|
||||
))
|
||||
if self._doKeywords and self._keepMarkdown:
|
||||
if self._doKeywords and self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
elif aLine.startswith(("# ", "#! ")):
|
||||
@@ -597,10 +644,10 @@ class Tokenizer(ABC):
|
||||
self._hFormatter.resetAll()
|
||||
self._noSep = True
|
||||
|
||||
self._tokens.append((
|
||||
tokens.append((
|
||||
tType, nHead, tText, [], tStyle
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
elif aLine.startswith(("## ", "##! ")):
|
||||
@@ -632,10 +679,10 @@ class Tokenizer(ABC):
|
||||
self._hFormatter.resetScene()
|
||||
self._noSep = True
|
||||
|
||||
self._tokens.append((
|
||||
tokens.append((
|
||||
tType, nHead, tText, [], tStyle
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
elif aLine.startswith(("### ", "###! ")):
|
||||
@@ -673,10 +720,10 @@ class Tokenizer(ABC):
|
||||
tStyle = self.A_NONE if self._noSep else self.A_CENTRE
|
||||
self._noSep = False
|
||||
|
||||
self._tokens.append((
|
||||
tokens.append((
|
||||
tType, nHead, tText, [], tStyle
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
elif aLine.startswith("#### "):
|
||||
@@ -703,10 +750,10 @@ class Tokenizer(ABC):
|
||||
tType = self.T_SEP
|
||||
tStyle = self.A_CENTRE
|
||||
|
||||
self._tokens.append((
|
||||
tokens.append((
|
||||
tType, nHead, tText, [], tStyle
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
else:
|
||||
@@ -750,54 +797,91 @@ class Tokenizer(ABC):
|
||||
sAlign |= self.A_IND_R
|
||||
|
||||
# Process formats
|
||||
tLine, fmtPos = self._extractFormats(aLine)
|
||||
self._tokens.append((
|
||||
self.T_TEXT, nHead, tLine, fmtPos, sAlign
|
||||
tLine, tFmt = self._extractFormats(aLine)
|
||||
tokens.append((
|
||||
self.T_TEXT, nHead, tLine, tFmt, sAlign
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append(f"{aLine}\n")
|
||||
|
||||
# If we have content, turn off the first page flag
|
||||
if self._isFirst and self._tokens:
|
||||
if self._isFirst and tokens:
|
||||
self._isFirst = False # First document has been processed
|
||||
|
||||
# Make sure the token array doesn't start with a page break
|
||||
# on the very first page, adding a blank first page.
|
||||
if self._tokens[0][4] & self.A_PBB:
|
||||
token = self._tokens[0]
|
||||
self._tokens[0] = (
|
||||
token[0], token[1], token[2], token[3], token[4] & ~self.A_PBB
|
||||
if tokens[0][4] & self.A_PBB:
|
||||
cToken = tokens[0]
|
||||
tokens[0] = (
|
||||
cToken[0], cToken[1], cToken[2], cToken[3], cToken[4] & ~self.A_PBB
|
||||
)
|
||||
|
||||
# Always add an empty line at the end of the file
|
||||
self._tokens.append((
|
||||
tokens.append((
|
||||
self.T_EMPTY, nHead, "", [], self.A_NONE
|
||||
))
|
||||
if self._keepMarkdown:
|
||||
if self._keepMD:
|
||||
tmpMarkdown.append("\n")
|
||||
self._allMarkdown.append("".join(tmpMarkdown))
|
||||
self._markdown.append("".join(tmpMarkdown))
|
||||
|
||||
# Second Pass
|
||||
# ===========
|
||||
# Some items need a second pass
|
||||
# This second pass strips away consecutive blank lines, and
|
||||
# combines consecutive text lines into the same paragraph.
|
||||
# It also ensures that there isn't paragraph spacing between
|
||||
# meta data lines for formats that has spacing.
|
||||
|
||||
pToken = (self.T_EMPTY, 0, "", [], self.A_NONE)
|
||||
nToken = (self.T_EMPTY, 0, "", [], self.A_NONE)
|
||||
tCount = len(self._tokens)
|
||||
for n, token in enumerate(self._tokens):
|
||||
self._tokens = []
|
||||
pToken: T_Token = (self.T_EMPTY, 0, "", [], self.A_NONE)
|
||||
nToken: T_Token = (self.T_EMPTY, 0, "", [], self.A_NONE)
|
||||
|
||||
lineSep = "\n" if self._keepBreaks else " "
|
||||
pLines: list[T_Token] = []
|
||||
|
||||
tCount = len(tokens)
|
||||
for n, cToken in enumerate(tokens):
|
||||
|
||||
if n > 0:
|
||||
pToken = self._tokens[n-1]
|
||||
pToken = tokens[n-1] # Look behind
|
||||
if n < tCount - 1:
|
||||
nToken = self._tokens[n+1]
|
||||
nToken = tokens[n+1] # Look ahead
|
||||
|
||||
if token[0] == self.T_KEYWORD:
|
||||
aStyle = token[4]
|
||||
if cToken[0] == self.T_EMPTY:
|
||||
# We don't need to keep the empty lines after this pass
|
||||
pass
|
||||
|
||||
elif cToken[0] == self.T_KEYWORD:
|
||||
# Adjust margins for lines in a list of keyword lines
|
||||
aStyle = cToken[4]
|
||||
if pToken[0] == self.T_KEYWORD:
|
||||
aStyle |= self.A_Z_TOPMRG
|
||||
if nToken[0] == self.T_KEYWORD:
|
||||
aStyle |= self.A_Z_BTMMRG
|
||||
self._tokens[n] = (token[0], token[1], token[2], token[3], aStyle)
|
||||
self._tokens.append((
|
||||
cToken[0], cToken[1], cToken[2], cToken[3], aStyle
|
||||
))
|
||||
|
||||
elif cToken[0] == self.T_TEXT:
|
||||
# Combine lines from the same paragraph
|
||||
pLines.append(cToken)
|
||||
if nToken[0] != self.T_TEXT:
|
||||
nLines = len(pLines)
|
||||
if nLines == 1:
|
||||
self._tokens.append(pLines[0])
|
||||
elif nLines > 1:
|
||||
tTxt = ""
|
||||
tFmt: T_Formats = []
|
||||
for aToken in pLines:
|
||||
tLen = len(tTxt)
|
||||
tTxt += f"{aToken[2]}{lineSep}"
|
||||
tFmt.extend((p+tLen, fmt, key) for p, fmt, key in aToken[3])
|
||||
self._tokens.append((
|
||||
self.T_TEXT, pLines[0][1], tTxt[:-1], tFmt, pLines[0][4]
|
||||
))
|
||||
pLines = []
|
||||
|
||||
else:
|
||||
self._tokens.append(cToken)
|
||||
|
||||
return
|
||||
|
||||
@@ -840,7 +924,6 @@ class Tokenizer(ABC):
|
||||
textWordChars = self._counts.get("textWordChars", 0)
|
||||
titleWordChars = self._counts.get("titleWordChars", 0)
|
||||
|
||||
para = []
|
||||
for tType, _, tText, _, _ in self._tokens:
|
||||
tText = tText.replace(nwUnicode.U_ENDASH, " ")
|
||||
tText = tText.replace(nwUnicode.U_EMDASH, " ")
|
||||
@@ -850,22 +933,19 @@ class Tokenizer(ABC):
|
||||
nChars = len(tText)
|
||||
nWChars = len("".join(tWords))
|
||||
|
||||
if tType == self.T_EMPTY:
|
||||
if len(para) > 0:
|
||||
tTemp = "\n".join(para)
|
||||
tPWords = tTemp.split()
|
||||
nPWords = len(tPWords)
|
||||
nPChars = len(tTemp)
|
||||
nPWChars = len("".join(tPWords))
|
||||
if tType == self.T_TEXT:
|
||||
tPWords = tText.split()
|
||||
nPWords = len(tPWords)
|
||||
nPChars = len(tText)
|
||||
nPWChars = len("".join(tPWords))
|
||||
|
||||
paragraphCount += 1
|
||||
allWords += nPWords
|
||||
textWords += nPWords
|
||||
allChars += nPChars
|
||||
textChars += nPChars
|
||||
allWordChars += nPWChars
|
||||
textWordChars += nPWChars
|
||||
para = []
|
||||
paragraphCount += 1
|
||||
allWords += nPWords
|
||||
textWords += nPWords
|
||||
allChars += nPChars
|
||||
textChars += nPChars
|
||||
allWordChars += nPWChars
|
||||
textWordChars += nPWChars
|
||||
|
||||
elif tType in self.L_HEADINGS:
|
||||
titleCount += 1
|
||||
@@ -881,9 +961,6 @@ class Tokenizer(ABC):
|
||||
allChars += nChars
|
||||
allWordChars += nWChars
|
||||
|
||||
elif tType == self.T_TEXT:
|
||||
para.append(tText.rstrip())
|
||||
|
||||
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||
text = "{0}: {1}".format(self._localLookup("Synopsis"), tText)
|
||||
words = text.split()
|
||||
@@ -935,7 +1012,7 @@ class Tokenizer(ABC):
|
||||
def saveRawMarkdown(self, path: str | Path) -> None:
|
||||
"""Save the raw text to a plain text file."""
|
||||
with open(path, mode="w", encoding="utf-8") as outFile:
|
||||
for nwdPage in self._allMarkdown:
|
||||
for nwdPage in self._markdown:
|
||||
outFile.write(nwdPage)
|
||||
return
|
||||
|
||||
@@ -950,7 +1027,7 @@ class Tokenizer(ABC):
|
||||
"buildTimeStr": formatTimeStamp(timeStamp),
|
||||
},
|
||||
"text": {
|
||||
"nwd": [page.rstrip("\n").split("\n") for page in self._allMarkdown],
|
||||
"nwd": [page.rstrip("\n").split("\n") for page in self._markdown],
|
||||
}
|
||||
}
|
||||
with open(path, mode="w", encoding="utf-8") as fObj:
|
||||
@@ -961,9 +1038,9 @@ class Tokenizer(ABC):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _extractFormats(self, text: str) -> tuple[str, list[tuple[int, int]]]:
|
||||
def _extractFormats(self, text: str, skip: int = 0) -> tuple[str, T_Formats]:
|
||||
"""Extract format markers from a text paragraph."""
|
||||
temp = []
|
||||
temp: list[tuple[int, int, int, str]] = []
|
||||
|
||||
# Match Markdown
|
||||
for regEx, fmts in self._rxMarkdown:
|
||||
@@ -971,7 +1048,7 @@ class Tokenizer(ABC):
|
||||
while rxItt.hasNext():
|
||||
rxMatch = rxItt.next()
|
||||
temp.extend(
|
||||
[rxMatch.capturedStart(n), rxMatch.capturedLength(n), fmt]
|
||||
(rxMatch.capturedStart(n), rxMatch.capturedLength(n), fmt, "")
|
||||
for n, fmt in enumerate(fmts) if fmt > 0
|
||||
)
|
||||
|
||||
@@ -979,25 +1056,37 @@ class Tokenizer(ABC):
|
||||
rxItt = self._rxShortCodes.globalMatch(text, 0)
|
||||
while rxItt.hasNext():
|
||||
rxMatch = rxItt.next()
|
||||
temp.append([
|
||||
temp.append((
|
||||
rxMatch.capturedStart(1),
|
||||
rxMatch.capturedLength(1),
|
||||
self._shortCodeFmt.get(rxMatch.captured(1).lower(), 0)
|
||||
])
|
||||
self._shortCodeFmt.get(rxMatch.captured(1).lower(), 0),
|
||||
"",
|
||||
))
|
||||
|
||||
# Post-process text and format markers
|
||||
# Match Shortcode w/Values
|
||||
rxItt = self._rxShortCodeVals.globalMatch(text, 0)
|
||||
tHandle = self._handle or ""
|
||||
while rxItt.hasNext():
|
||||
rxMatch = rxItt.next()
|
||||
kind = self._shortCodeVals.get(rxMatch.captured(1).lower(), 0)
|
||||
temp.append((
|
||||
rxMatch.capturedStart(0),
|
||||
rxMatch.capturedLength(0),
|
||||
self.FMT_STRIP if kind == skip else kind,
|
||||
f"{tHandle}:{rxMatch.captured(2)}",
|
||||
))
|
||||
|
||||
# Post-process text and format
|
||||
result = text
|
||||
formats = []
|
||||
for pos, n, fmt in reversed(sorted(temp, key=lambda x: x[0])):
|
||||
for pos, n, fmt, key in reversed(sorted(temp, key=lambda x: x[0])):
|
||||
if fmt > 0:
|
||||
result = result[:pos] + result[pos+n:]
|
||||
formats = [(p-n, f) for p, f in formats]
|
||||
formats.insert(0, (pos, fmt))
|
||||
formats = [(p-n, f, k) for p, f, k in formats]
|
||||
formats.insert(0, (pos, fmt, key))
|
||||
|
||||
return result, formats
|
||||
|
||||
# END Class Tokenizer
|
||||
|
||||
|
||||
class HeadingFormatter:
|
||||
|
||||
@@ -1067,5 +1156,3 @@ class HeadingFormatter:
|
||||
hFormat = hFormat.replace(nwHeadFmt.CHAR_FOCUS, fText)
|
||||
|
||||
return hFormat
|
||||
|
||||
# END Class HeadingFormatter
|
||||
|
||||
@@ -29,11 +29,50 @@ from pathlib import Path
|
||||
|
||||
from novelwriter.constants import nwHeadFmt, nwLabels, nwUnicode
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer
|
||||
from novelwriter.core.tokenizer import T_Formats, Tokenizer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Standard Markdown
|
||||
STD_MD = {
|
||||
Tokenizer.FMT_B_B: "**",
|
||||
Tokenizer.FMT_B_E: "**",
|
||||
Tokenizer.FMT_I_B: "_",
|
||||
Tokenizer.FMT_I_E: "_",
|
||||
Tokenizer.FMT_D_B: "",
|
||||
Tokenizer.FMT_D_E: "",
|
||||
Tokenizer.FMT_U_B: "",
|
||||
Tokenizer.FMT_U_E: "",
|
||||
Tokenizer.FMT_M_B: "",
|
||||
Tokenizer.FMT_M_E: "",
|
||||
Tokenizer.FMT_SUP_B: "",
|
||||
Tokenizer.FMT_SUP_E: "",
|
||||
Tokenizer.FMT_SUB_B: "",
|
||||
Tokenizer.FMT_SUB_E: "",
|
||||
Tokenizer.FMT_STRIP: "",
|
||||
}
|
||||
|
||||
# Extended Markdown
|
||||
EXT_MD = {
|
||||
Tokenizer.FMT_B_B: "**",
|
||||
Tokenizer.FMT_B_E: "**",
|
||||
Tokenizer.FMT_I_B: "_",
|
||||
Tokenizer.FMT_I_E: "_",
|
||||
Tokenizer.FMT_D_B: "~~",
|
||||
Tokenizer.FMT_D_E: "~~",
|
||||
Tokenizer.FMT_U_B: "",
|
||||
Tokenizer.FMT_U_E: "",
|
||||
Tokenizer.FMT_M_B: "==",
|
||||
Tokenizer.FMT_M_E: "==",
|
||||
Tokenizer.FMT_SUP_B: "^",
|
||||
Tokenizer.FMT_SUP_E: "^",
|
||||
Tokenizer.FMT_SUB_B: "~",
|
||||
Tokenizer.FMT_SUB_E: "~",
|
||||
Tokenizer.FMT_STRIP: "",
|
||||
}
|
||||
|
||||
|
||||
class ToMarkdown(Tokenizer):
|
||||
"""Core: Markdown Document Writer
|
||||
|
||||
@@ -42,14 +81,11 @@ class ToMarkdown(Tokenizer):
|
||||
supports concatenating novelWriter markup files.
|
||||
"""
|
||||
|
||||
M_STD = 0 # Standard Markdown
|
||||
M_EXT = 1 # Extended Markdown
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
super().__init__(project)
|
||||
self._genMode = self.M_STD
|
||||
self._fullMD: list[str] = []
|
||||
self._preserveBreaks = True
|
||||
self._usedNotes: dict[str, int] = {}
|
||||
self._extended = True
|
||||
return
|
||||
|
||||
##
|
||||
@@ -65,19 +101,9 @@ class ToMarkdown(Tokenizer):
|
||||
# Setters
|
||||
##
|
||||
|
||||
def setStandardMarkdown(self) -> None:
|
||||
"""Set the converter to use standard Markdown formatting."""
|
||||
self._genMode = self.M_STD
|
||||
return
|
||||
|
||||
def setExtendedMarkdown(self) -> None:
|
||||
def setExtendedMarkdown(self, state: bool) -> None:
|
||||
"""Set the converter to use Extended Markdown formatting."""
|
||||
self._genMode = self.M_EXT
|
||||
return
|
||||
|
||||
def setPreserveBreaks(self, state: bool) -> None:
|
||||
"""Preserve line breaks in paragraphs."""
|
||||
self._preserveBreaks = state
|
||||
self._extended = state
|
||||
return
|
||||
|
||||
##
|
||||
@@ -90,58 +116,21 @@ class ToMarkdown(Tokenizer):
|
||||
|
||||
def doConvert(self) -> None:
|
||||
"""Convert the list of text tokens into a Markdown document."""
|
||||
if self._genMode == self.M_STD:
|
||||
# Standard Markdown
|
||||
mdTags = {
|
||||
self.FMT_B_B: "**",
|
||||
self.FMT_B_E: "**",
|
||||
self.FMT_I_B: "_",
|
||||
self.FMT_I_E: "_",
|
||||
self.FMT_D_B: "",
|
||||
self.FMT_D_E: "",
|
||||
self.FMT_U_B: "",
|
||||
self.FMT_U_E: "",
|
||||
self.FMT_M_B: "",
|
||||
self.FMT_M_E: "",
|
||||
self.FMT_SUP_B: "",
|
||||
self.FMT_SUP_E: "",
|
||||
self.FMT_SUB_B: "",
|
||||
self.FMT_SUB_E: "",
|
||||
}
|
||||
cSkip = ""
|
||||
else:
|
||||
# Extended Markdown
|
||||
mdTags = {
|
||||
self.FMT_B_B: "**",
|
||||
self.FMT_B_E: "**",
|
||||
self.FMT_I_B: "_",
|
||||
self.FMT_I_E: "_",
|
||||
self.FMT_D_B: "~~",
|
||||
self.FMT_D_E: "~~",
|
||||
self.FMT_U_B: "",
|
||||
self.FMT_U_E: "",
|
||||
self.FMT_M_B: "==",
|
||||
self.FMT_M_E: "==",
|
||||
self.FMT_SUP_B: "^",
|
||||
self.FMT_SUP_E: "^",
|
||||
self.FMT_SUB_B: "~",
|
||||
self.FMT_SUB_E: "~",
|
||||
}
|
||||
cSkip = nwUnicode.U_MMSP
|
||||
|
||||
self._result = ""
|
||||
|
||||
para = []
|
||||
lines = []
|
||||
lineSep = " \n" if self._preserveBreaks else " "
|
||||
if self._extended:
|
||||
mTags = EXT_MD
|
||||
cSkip = nwUnicode.U_MMSP
|
||||
else:
|
||||
mTags = STD_MD
|
||||
cSkip = ""
|
||||
|
||||
lines = []
|
||||
for tType, _, tText, tFormat, tStyle in self._tokens:
|
||||
|
||||
if tType == self.T_EMPTY:
|
||||
if para:
|
||||
tTemp = (lineSep.join(para)).rstrip(" ")
|
||||
lines.append(f"{tTemp}\n\n")
|
||||
para = []
|
||||
if tType == self.T_TEXT:
|
||||
tTemp = self._formatText(tText, tFormat, mTags).replace("\n", " \n")
|
||||
lines.append(f"{tTemp}\n\n")
|
||||
|
||||
elif tType == self.T_TITLE:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
@@ -169,23 +158,17 @@ class ToMarkdown(Tokenizer):
|
||||
elif tType == self.T_SKIP:
|
||||
lines.append(f"{cSkip}\n\n")
|
||||
|
||||
elif tType == self.T_TEXT:
|
||||
tTemp = tText
|
||||
for pos, fmt in reversed(tFormat):
|
||||
tTemp = f"{tTemp[:pos]}{mdTags[fmt]}{tTemp[pos:]}"
|
||||
para.append(tTemp.rstrip())
|
||||
|
||||
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||
label = self._localLookup("Synopsis")
|
||||
lines.append(f"**{label}:** {tText}\n\n")
|
||||
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
||||
|
||||
elif tType == self.T_SHORT and self._doSynopsis:
|
||||
label = self._localLookup("Short Description")
|
||||
lines.append(f"**{label}:** {tText}\n\n")
|
||||
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
||||
|
||||
elif tType == self.T_COMMENT and self._doComments:
|
||||
label = self._localLookup("Comment")
|
||||
lines.append(f"**{label}:** {tText}\n\n")
|
||||
lines.append(f"**{label}:** {self._formatText(tText, tFormat, mTags)}\n\n")
|
||||
|
||||
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||
lines.append(self._formatKeywords(tText, tStyle))
|
||||
@@ -195,6 +178,27 @@ class ToMarkdown(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
def appendFootnotes(self) -> None:
|
||||
"""Append the footnotes in the buffer."""
|
||||
if self._usedNotes:
|
||||
tags = EXT_MD if self._extended else STD_MD
|
||||
footnotes = self._localLookup("Footnotes")
|
||||
|
||||
lines = []
|
||||
lines.append(f"### {footnotes}\n\n")
|
||||
for key, index in self._usedNotes.items():
|
||||
if content := self._footnotes.get(key):
|
||||
marker = f"{index}. "
|
||||
text = self._formatText(*content, tags)
|
||||
lines.append(f"{marker}{text}\n")
|
||||
lines.append("\n")
|
||||
|
||||
result = "".join(lines)
|
||||
self._result += result
|
||||
self._fullMD.append(result)
|
||||
|
||||
return
|
||||
|
||||
def saveMarkdown(self, path: str | Path) -> None:
|
||||
"""Save the data to a plain text file."""
|
||||
with open(path, mode="w", encoding="utf-8") as outFile:
|
||||
@@ -206,14 +210,31 @@ class ToMarkdown(Tokenizer):
|
||||
"""Replace tabs with spaces."""
|
||||
spaces = spaceChar*nSpaces
|
||||
self._fullMD = [p.replace("\t", spaces) for p in self._fullMD]
|
||||
if self._keepMarkdown:
|
||||
self._allMarkdown = [p.replace("\t", spaces) for p in self._allMarkdown]
|
||||
if self._keepMD:
|
||||
self._markdown = [p.replace("\t", spaces) for p in self._markdown]
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatText(self, text: str, tFmt: T_Formats, tags: dict[int, str]) -> str:
|
||||
"""Apply formatting tags to text."""
|
||||
temp = text
|
||||
for pos, fmt, data in reversed(tFmt):
|
||||
md = ""
|
||||
if fmt == self.FMT_FNOTE:
|
||||
if data in self._footnotes:
|
||||
index = len(self._usedNotes) + 1
|
||||
self._usedNotes[data] = index
|
||||
md = f"[{index}]"
|
||||
else:
|
||||
md = "[ERR]"
|
||||
else:
|
||||
md = tags.get(fmt, "")
|
||||
temp = f"{temp[:pos]}{md}{temp[pos:]}"
|
||||
return temp
|
||||
|
||||
def _formatKeywords(self, text: str, style: int) -> str:
|
||||
"""Apply Markdown formatting to keywords."""
|
||||
valid, bits, _ = self._project.index.scanThis("@"+text)
|
||||
@@ -229,5 +250,3 @@ class ToMarkdown(Tokenizer):
|
||||
result += " \n" if style & self.A_Z_BTMMRG else "\n\n"
|
||||
|
||||
return result
|
||||
|
||||
# END Class ToMarkdown
|
||||
@@ -29,17 +29,20 @@ from __future__ import annotations
|
||||
import logging
|
||||
import xml.etree.ElementTree as ET
|
||||
|
||||
from collections.abc import Sequence
|
||||
from datetime import datetime
|
||||
from hashlib import sha256
|
||||
from pathlib import Path
|
||||
from zipfile import ZipFile
|
||||
from datetime import datetime
|
||||
from collections.abc import Sequence
|
||||
|
||||
from PyQt5.QtGui import QFont
|
||||
|
||||
from novelwriter import __version__
|
||||
from novelwriter.common import xmlIndent
|
||||
from novelwriter.constants import nwHeadFmt, nwKeyWords, nwLabels
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import Tokenizer, stripEscape
|
||||
from novelwriter.core.tokenizer import T_Formats, Tokenizer, stripEscape
|
||||
from novelwriter.types import FONT_STYLE, FONT_WEIGHTS
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -96,6 +99,22 @@ M_MRK = ~X_MRK
|
||||
M_SUP = ~X_SUP
|
||||
M_SUB = ~X_SUB
|
||||
|
||||
# ODT Styles
|
||||
S_TITLE = "Title"
|
||||
S_HEAD1 = "Heading_20_1"
|
||||
S_HEAD2 = "Heading_20_2"
|
||||
S_HEAD3 = "Heading_20_3"
|
||||
S_HEAD4 = "Heading_20_4"
|
||||
S_SEP = "Separator"
|
||||
S_FIND = "First_20_line_20_indent"
|
||||
S_TEXT = "Text_20_body"
|
||||
S_META = "Text_20_Meta"
|
||||
S_HNF = "Header_20_and_20_Footer"
|
||||
|
||||
# Font Data
|
||||
FONT_WEIGHT_NUM = ["100", "200", "300", "400", "500", "600", "700", "800", "900"]
|
||||
FONT_WEIGHT_MAP = {"400": "normal", "700": "bold"}
|
||||
|
||||
|
||||
class ToOdt(Tokenizer):
|
||||
"""Core: Open Document Writer
|
||||
@@ -130,20 +149,25 @@ class ToOdt(Tokenizer):
|
||||
self._autoPara: dict[str, ODTParagraphStyle] = {} # Auto-generated paragraph styles
|
||||
self._autoText: dict[int, ODTTextStyle] = {} # Auto-generated text styles
|
||||
|
||||
# Footnotes
|
||||
self._nNote = 0
|
||||
self._etNotes: dict[str, ET.Element] = {} # Generated note elements
|
||||
|
||||
self._errData = [] # List of errors encountered
|
||||
|
||||
# Properties
|
||||
self._textFont = "Liberation Serif"
|
||||
self._textSize = 12
|
||||
self._textFixed = False
|
||||
self._textFont = QFont("Liberation Serif", 12)
|
||||
self._colourHead = False
|
||||
self._firstIndent = False
|
||||
self._headerFormat = ""
|
||||
self._pageOffset = 0
|
||||
|
||||
# Internal
|
||||
self._fontFamily = "'Liberation Serif'"
|
||||
self._fontFamily = "Liberation Serif"
|
||||
self._fontSize = 12
|
||||
self._fontWeight = "normal"
|
||||
self._fontStyle = "normal"
|
||||
self._fontPitch = "variable"
|
||||
self._fontBold = "bold"
|
||||
self._fSizeTitle = "30pt"
|
||||
self._fSizeHead1 = "24pt"
|
||||
self._fSizeHead2 = "20pt"
|
||||
@@ -151,6 +175,7 @@ class ToOdt(Tokenizer):
|
||||
self._fSizeHead4 = "14pt"
|
||||
self._fSizeHead = "14pt"
|
||||
self._fSizeText = "12pt"
|
||||
self._fSizeFoot = "10pt"
|
||||
self._fLineHeight = "115%"
|
||||
self._fBlockIndent = "1.693cm"
|
||||
self._fTextIndent = "0.499cm"
|
||||
@@ -167,6 +192,7 @@ class ToOdt(Tokenizer):
|
||||
self._mTopHead = "0.423cm"
|
||||
self._mTopText = "0.000cm"
|
||||
self._mTopMeta = "0.000cm"
|
||||
self._mTopSep = "0.247cm"
|
||||
|
||||
self._mBotTitle = "0.212cm"
|
||||
self._mBotHead1 = "0.212cm"
|
||||
@@ -176,6 +202,10 @@ class ToOdt(Tokenizer):
|
||||
self._mBotHead = "0.212cm"
|
||||
self._mBotText = "0.247cm"
|
||||
self._mBotMeta = "0.106cm"
|
||||
self._mBotSep = "0.247cm"
|
||||
|
||||
self._mBotFoot = "0.106cm"
|
||||
self._mLeftFoot = "0.600cm"
|
||||
|
||||
# Document Size and Margins
|
||||
self._mDocWidth = "21.0cm"
|
||||
@@ -232,11 +262,6 @@ class ToOdt(Tokenizer):
|
||||
self._pageOffset = offset
|
||||
return
|
||||
|
||||
def setFirstLineIndent(self, state: bool) -> None:
|
||||
"""Enable or disable first line indent."""
|
||||
self._firstIndent = state
|
||||
return
|
||||
|
||||
##
|
||||
# Class Methods
|
||||
##
|
||||
@@ -246,18 +271,25 @@ class ToOdt(Tokenizer):
|
||||
# Initialise Variables
|
||||
# ====================
|
||||
|
||||
self._fontFamily = self._textFont
|
||||
if len(self._textFont.split()) > 1:
|
||||
self._fontFamily = f"'{self._textFont}'"
|
||||
self._fontPitch = "fixed" if self._textFixed else "variable"
|
||||
intWeight = FONT_WEIGHTS.get(self._textFont.weight(), 400)
|
||||
fontWeight = str(intWeight)
|
||||
fontBold = str(min(intWeight + 300, 900))
|
||||
|
||||
self._fSizeTitle = f"{round(2.50 * self._textSize):d}pt"
|
||||
self._fSizeHead1 = f"{round(2.00 * self._textSize):d}pt"
|
||||
self._fSizeHead2 = f"{round(1.60 * self._textSize):d}pt"
|
||||
self._fSizeHead3 = f"{round(1.30 * self._textSize):d}pt"
|
||||
self._fSizeHead4 = f"{round(1.15 * self._textSize):d}pt"
|
||||
self._fSizeHead = f"{round(1.15 * self._textSize):d}pt"
|
||||
self._fSizeText = f"{self._textSize:d}pt"
|
||||
self._fontFamily = self._textFont.family()
|
||||
self._fontSize = self._textFont.pointSize()
|
||||
self._fontWeight = FONT_WEIGHT_MAP.get(fontWeight, fontWeight)
|
||||
self._fontStyle = FONT_STYLE.get(self._textFont.style(), "normal")
|
||||
self._fontPitch = "fixed" if self._textFont.fixedPitch() else "variable"
|
||||
self._fontBold = FONT_WEIGHT_MAP.get(fontBold, fontBold)
|
||||
|
||||
self._fSizeTitle = f"{round(2.50 * self._fontSize):d}pt"
|
||||
self._fSizeHead1 = f"{round(2.00 * self._fontSize):d}pt"
|
||||
self._fSizeHead2 = f"{round(1.60 * self._fontSize):d}pt"
|
||||
self._fSizeHead3 = f"{round(1.30 * self._fontSize):d}pt"
|
||||
self._fSizeHead4 = f"{round(1.15 * self._fontSize):d}pt"
|
||||
self._fSizeHead = f"{round(1.15 * self._fontSize):d}pt"
|
||||
self._fSizeText = f"{self._fontSize:d}pt"
|
||||
self._fSizeFoot = f"{round(0.8*self._fontSize):d}pt"
|
||||
|
||||
mScale = self._lineHeight/1.15
|
||||
|
||||
@@ -269,6 +301,7 @@ class ToOdt(Tokenizer):
|
||||
self._mTopHead = self._emToCm(mScale * self._marginHead4[0])
|
||||
self._mTopText = self._emToCm(mScale * self._marginText[0])
|
||||
self._mTopMeta = self._emToCm(mScale * self._marginMeta[0])
|
||||
self._mTopSep = self._emToCm(mScale * self._marginSep[0])
|
||||
|
||||
self._mBotTitle = self._emToCm(mScale * self._marginTitle[1])
|
||||
self._mBotHead1 = self._emToCm(mScale * self._marginHead1[1])
|
||||
@@ -278,6 +311,10 @@ class ToOdt(Tokenizer):
|
||||
self._mBotHead = self._emToCm(mScale * self._marginHead4[1])
|
||||
self._mBotText = self._emToCm(mScale * self._marginText[1])
|
||||
self._mBotMeta = self._emToCm(mScale * self._marginMeta[1])
|
||||
self._mBotSep = self._emToCm(mScale * self._marginSep[1])
|
||||
|
||||
self._mLeftFoot = self._emToCm(self._marginFoot[0])
|
||||
self._mBotFoot = self._emToCm(self._marginFoot[1])
|
||||
|
||||
if self._colourHead:
|
||||
self._colHead12 = "#2a6099"
|
||||
@@ -289,6 +326,7 @@ class ToOdt(Tokenizer):
|
||||
|
||||
self._fLineHeight = f"{round(100 * self._lineHeight):d}%"
|
||||
self._fBlockIndent = self._emToCm(self._blockIndent)
|
||||
self._fTextIndent = self._emToCm(self._firstWidth)
|
||||
self._textAlign = "justify" if self._doJustify else "left"
|
||||
|
||||
# Clear Errors
|
||||
@@ -301,7 +339,7 @@ class ToOdt(Tokenizer):
|
||||
tAttr[_mkTag("office", "version")] = X_VERS
|
||||
|
||||
fAttr = {}
|
||||
fAttr[_mkTag("style", "name")] = self._textFont
|
||||
fAttr[_mkTag("style", "name")] = self._fontFamily
|
||||
fAttr[_mkTag("style", "font-pitch")] = self._fontPitch
|
||||
|
||||
if self._isFlat:
|
||||
@@ -399,9 +437,7 @@ class ToOdt(Tokenizer):
|
||||
"""Convert the list of text tokens into XML elements."""
|
||||
self._result = "" # Not used, but cleared just in case
|
||||
|
||||
pFmt = []
|
||||
pText = []
|
||||
pStyle = None
|
||||
xText = self._xText
|
||||
pIndent = True
|
||||
for tType, _, tText, tFormat, tStyle in self._tokens:
|
||||
|
||||
@@ -433,82 +469,59 @@ class ToOdt(Tokenizer):
|
||||
if tStyle & self.A_IND_R:
|
||||
oStyle.setMarginRight(self._fBlockIndent)
|
||||
|
||||
if tType not in (self.T_EMPTY, self.T_TEXT):
|
||||
if not self._indentFirst and tType in self.L_SKIP_INDENT:
|
||||
pIndent = False
|
||||
|
||||
# Process Text Types
|
||||
if tType == self.T_EMPTY:
|
||||
if len(pText) > 1 and pStyle is not None:
|
||||
if self._doJustify:
|
||||
pStyle.setTextAlign("left")
|
||||
|
||||
if len(pText) > 0 and pStyle is not None:
|
||||
tTxt = ""
|
||||
tFmt = []
|
||||
for nText, nFmt in zip(pText, pFmt):
|
||||
tLen = len(tTxt)
|
||||
tTxt += f"{nText}\n"
|
||||
tFmt.extend((p+tLen, fmt) for p, fmt in nFmt)
|
||||
|
||||
# Don't indent a paragraph if it has alignment set
|
||||
tIndent = self._firstIndent and pIndent and pStyle.isUnaligned()
|
||||
self._addTextPar(
|
||||
"First_20_line_20_indent" if tIndent else "Text_20_body",
|
||||
pStyle, tTxt.rstrip(), tFmt=tFmt
|
||||
)
|
||||
pIndent = True
|
||||
|
||||
pFmt = []
|
||||
pText = []
|
||||
pStyle = None
|
||||
if tType == self.T_TEXT:
|
||||
if self._firstIndent and pIndent and oStyle.isUnaligned():
|
||||
self._addTextPar(xText, S_FIND, oStyle, tText, tFmt=tFormat)
|
||||
else:
|
||||
self._addTextPar(xText, S_TEXT, oStyle, tText, tFmt=tFormat)
|
||||
pIndent = True
|
||||
|
||||
elif tType == self.T_TITLE:
|
||||
# Title must be text:p
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Title", oStyle, tHead, isHead=False) # Title must be text:p
|
||||
self._addTextPar(xText, S_TITLE, oStyle, tHead, isHead=False)
|
||||
|
||||
elif tType == self.T_HEAD1:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_1", oStyle, tHead, isHead=True, oLevel="1")
|
||||
self._addTextPar(xText, S_HEAD1, oStyle, tHead, isHead=True, oLevel="1")
|
||||
|
||||
elif tType == self.T_HEAD2:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_2", oStyle, tHead, isHead=True, oLevel="2")
|
||||
self._addTextPar(xText, S_HEAD2, oStyle, tHead, isHead=True, oLevel="2")
|
||||
|
||||
elif tType == self.T_HEAD3:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_3", oStyle, tHead, isHead=True, oLevel="3")
|
||||
self._addTextPar(xText, S_HEAD3, oStyle, tHead, isHead=True, oLevel="3")
|
||||
|
||||
elif tType == self.T_HEAD4:
|
||||
tHead = tText.replace(nwHeadFmt.BR, "\n")
|
||||
self._addTextPar("Heading_20_4", oStyle, tHead, isHead=True, oLevel="4")
|
||||
self._addTextPar(xText, S_HEAD4, oStyle, tHead, isHead=True, oLevel="4")
|
||||
|
||||
elif tType == self.T_SEP:
|
||||
self._addTextPar("Separator", oStyle, tText)
|
||||
self._addTextPar(xText, S_SEP, oStyle, tText)
|
||||
|
||||
elif tType == self.T_SKIP:
|
||||
self._addTextPar("Separator", oStyle, "")
|
||||
|
||||
elif tType == self.T_TEXT:
|
||||
if pStyle is None:
|
||||
pStyle = oStyle
|
||||
pText.append(tText)
|
||||
pFmt.append(tFormat)
|
||||
self._addTextPar(xText, S_TEXT, oStyle, "")
|
||||
|
||||
elif tType == self.T_SYNOPSIS and self._doSynopsis:
|
||||
tTemp, fTemp = self._formatSynopsis(tText, True)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp)
|
||||
tTemp, tFmt = self._formatSynopsis(tText, tFormat, True)
|
||||
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
|
||||
|
||||
elif tType == self.T_SHORT and self._doSynopsis:
|
||||
tTemp, fTemp = self._formatSynopsis(tText, False)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp)
|
||||
tTemp, tFmt = self._formatSynopsis(tText, tFormat, False)
|
||||
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
|
||||
|
||||
elif tType == self.T_COMMENT and self._doComments:
|
||||
tTemp, fTemp = self._formatComments(tText)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp)
|
||||
tTemp, tFmt = self._formatComments(tText, tFormat)
|
||||
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
|
||||
|
||||
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||
tTemp, fTemp = self._formatKeywords(tText)
|
||||
self._addTextPar("Text_20_Meta", oStyle, tTemp, tFmt=fTemp)
|
||||
tTemp, tFmt = self._formatKeywords(tText)
|
||||
self._addTextPar(xText, S_META, oStyle, tTemp, tFmt=tFmt)
|
||||
|
||||
return
|
||||
|
||||
@@ -569,28 +582,32 @@ class ToOdt(Tokenizer):
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _formatSynopsis(self, text: str, synopsis: bool) -> tuple[str, list[tuple[int, int]]]:
|
||||
def _formatSynopsis(self, text: str, fmt: T_Formats, synopsis: bool) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to synopsis lines."""
|
||||
name = self._localLookup("Synopsis" if synopsis else "Short Description")
|
||||
shift = len(name) + 2
|
||||
rTxt = f"{name}: {text}"
|
||||
rFmt = [(0, self.FMT_B_B), (len(name) + 1, self.FMT_B_E)]
|
||||
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(name) + 1, self.FMT_B_E, "")]
|
||||
rFmt.extend((p + shift, f, d) for p, f, d in fmt)
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatComments(self, text: str) -> tuple[str, list[tuple[int, int]]]:
|
||||
def _formatComments(self, text: str, fmt: T_Formats) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to comments."""
|
||||
name = self._localLookup("Comment")
|
||||
shift = len(name) + 2
|
||||
rTxt = f"{name}: {text}"
|
||||
rFmt = [(0, self.FMT_B_B), (len(name) + 1, self.FMT_B_E)]
|
||||
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(name) + 1, self.FMT_B_E, "")]
|
||||
rFmt.extend((p + shift, f, d) for p, f, d in fmt)
|
||||
return rTxt, rFmt
|
||||
|
||||
def _formatKeywords(self, text: str) -> tuple[str, list[tuple[int, int]]]:
|
||||
def _formatKeywords(self, text: str) -> tuple[str, T_Formats]:
|
||||
"""Apply formatting to keywords."""
|
||||
valid, bits, _ = self._project.index.scanThis("@"+text)
|
||||
if not valid or not bits or bits[0] not in nwLabels.KEY_NAME:
|
||||
return "", []
|
||||
|
||||
rTxt = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
|
||||
rFmt = [(0, self.FMT_B_B), (len(rTxt) - 1, self.FMT_B_E)]
|
||||
rFmt: T_Formats = [(0, self.FMT_B_B, ""), (len(rTxt) - 1, self.FMT_B_E, "")]
|
||||
if len(bits) > 1:
|
||||
if bits[0] == nwKeyWords.TAG_KEY:
|
||||
rTxt += bits[1]
|
||||
@@ -600,8 +617,8 @@ class ToOdt(Tokenizer):
|
||||
return rTxt, rFmt
|
||||
|
||||
def _addTextPar(
|
||||
self, styleName: str, oStyle: ODTParagraphStyle, tText: str,
|
||||
tFmt: Sequence[tuple[int, int]] = [], isHead: bool = False, oLevel: str | None = None
|
||||
self, xParent: ET.Element, styleName: str, oStyle: ODTParagraphStyle, tText: str,
|
||||
tFmt: Sequence[tuple[int, int, str]] = [], isHead: bool = False, oLevel: str | None = None
|
||||
) -> None:
|
||||
"""Add a text paragraph to the text XML element."""
|
||||
tAttr = {_mkTag("text", "style-name"): self._paraStyle(styleName, oStyle)}
|
||||
@@ -609,7 +626,7 @@ class ToOdt(Tokenizer):
|
||||
tAttr[_mkTag("text", "outline-level")] = oLevel
|
||||
|
||||
pTag = "h" if isHead else "p"
|
||||
xElem = ET.SubElement(self._xText, _mkTag("text", pTag), attrib=tAttr)
|
||||
xElem = ET.SubElement(xParent, _mkTag("text", pTag), attrib=tAttr)
|
||||
|
||||
# It's important to set the initial text field to empty, otherwise
|
||||
# xmlIndent will add a line break if the first subelement is a span.
|
||||
@@ -627,7 +644,13 @@ class ToOdt(Tokenizer):
|
||||
xFmt = 0x00
|
||||
tFrag = ""
|
||||
fLast = 0
|
||||
for fPos, fFmt in tFmt:
|
||||
xNode = None
|
||||
for fPos, fFmt, fData in tFmt:
|
||||
|
||||
# Add any extra nodes
|
||||
if xNode is not None:
|
||||
parProc.appendNode(xNode)
|
||||
xNode = None
|
||||
|
||||
# Add the text up to the current fragment
|
||||
if tFrag := tText[fLast:fPos]:
|
||||
@@ -665,11 +688,18 @@ class ToOdt(Tokenizer):
|
||||
xFmt |= X_SUB
|
||||
elif fFmt == self.FMT_SUB_E:
|
||||
xFmt &= M_SUB
|
||||
elif fFmt == self.FMT_FNOTE:
|
||||
xNode = self._generateFootnote(fData)
|
||||
elif fFmt == self.FMT_STRIP:
|
||||
pass
|
||||
else:
|
||||
pErr += 1
|
||||
|
||||
fLast = fPos
|
||||
|
||||
if xNode is not None:
|
||||
parProc.appendNode(xNode)
|
||||
|
||||
if tFrag := tText[fLast:]:
|
||||
if xFmt == 0x00:
|
||||
parProc.appendText(tFrag)
|
||||
@@ -715,7 +745,7 @@ class ToOdt(Tokenizer):
|
||||
|
||||
style = ODTTextStyle(f"T{len(self._autoText)+1:d}")
|
||||
if hFmt & X_BLD:
|
||||
style.setFontWeight("bold")
|
||||
style.setFontWeight(self._fontBold)
|
||||
if hFmt & X_ITA:
|
||||
style.setFontStyle("italic")
|
||||
if hFmt & X_DEL:
|
||||
@@ -735,9 +765,25 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return style.name
|
||||
|
||||
def _generateFootnote(self, key: str) -> ET.Element | None:
|
||||
"""Generate a footnote XML object."""
|
||||
if content := self._footnotes.get(key):
|
||||
self._nNote += 1
|
||||
nStyle = ODTParagraphStyle("New")
|
||||
xNote = ET.Element(_mkTag("text", "note"), attrib={
|
||||
_mkTag("text", "id"): f"ftn{self._nNote}",
|
||||
_mkTag("text", "note-class"): "footnote",
|
||||
})
|
||||
xCite = ET.SubElement(xNote, _mkTag("text", "note-citation"))
|
||||
xCite.text = str(self._nNote)
|
||||
xBody = ET.SubElement(xNote, _mkTag("text", "note-body"))
|
||||
self._addTextPar(xBody, "Footnote", nStyle, content[0], tFmt=content[1])
|
||||
return xNote
|
||||
return None
|
||||
|
||||
def _emToCm(self, value: float) -> str:
|
||||
"""Converts an em value to centimetres."""
|
||||
return f"{value*2.54/72*self._textSize:.3f}cm"
|
||||
return f"{value*2.54/72*self._fontSize:.3f}cm"
|
||||
|
||||
##
|
||||
# Style Elements
|
||||
@@ -757,7 +803,6 @@ class ToOdt(Tokenizer):
|
||||
_mkTag("fo", "margin-bottom"): self._mDocBtm,
|
||||
_mkTag("fo", "margin-left"): self._mDocLeft,
|
||||
_mkTag("fo", "margin-right"): self._mDocRight,
|
||||
_mkTag("fo", "print-orientation"): "portrait",
|
||||
})
|
||||
|
||||
xHead = ET.SubElement(xPage, _mkTag("style", "header-style"))
|
||||
@@ -782,8 +827,10 @@ class ToOdt(Tokenizer):
|
||||
_mkTag("style", "writing-mode"): "page",
|
||||
})
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
|
||||
_mkTag("style", "font-name"): self._textFont,
|
||||
_mkTag("style", "font-name"): self._fontFamily,
|
||||
_mkTag("fo", "font-family"): self._fontFamily,
|
||||
_mkTag("fo", "font-weight"): self._fontWeight,
|
||||
_mkTag("fo", "font-style"): self._fontStyle,
|
||||
_mkTag("fo", "font-size"): self._fSizeText,
|
||||
_mkTag("fo", "language"): self._dLanguage,
|
||||
_mkTag("fo", "country"): self._dCountry,
|
||||
@@ -796,8 +843,10 @@ class ToOdt(Tokenizer):
|
||||
_mkTag("style", "class"): "text",
|
||||
})
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
|
||||
_mkTag("style", "font-name"): self._textFont,
|
||||
_mkTag("style", "font-name"): self._fontFamily,
|
||||
_mkTag("fo", "font-family"): self._fontFamily,
|
||||
_mkTag("fo", "font-weight"): self._fontWeight,
|
||||
_mkTag("fo", "font-style"): self._fontStyle,
|
||||
_mkTag("fo", "font-size"): self._fSizeText,
|
||||
})
|
||||
|
||||
@@ -806,7 +855,7 @@ class ToOdt(Tokenizer):
|
||||
_mkTag("style", "name"): "Heading",
|
||||
_mkTag("style", "family"): "paragraph",
|
||||
_mkTag("style", "parent-style-name"): "Standard",
|
||||
_mkTag("style", "next-style-name"): "Text_20_body",
|
||||
_mkTag("style", "next-style-name"): S_TEXT,
|
||||
_mkTag("style", "class"): "text",
|
||||
})
|
||||
ET.SubElement(xStyl, _mkTag("style", "paragraph-properties"), attrib={
|
||||
@@ -815,14 +864,16 @@ class ToOdt(Tokenizer):
|
||||
_mkTag("fo", "keep-with-next"): "always",
|
||||
})
|
||||
ET.SubElement(xStyl, _mkTag("style", "text-properties"), attrib={
|
||||
_mkTag("style", "font-name"): self._textFont,
|
||||
_mkTag("style", "font-name"): self._fontFamily,
|
||||
_mkTag("fo", "font-family"): self._fontFamily,
|
||||
_mkTag("fo", "font-weight"): self._fontWeight,
|
||||
_mkTag("fo", "font-style"): self._fontStyle,
|
||||
_mkTag("fo", "font-size"): self._fSizeHead,
|
||||
})
|
||||
|
||||
# Add Header and Footer Styles
|
||||
ET.SubElement(self._xStyl, _mkTag("style", "style"), attrib={
|
||||
_mkTag("style", "name"): "Header_20_and_20_Footer",
|
||||
_mkTag("style", "name"): S_HNF,
|
||||
_mkTag("style", "display-name"): "Header and Footer",
|
||||
_mkTag("style", "family"): "paragraph",
|
||||
_mkTag("style", "parent-style-name"): "Standard",
|
||||
@@ -834,7 +885,7 @@ class ToOdt(Tokenizer):
|
||||
def _useableStyles(self) -> None:
|
||||
"""Set the usable styles."""
|
||||
# Add Text Body Style
|
||||
style = ODTParagraphStyle("Text_20_body")
|
||||
style = ODTParagraphStyle(S_TEXT)
|
||||
style.setDisplayName("Text body")
|
||||
style.setParentStyleName("Standard")
|
||||
style.setClass("text")
|
||||
@@ -842,136 +893,139 @@ class ToOdt(Tokenizer):
|
||||
style.setMarginBottom(self._mBotText)
|
||||
style.setLineHeight(self._fLineHeight)
|
||||
style.setTextAlign(self._textAlign)
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeText)
|
||||
style.setFontWeight(self._fontWeight)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add First Line Indent Style
|
||||
style = ODTParagraphStyle("First_20_line_20_indent")
|
||||
style = ODTParagraphStyle(S_FIND)
|
||||
style.setDisplayName("First line indent")
|
||||
style.setParentStyleName("Text_20_body")
|
||||
style.setParentStyleName(S_TEXT)
|
||||
style.setClass("text")
|
||||
style.setTextIndent(self._fTextIndent)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Text Meta Style
|
||||
style = ODTParagraphStyle("Text_20_Meta")
|
||||
style = ODTParagraphStyle(S_META)
|
||||
style.setDisplayName("Text Meta")
|
||||
style.setParentStyleName("Standard")
|
||||
style.setClass("text")
|
||||
style.setMarginTop(self._mTopMeta)
|
||||
style.setMarginBottom(self._mBotMeta)
|
||||
style.setLineHeight(self._fLineHeight)
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeText)
|
||||
style.setFontWeight(self._fontWeight)
|
||||
style.setColour(self._colMetaTx)
|
||||
style.setOpacity(self._opaMetaTx)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Title Style
|
||||
style = ODTParagraphStyle("Title")
|
||||
style = ODTParagraphStyle(S_TITLE)
|
||||
style.setDisplayName("Title")
|
||||
style.setParentStyleName("Heading")
|
||||
style.setNextStyleName("Text_20_body")
|
||||
style.setNextStyleName(S_TEXT)
|
||||
style.setClass("chapter")
|
||||
style.setMarginTop(self._mTopTitle)
|
||||
style.setMarginBottom(self._mBotTitle)
|
||||
style.setTextAlign("center")
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeTitle)
|
||||
style.setFontWeight("bold")
|
||||
style.setFontWeight(self._fontBold)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Separator Style
|
||||
style = ODTParagraphStyle("Separator")
|
||||
style = ODTParagraphStyle(S_SEP)
|
||||
style.setDisplayName("Separator")
|
||||
style.setParentStyleName("Standard")
|
||||
style.setNextStyleName("Text_20_body")
|
||||
style.setNextStyleName(S_TEXT)
|
||||
style.setClass("text")
|
||||
style.setMarginTop(self._mTopText)
|
||||
style.setMarginBottom(self._mBotText)
|
||||
style.setMarginTop(self._mTopSep)
|
||||
style.setMarginBottom(self._mBotSep)
|
||||
style.setLineHeight(self._fLineHeight)
|
||||
style.setTextAlign("center")
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeText)
|
||||
style.setFontWeight(self._fontWeight)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Heading 1 Style
|
||||
style = ODTParagraphStyle("Heading_20_1")
|
||||
style = ODTParagraphStyle(S_HEAD1)
|
||||
style.setDisplayName("Heading 1")
|
||||
style.setParentStyleName("Heading")
|
||||
style.setNextStyleName("Text_20_body")
|
||||
style.setNextStyleName(S_TEXT)
|
||||
style.setOutlineLevel("1")
|
||||
style.setClass("text")
|
||||
style.setMarginTop(self._mTopHead1)
|
||||
style.setMarginBottom(self._mBotHead1)
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead1)
|
||||
style.setFontWeight("bold")
|
||||
style.setFontWeight(self._fontBold)
|
||||
style.setColour(self._colHead12)
|
||||
style.setOpacity(self._opaHead12)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Heading 2 Style
|
||||
style = ODTParagraphStyle("Heading_20_2")
|
||||
style = ODTParagraphStyle(S_HEAD2)
|
||||
style.setDisplayName("Heading 2")
|
||||
style.setParentStyleName("Heading")
|
||||
style.setNextStyleName("Text_20_body")
|
||||
style.setNextStyleName(S_TEXT)
|
||||
style.setOutlineLevel("2")
|
||||
style.setClass("text")
|
||||
style.setMarginTop(self._mTopHead2)
|
||||
style.setMarginBottom(self._mBotHead2)
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead2)
|
||||
style.setFontWeight("bold")
|
||||
style.setFontWeight(self._fontBold)
|
||||
style.setColour(self._colHead12)
|
||||
style.setOpacity(self._opaHead12)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Heading 3 Style
|
||||
style = ODTParagraphStyle("Heading_20_3")
|
||||
style = ODTParagraphStyle(S_HEAD3)
|
||||
style.setDisplayName("Heading 3")
|
||||
style.setParentStyleName("Heading")
|
||||
style.setNextStyleName("Text_20_body")
|
||||
style.setNextStyleName(S_TEXT)
|
||||
style.setOutlineLevel("3")
|
||||
style.setClass("text")
|
||||
style.setMarginTop(self._mTopHead3)
|
||||
style.setMarginBottom(self._mBotHead3)
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead3)
|
||||
style.setFontWeight("bold")
|
||||
style.setFontWeight(self._fontBold)
|
||||
style.setColour(self._colHead34)
|
||||
style.setOpacity(self._opaHead34)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Heading 4 Style
|
||||
style = ODTParagraphStyle("Heading_20_4")
|
||||
style = ODTParagraphStyle(S_HEAD4)
|
||||
style.setDisplayName("Heading 4")
|
||||
style.setParentStyleName("Heading")
|
||||
style.setNextStyleName("Text_20_body")
|
||||
style.setNextStyleName(S_TEXT)
|
||||
style.setOutlineLevel("4")
|
||||
style.setClass("text")
|
||||
style.setMarginTop(self._mTopHead4)
|
||||
style.setMarginBottom(self._mBotHead4)
|
||||
style.setFontName(self._textFont)
|
||||
style.setFontName(self._fontFamily)
|
||||
style.setFontFamily(self._fontFamily)
|
||||
style.setFontSize(self._fSizeHead4)
|
||||
style.setFontWeight("bold")
|
||||
style.setFontWeight(self._fontBold)
|
||||
style.setColour(self._colHead34)
|
||||
style.setOpacity(self._opaHead34)
|
||||
style.packXML(self._xStyl)
|
||||
@@ -980,11 +1034,23 @@ class ToOdt(Tokenizer):
|
||||
# Add Header Style
|
||||
style = ODTParagraphStyle("Header")
|
||||
style.setDisplayName("Header")
|
||||
style.setParentStyleName("Header_20_and_20_Footer")
|
||||
style.setParentStyleName(S_HNF)
|
||||
style.setTextAlign("right")
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
# Add Footnote Style
|
||||
style = ODTParagraphStyle("Footnote")
|
||||
style.setDisplayName("Footnote")
|
||||
style.setParentStyleName("Standard")
|
||||
style.setClass("extra")
|
||||
style.setMarginLeft(self._mLeftFoot)
|
||||
style.setMarginBottom(self._mBotFoot)
|
||||
style.setTextIndent("-"+self._mLeftFoot)
|
||||
style.setFontSize(self._fSizeFoot)
|
||||
style.packXML(self._xStyl)
|
||||
self._mainPara[style.name] = style
|
||||
|
||||
return
|
||||
|
||||
def _writeHeader(self) -> None:
|
||||
@@ -1026,12 +1092,9 @@ class ToOdt(Tokenizer):
|
||||
|
||||
return
|
||||
|
||||
# END Class ToOdt
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# Auto-Style Classes
|
||||
# =============================================================================================== #
|
||||
# Auto-Style Classes
|
||||
# ==================
|
||||
|
||||
class ODTParagraphStyle:
|
||||
"""Wrapper class for the paragraph style setting used by the
|
||||
@@ -1041,8 +1104,8 @@ class ODTParagraphStyle:
|
||||
VALID_ALIGN = ["start", "center", "end", "justify", "inside", "outside", "left", "right"]
|
||||
VALID_BREAK = ["auto", "column", "page", "even-page", "odd-page", "inherit"]
|
||||
VALID_LEVEL = ["1", "2", "3", "4"]
|
||||
VALID_CLASS = ["text", "chapter"]
|
||||
VALID_WEIGHT = ["normal", "inherit", "bold"]
|
||||
VALID_CLASS = ["text", "chapter", "extra"]
|
||||
VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
|
||||
|
||||
def __init__(self, name: str) -> None:
|
||||
|
||||
@@ -1279,16 +1342,14 @@ class ODTParagraphStyle:
|
||||
|
||||
return
|
||||
|
||||
# END Class ODTParagraphStyle
|
||||
|
||||
|
||||
class ODTTextStyle:
|
||||
"""Wrapper class for the text style setting used by the exporter.
|
||||
Only the used settings are exposed here to keep the class minimal
|
||||
and fast.
|
||||
"""
|
||||
VALID_WEIGHT = ["normal", "inherit", "bold"]
|
||||
VALID_STYLE = ["normal", "inherit", "italic"]
|
||||
VALID_WEIGHT = ["normal", "bold"] + FONT_WEIGHT_NUM
|
||||
VALID_STYLE = ["normal", "italic", "oblique"]
|
||||
VALID_POS = ["super", "sub"]
|
||||
VALID_LSTYLE = ["none", "solid"]
|
||||
VALID_LTYPE = ["single", "double"]
|
||||
@@ -1404,12 +1465,9 @@ class ODTTextStyle:
|
||||
ET.SubElement(xEntry, _mkTag("style", "text-properties"), attrib=attr)
|
||||
return
|
||||
|
||||
# END Class ODTTextStyle
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# XML Complex Element Helper Class
|
||||
# =============================================================================================== #
|
||||
# XML Complex Element Helper Class
|
||||
# ================================
|
||||
|
||||
X_ROOT_TEXT = 0
|
||||
X_ROOT_TAIL = 1
|
||||
@@ -1464,7 +1522,6 @@ class XMLParagraph:
|
||||
if c == " ":
|
||||
nSpaces += 1
|
||||
continue
|
||||
|
||||
elif nSpaces > 0:
|
||||
self._processSpaces(nSpaces)
|
||||
nSpaces = 0
|
||||
@@ -1475,26 +1532,22 @@ class XMLParagraph:
|
||||
self._xTail.tail = ""
|
||||
self._nState = X_ROOT_TAIL
|
||||
self._chrPos += 1
|
||||
|
||||
elif self._nState in (X_SPAN_TEXT, X_SPAN_SING):
|
||||
self._xSing = ET.SubElement(self._xTail, TAG_BR)
|
||||
self._xSing.tail = ""
|
||||
self._nState = X_SPAN_SING
|
||||
self._chrPos += 1
|
||||
|
||||
elif c == "\t":
|
||||
if self._nState in (X_ROOT_TEXT, X_ROOT_TAIL):
|
||||
self._xTail = ET.SubElement(self._xRoot, TAG_TAB)
|
||||
self._xTail.tail = ""
|
||||
self._nState = X_ROOT_TAIL
|
||||
self._chrPos += 1
|
||||
|
||||
elif self._nState in (X_SPAN_TEXT, X_SPAN_SING):
|
||||
self._xSing = ET.SubElement(self._xTail, TAG_TAB)
|
||||
self._xSing.tail = ""
|
||||
self._chrPos += 1
|
||||
self._nState = X_SPAN_SING
|
||||
|
||||
else:
|
||||
if self._nState == X_ROOT_TEXT:
|
||||
self._xRoot.text = (self._xRoot.text or "") + c
|
||||
@@ -1529,6 +1582,19 @@ class XMLParagraph:
|
||||
self._nState = X_ROOT_TAIL
|
||||
return
|
||||
|
||||
def appendNode(self, xNode: ET.Element | None) -> None:
|
||||
"""Append an XML node to the paragraph. We only check for the
|
||||
X_ROOT_TEXT and X_ROOT_TAIL states. X_SPAN_TEXT is not possible
|
||||
at all, and X_SPAN_SING only happens internally in an appendSpan
|
||||
call, returning us to an X_ROOT_TAIL state.
|
||||
"""
|
||||
if xNode is not None and self._nState in (X_ROOT_TEXT, X_ROOT_TAIL):
|
||||
self._xRoot.append(xNode)
|
||||
self._xTail = xNode
|
||||
self._xTail.tail = ""
|
||||
self._nState = X_ROOT_TAIL
|
||||
return
|
||||
|
||||
def checkError(self) -> tuple[int, str]:
|
||||
"""Check that the number of characters written matches the
|
||||
number of characters received.
|
||||
@@ -1600,5 +1666,3 @@ class XMLParagraph:
|
||||
self._chrPos += nSpaces - 1
|
||||
|
||||
return
|
||||
|
||||
# END Class XMLParagraph
|
||||
|
||||
403
novelwriter/core/toqdoc.py
Normal file
403
novelwriter/core/toqdoc.py
Normal file
@@ -0,0 +1,403 @@
|
||||
"""
|
||||
novelWriter – QTextDocument Converter
|
||||
=====================================
|
||||
|
||||
File History:
|
||||
Created: 2024-05-21 [2.5b1] ToQTextDocument
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, 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/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt5.QtGui import (
|
||||
QColor, QFont, QFontMetrics, QTextBlockFormat, QTextCharFormat,
|
||||
QTextCursor, QTextDocument
|
||||
)
|
||||
|
||||
from novelwriter.constants import nwHeaders, nwHeadFmt, nwKeyWords, nwLabels, nwUnicode
|
||||
from novelwriter.core.project import NWProject
|
||||
from novelwriter.core.tokenizer import T_Formats, Tokenizer
|
||||
from novelwriter.types import (
|
||||
QtAlignAbsolute, QtAlignCenter, QtAlignJustify, QtAlignLeft, QtAlignRight,
|
||||
QtBlack, QtPageBreakAfter, QtPageBreakBefore, QtTransparent,
|
||||
QtVAlignNormal, QtVAlignSub, QtVAlignSuper
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
T_TextStyle = tuple[QTextBlockFormat, QTextCharFormat]
|
||||
|
||||
|
||||
class TextDocumentTheme:
|
||||
text: QColor = QtBlack
|
||||
highlight: QColor = QtTransparent
|
||||
head: QColor = QtBlack
|
||||
comment: QColor = QtBlack
|
||||
note: QColor = QtBlack
|
||||
code: QColor = QtBlack
|
||||
modifier: QColor = QtBlack
|
||||
keyword: QColor = QtBlack
|
||||
tag: QColor = QtBlack
|
||||
optional: QColor = QtBlack
|
||||
|
||||
|
||||
def newBlock(cursor: QTextCursor, bFmt: QTextBlockFormat) -> None:
|
||||
if cursor.position() > 0:
|
||||
cursor.insertBlock(bFmt)
|
||||
else:
|
||||
cursor.setBlockFormat(bFmt)
|
||||
|
||||
|
||||
class ToQTextDocument(Tokenizer):
|
||||
"""Core: QTextDocument Writer
|
||||
|
||||
Extend the Tokenizer class to generate a QTextDocument output. This
|
||||
is intended for usage in the document viewer and build tool preview.
|
||||
"""
|
||||
|
||||
def __init__(self, project: NWProject) -> None:
|
||||
super().__init__(project)
|
||||
self._document = QTextDocument()
|
||||
self._document.setUndoRedoEnabled(False)
|
||||
self._document.setDocumentMargin(0)
|
||||
|
||||
self._theme = TextDocumentTheme()
|
||||
self._styles: dict[int, T_TextStyle] = {}
|
||||
self._usedNotes: dict[str, int] = {}
|
||||
|
||||
self._init = False
|
||||
self._bold = QFont.Weight.Bold
|
||||
self._normal = QFont.Weight.Normal
|
||||
|
||||
return
|
||||
|
||||
def initDocument(self, font: QFont, theme: TextDocumentTheme) -> None:
|
||||
"""Initialise all computed values of the document."""
|
||||
self._textFont = font
|
||||
self._theme = theme
|
||||
|
||||
self._document.setUndoRedoEnabled(False)
|
||||
self._document.blockSignals(True)
|
||||
self._document.clear()
|
||||
self._document.setDefaultFont(self._textFont)
|
||||
|
||||
qMetric = QFontMetrics(self._textFont)
|
||||
mScale = qMetric.height()
|
||||
fPt = self._textFont.pointSizeF()
|
||||
|
||||
# Scaled Sizes
|
||||
# ============
|
||||
|
||||
self._mHead = {
|
||||
self.T_TITLE: (mScale * self._marginTitle[0], mScale * self._marginTitle[1]),
|
||||
self.T_HEAD1: (mScale * self._marginHead1[0], mScale * self._marginHead1[1]),
|
||||
self.T_HEAD2: (mScale * self._marginHead2[0], mScale * self._marginHead2[1]),
|
||||
self.T_HEAD3: (mScale * self._marginHead3[0], mScale * self._marginHead3[1]),
|
||||
self.T_HEAD4: (mScale * self._marginHead4[0], mScale * self._marginHead4[1]),
|
||||
}
|
||||
|
||||
self._sHead = {
|
||||
self.T_TITLE: nwHeaders.H_SIZES.get(0, 1.0) * fPt,
|
||||
self.T_HEAD1: nwHeaders.H_SIZES.get(1, 1.0) * fPt,
|
||||
self.T_HEAD2: nwHeaders.H_SIZES.get(2, 1.0) * fPt,
|
||||
self.T_HEAD3: nwHeaders.H_SIZES.get(3, 1.0) * fPt,
|
||||
self.T_HEAD4: nwHeaders.H_SIZES.get(4, 1.0) * fPt,
|
||||
}
|
||||
|
||||
self._mText = (mScale * self._marginText[0], mScale * self._marginText[1])
|
||||
self._mMeta = (mScale * self._marginMeta[0], mScale * self._marginMeta[1])
|
||||
self._mSep = (mScale * self._marginSep[0], mScale * self._marginSep[1])
|
||||
|
||||
self._mIndent = mScale * 2.0
|
||||
|
||||
# Block Format
|
||||
# ============
|
||||
|
||||
self._blockFmt = QTextBlockFormat()
|
||||
self._blockFmt.setTopMargin(self._mText[0])
|
||||
self._blockFmt.setBottomMargin(self._mText[1])
|
||||
self._blockFmt.setAlignment(QtAlignJustify if self._doJustify else QtAlignAbsolute)
|
||||
|
||||
# Character Formats
|
||||
# =================
|
||||
|
||||
self._cText = QTextCharFormat()
|
||||
self._cText.setBackground(QtTransparent)
|
||||
self._cText.setForeground(self._theme.text)
|
||||
|
||||
self._cHead = QTextCharFormat(self._cText)
|
||||
self._cHead.setForeground(self._theme.head)
|
||||
|
||||
self._cComment = QTextCharFormat(self._cText)
|
||||
self._cComment.setForeground(self._theme.comment)
|
||||
|
||||
self._cCommentMod = QTextCharFormat(self._cText)
|
||||
self._cCommentMod.setForeground(self._theme.comment)
|
||||
self._cCommentMod.setFontWeight(self._bold)
|
||||
|
||||
self._cNote = QTextCharFormat(self._cText)
|
||||
self._cNote.setForeground(self._theme.note)
|
||||
|
||||
self._cCode = QTextCharFormat(self._cText)
|
||||
self._cCode.setForeground(self._theme.code)
|
||||
|
||||
self._cModifier = QTextCharFormat(self._cText)
|
||||
self._cModifier.setForeground(self._theme.modifier)
|
||||
self._cModifier.setFontWeight(self._bold)
|
||||
|
||||
self._cKeyword = QTextCharFormat(self._cText)
|
||||
self._cKeyword.setForeground(self._theme.keyword)
|
||||
|
||||
self._cTag = QTextCharFormat(self._cText)
|
||||
self._cTag.setForeground(self._theme.tag)
|
||||
|
||||
self._cOptional = QTextCharFormat(self._cText)
|
||||
self._cOptional.setForeground(self._theme.optional)
|
||||
|
||||
self._init = True
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Properties
|
||||
##
|
||||
|
||||
@property
|
||||
def document(self) -> QTextDocument:
|
||||
"""Return the document."""
|
||||
return self._document
|
||||
|
||||
##
|
||||
# Class Methods
|
||||
##
|
||||
|
||||
def doConvert(self) -> None:
|
||||
"""Write text tokens into the document."""
|
||||
if not self._init:
|
||||
return
|
||||
|
||||
self._document.blockSignals(True)
|
||||
cursor = QTextCursor(self._document)
|
||||
cursor.movePosition(QTextCursor.MoveOperation.End)
|
||||
|
||||
for tType, nHead, tText, tFormat, tStyle in self._tokens:
|
||||
|
||||
# Styles
|
||||
bFmt = QTextBlockFormat(self._blockFmt)
|
||||
if tStyle is not None:
|
||||
if tStyle & self.A_LEFT:
|
||||
bFmt.setAlignment(QtAlignLeft)
|
||||
elif tStyle & self.A_RIGHT:
|
||||
bFmt.setAlignment(QtAlignRight)
|
||||
elif tStyle & self.A_CENTRE:
|
||||
bFmt.setAlignment(QtAlignCenter)
|
||||
elif tStyle & self.A_JUSTIFY:
|
||||
bFmt.setAlignment(QtAlignJustify)
|
||||
|
||||
if tStyle & self.A_PBB:
|
||||
bFmt.setPageBreakPolicy(QtPageBreakBefore)
|
||||
if tStyle & self.A_PBA:
|
||||
bFmt.setPageBreakPolicy(QtPageBreakAfter)
|
||||
|
||||
if tStyle & self.A_Z_BTMMRG:
|
||||
bFmt.setBottomMargin(0.0)
|
||||
if tStyle & self.A_Z_TOPMRG:
|
||||
bFmt.setTopMargin(0.0)
|
||||
|
||||
if tStyle & self.A_IND_L:
|
||||
bFmt.setLeftMargin(self._mIndent)
|
||||
if tStyle & self.A_IND_R:
|
||||
bFmt.setRightMargin(self._mIndent)
|
||||
|
||||
if tType == self.T_TEXT:
|
||||
newBlock(cursor, bFmt)
|
||||
self._insertFragments(tText, tFormat, cursor, self._cText)
|
||||
|
||||
elif tType in self.L_HEADINGS:
|
||||
bFmt, cFmt = self._genHeadStyle(tType, nHead, bFmt)
|
||||
newBlock(cursor, bFmt)
|
||||
cursor.insertText(tText.replace(nwHeadFmt.BR, "\n"), cFmt)
|
||||
|
||||
elif tType == self.T_SEP:
|
||||
sFmt = QTextBlockFormat(bFmt)
|
||||
sFmt.setTopMargin(self._mSep[0])
|
||||
sFmt.setBottomMargin(self._mSep[1])
|
||||
newBlock(cursor, sFmt)
|
||||
cursor.insertText(tText, self._cText)
|
||||
|
||||
elif tType == self.T_SKIP:
|
||||
newBlock(cursor, bFmt)
|
||||
cursor.insertText(nwUnicode.U_NBSP, self._cText)
|
||||
|
||||
elif tType in self.L_SUMMARY and self._doSynopsis:
|
||||
newBlock(cursor, bFmt)
|
||||
modifier = self._localLookup(
|
||||
"Short Description" if tType == self.T_SHORT else "Synopsis"
|
||||
)
|
||||
cursor.insertText(f"{modifier}: ", self._cModifier)
|
||||
self._insertFragments(tText, tFormat, cursor, self._cNote)
|
||||
|
||||
elif tType == self.T_COMMENT and self._doComments:
|
||||
newBlock(cursor, bFmt)
|
||||
modifier = self._localLookup("Comment")
|
||||
cursor.insertText(f"{modifier}: ", self._cCommentMod)
|
||||
self._insertFragments(tText, tFormat, cursor, self._cComment)
|
||||
|
||||
elif tType == self.T_KEYWORD and self._doKeywords:
|
||||
newBlock(cursor, bFmt)
|
||||
self._insertKeywords(tText, cursor)
|
||||
|
||||
self._document.blockSignals(False)
|
||||
|
||||
return
|
||||
|
||||
def appendFootnotes(self) -> None:
|
||||
"""Append the footnotes in the buffer."""
|
||||
if self._usedNotes:
|
||||
self._document.blockSignals(True)
|
||||
|
||||
cursor = QTextCursor(self._document)
|
||||
cursor.movePosition(QTextCursor.MoveOperation.End)
|
||||
|
||||
bFmt, cFmt = self._genHeadStyle(self.T_HEAD4, -1, self._blockFmt)
|
||||
newBlock(cursor, bFmt)
|
||||
cursor.insertText(self._localLookup("Footnotes"), cFmt)
|
||||
|
||||
for key, index in self._usedNotes.items():
|
||||
if content := self._footnotes.get(key):
|
||||
cFmt = QTextCharFormat(self._cCode)
|
||||
cFmt.setAnchor(True)
|
||||
cFmt.setAnchorNames([f"footnote_{index}"])
|
||||
newBlock(cursor, self._blockFmt)
|
||||
cursor.insertText(f"{index}. ", cFmt)
|
||||
self._insertFragments(*content, cursor, self._cText)
|
||||
|
||||
self._document.blockSignals(False)
|
||||
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _insertFragments(
|
||||
self, text: str, tFmt: T_Formats, cursor: QTextCursor, dFmt: QTextCharFormat
|
||||
) -> None:
|
||||
"""Apply formatting tags to text."""
|
||||
cFmt = QTextCharFormat(dFmt)
|
||||
start = 0
|
||||
temp = text.replace("\n", nwUnicode.U_LSEP)
|
||||
for pos, fmt, data in tFmt:
|
||||
|
||||
# Insert buffer with previous format
|
||||
cursor.insertText(temp[start:pos], cFmt)
|
||||
|
||||
# Construct next format
|
||||
if fmt == self.FMT_B_B:
|
||||
cFmt.setFontWeight(self._bold)
|
||||
elif fmt == self.FMT_B_E:
|
||||
cFmt.setFontWeight(self._normal)
|
||||
elif fmt == self.FMT_I_B:
|
||||
cFmt.setFontItalic(True)
|
||||
elif fmt == self.FMT_I_E:
|
||||
cFmt.setFontItalic(False)
|
||||
elif fmt == self.FMT_D_B:
|
||||
cFmt.setFontStrikeOut(True)
|
||||
elif fmt == self.FMT_D_E:
|
||||
cFmt.setFontStrikeOut(False)
|
||||
elif fmt == self.FMT_U_B:
|
||||
cFmt.setFontUnderline(True)
|
||||
elif fmt == self.FMT_U_E:
|
||||
cFmt.setFontUnderline(False)
|
||||
elif fmt == self.FMT_M_B:
|
||||
cFmt.setBackground(self._theme.highlight)
|
||||
elif fmt == self.FMT_M_E:
|
||||
cFmt.setBackground(QtTransparent)
|
||||
elif fmt == self.FMT_SUP_B:
|
||||
cFmt.setVerticalAlignment(QtVAlignSuper)
|
||||
elif fmt == self.FMT_SUP_E:
|
||||
cFmt.setVerticalAlignment(QtVAlignNormal)
|
||||
elif fmt == self.FMT_SUB_B:
|
||||
cFmt.setVerticalAlignment(QtVAlignSub)
|
||||
elif fmt == self.FMT_SUB_E:
|
||||
cFmt.setVerticalAlignment(QtVAlignNormal)
|
||||
elif fmt == self.FMT_FNOTE:
|
||||
xFmt = QTextCharFormat(self._cCode)
|
||||
xFmt.setVerticalAlignment(QtVAlignSuper)
|
||||
if data in self._footnotes:
|
||||
index = len(self._usedNotes) + 1
|
||||
self._usedNotes[data] = index
|
||||
xFmt.setAnchor(True)
|
||||
xFmt.setAnchorHref(f"#footnote_{index}")
|
||||
xFmt.setFontUnderline(True)
|
||||
cursor.insertText(f"[{index}]", xFmt)
|
||||
else:
|
||||
cursor.insertText("[ERR]", cFmt)
|
||||
|
||||
# Move pos for next pass
|
||||
start = pos
|
||||
|
||||
# Insert whatever is left in the buffer
|
||||
cursor.insertText(temp[start:], cFmt)
|
||||
|
||||
return
|
||||
|
||||
def _insertKeywords(self, text: str, cursor: QTextCursor) -> None:
|
||||
"""Apply Markdown formatting to keywords."""
|
||||
valid, bits, _ = self._project.index.scanThis("@"+text)
|
||||
if valid and bits:
|
||||
key = f"{self._localLookup(nwLabels.KEY_NAME[bits[0]])}: "
|
||||
cursor.insertText(key, self._cKeyword)
|
||||
if (num := len(bits)) > 1:
|
||||
if bits[0] == nwKeyWords.TAG_KEY:
|
||||
one, two = self._project.index.parseValue(bits[1])
|
||||
cFmt = QTextCharFormat(self._cTag)
|
||||
cFmt.setAnchor(True)
|
||||
cFmt.setAnchorNames([f"tag_{one}".lower()])
|
||||
cursor.insertText(one, cFmt)
|
||||
if two:
|
||||
cursor.insertText(" | ", self._cText)
|
||||
cursor.insertText(two, self._cOptional)
|
||||
else:
|
||||
for n, bit in enumerate(bits[1:], 2):
|
||||
cFmt = QTextCharFormat(self._cTag)
|
||||
cFmt.setFontUnderline(True)
|
||||
cFmt.setAnchor(True)
|
||||
cFmt.setAnchorHref(f"#tag_{bit}".lower())
|
||||
cursor.insertText(bit, cFmt)
|
||||
if n < num:
|
||||
cursor.insertText(", ", self._cText)
|
||||
return
|
||||
|
||||
def _genHeadStyle(self, hType: int, nHead: int, rFmt: QTextBlockFormat) -> T_TextStyle:
|
||||
"""Generate a heading style set."""
|
||||
mTop, mBottom = self._mHead.get(hType, (0.0, 0.0))
|
||||
|
||||
bFmt = QTextBlockFormat(rFmt)
|
||||
bFmt.setTopMargin(mTop)
|
||||
bFmt.setBottomMargin(mBottom)
|
||||
|
||||
cFmt = QTextCharFormat(self._cText if hType == self.T_TITLE else self._cHead)
|
||||
cFmt.setFontWeight(self._bold)
|
||||
cFmt.setFontPointSize(self._sHead.get(hType, 1.0))
|
||||
if nHead >= 0:
|
||||
cFmt.setAnchorNames([f"{self._handle}:T{nHead:04d}"])
|
||||
cFmt.setAnchor(True)
|
||||
|
||||
return bFmt, cFmt
|
||||
@@ -23,18 +23,18 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import logging
|
||||
import random
|
||||
|
||||
from typing import TYPE_CHECKING, Literal, overload
|
||||
from pathlib import Path
|
||||
from collections.abc import Iterable, Iterator
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Literal, overload
|
||||
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
from novelwriter.common import isHandle
|
||||
from novelwriter.constants import nwFiles
|
||||
from novelwriter.core.item import NWItem
|
||||
from novelwriter.enum import nwItemClass, nwItemLayout, nwItemType
|
||||
from novelwriter.error import logException
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.core.project import NWProject
|
||||
@@ -520,5 +520,3 @@ class NWTree:
|
||||
handle = self._makeHandle()
|
||||
|
||||
return handle
|
||||
|
||||
# END Class NWTree
|
||||
|
||||
@@ -27,20 +27,20 @@ import logging
|
||||
|
||||
from PyQt5.QtGui import QCloseEvent, QColor
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout,
|
||||
QWidget
|
||||
QDialogButtonBox, QHBoxLayout, QLabel, QTextBrowser, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import cssCol, readTextFile
|
||||
from novelwriter.extensions.configlayout import NColourLabel
|
||||
from novelwriter.extensions.modified import NNonBlockingDialog
|
||||
from novelwriter.extensions.versioninfo import VersionInfoWidget
|
||||
from novelwriter.types import QtAlignRightTop, QtDialogClose
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GuiAbout(QDialog):
|
||||
class GuiAbout(NNonBlockingDialog):
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
@@ -152,5 +152,3 @@ class GuiAbout(QDialog):
|
||||
f"QTextBrowser {{border: none; background: {baseCol};}} "
|
||||
)
|
||||
return
|
||||
|
||||
# END Class GuiAbout
|
||||
|
||||
@@ -34,8 +34,8 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.extensions.configlayout import NColourLabel
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.types import QtDialogCancel, QtDialogOk, QtDialogReset, QtUserRole
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -182,5 +182,3 @@ class GuiDocMerge(QDialog):
|
||||
self.listBox.addItem(newItem)
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiDocMerge
|
||||
|
||||
@@ -34,8 +34,8 @@ from PyQt5.QtWidgets import (
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.extensions.configlayout import NColourLabel
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.types import QtDialogCancel, QtDialogOk, QtUserRole
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -257,5 +257,3 @@ class GuiDocSplit(QDialog):
|
||||
self.listBox.addItem(newItem)
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiDocSplit
|
||||
|
||||
@@ -94,5 +94,3 @@ class GuiEditLabel(QDialog):
|
||||
accepted = cls.result() == QDialog.DialogCode.Accepted
|
||||
cls.deleteLater()
|
||||
return label, accepted
|
||||
|
||||
# END Class GuiEditLabel
|
||||
|
||||
@@ -27,14 +27,14 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QCloseEvent, QFont, QKeyEvent, QKeySequence
|
||||
from PyQt5.QtGui import QCloseEvent, QKeyEvent, QKeySequence
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractButton, QApplication, QCompleter, QDialog, QDialogButtonBox,
|
||||
QFileDialog, QFontDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout,
|
||||
QWidget
|
||||
QFileDialog, QHBoxLayout, QLineEdit, QPushButton, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import describeFont
|
||||
from novelwriter.constants import nwConst, nwUnicode
|
||||
from novelwriter.dialogs.quotes import GuiQuoteSelect
|
||||
from novelwriter.extensions.configlayout import NColourLabel, NScrollableForm
|
||||
@@ -133,7 +133,13 @@ class GuiPreferences(QDialog):
|
||||
"""Build the settings form."""
|
||||
section = 0
|
||||
iSz = SHARED.theme.baseIconSize
|
||||
boxFixed = 5*SHARED.theme.textNWidth
|
||||
minWidth = CONFIG.pxInt(200)
|
||||
fontWidth = CONFIG.pxInt(162)
|
||||
|
||||
# Temporary Variables
|
||||
self._guiFont = CONFIG.guiFont
|
||||
self._textFont = CONFIG.textFont
|
||||
|
||||
# Label
|
||||
self.sidebar.addLabel(self.tr("General"))
|
||||
@@ -173,27 +179,17 @@ class GuiPreferences(QDialog):
|
||||
# Application Font Family
|
||||
self.guiFont = QLineEdit(self)
|
||||
self.guiFont.setReadOnly(True)
|
||||
self.guiFont.setMinimumWidth(CONFIG.pxInt(162))
|
||||
self.guiFont.setText(CONFIG.guiFont)
|
||||
self.guiFontButton = NIconToolButton(self, iSz, "more")
|
||||
self.guiFont.setMinimumWidth(fontWidth)
|
||||
self.guiFont.setText(describeFont(self._guiFont))
|
||||
self.guiFont.setCursorPosition(0)
|
||||
self.guiFontButton = NIconToolButton(self, iSz, "font")
|
||||
self.guiFontButton.clicked.connect(self._selectGuiFont)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Application font family"), self.guiFont,
|
||||
self.tr("Application font"), self.guiFont,
|
||||
self.tr("Requires restart to take effect."), stretch=(3, 2),
|
||||
button=self.guiFontButton
|
||||
)
|
||||
|
||||
# Application Font Size
|
||||
self.guiFontSize = NSpinBox(self)
|
||||
self.guiFontSize.setMinimum(8)
|
||||
self.guiFontSize.setMaximum(60)
|
||||
self.guiFontSize.setSingleStep(1)
|
||||
self.guiFontSize.setValue(CONFIG.guiFontSize)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Application font size"), self.guiFontSize,
|
||||
self.tr("Requires restart to take effect."), unit=self.tr("pt")
|
||||
)
|
||||
|
||||
# Vertical Scrollbars
|
||||
self.hideVScroll = NSwitch(self)
|
||||
self.hideVScroll.setChecked(CONFIG.hideVScroll)
|
||||
@@ -210,6 +206,14 @@ class GuiPreferences(QDialog):
|
||||
self.tr("Scrolling available with mouse wheel and keys only.")
|
||||
)
|
||||
|
||||
# Native Font Dialog
|
||||
self.nativeFont = NSwitch(self)
|
||||
self.nativeFont.setChecked(CONFIG.nativeFont)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Use the system's font selection dialog"), self.nativeFont,
|
||||
self.tr("Turn off to use the Qt font dialog, which may have more options.")
|
||||
)
|
||||
|
||||
# Document Style
|
||||
# ==============
|
||||
|
||||
@@ -233,27 +237,17 @@ class GuiPreferences(QDialog):
|
||||
# Document Font Family
|
||||
self.textFont = QLineEdit(self)
|
||||
self.textFont.setReadOnly(True)
|
||||
self.textFont.setMinimumWidth(CONFIG.pxInt(162))
|
||||
self.textFont.setText(CONFIG.textFont)
|
||||
self.textFontButton = NIconToolButton(self, iSz, "more")
|
||||
self.textFont.setMinimumWidth(fontWidth)
|
||||
self.textFont.setText(describeFont(CONFIG.textFont))
|
||||
self.textFont.setCursorPosition(0)
|
||||
self.textFontButton = NIconToolButton(self, iSz, "font")
|
||||
self.textFontButton.clicked.connect(self._selectTextFont)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Document font family"), self.textFont,
|
||||
self.tr("Document font"), self.textFont,
|
||||
self.tr("Applies to both document editor and viewer."), stretch=(3, 2),
|
||||
button=self.textFontButton
|
||||
)
|
||||
|
||||
# Document Font Size
|
||||
self.textSize = NSpinBox(self)
|
||||
self.textSize.setMinimum(8)
|
||||
self.textSize.setMaximum(60)
|
||||
self.textSize.setSingleStep(1)
|
||||
self.textSize.setValue(CONFIG.textSize)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Document font size"), self.textSize,
|
||||
self.tr("Applies to both document editor and viewer."), unit=self.tr("pt")
|
||||
)
|
||||
|
||||
# Emphasise Labels
|
||||
self.emphLabels = NSwitch(self)
|
||||
self.emphLabels.setChecked(CONFIG.emphLabels)
|
||||
@@ -538,26 +532,59 @@ class GuiPreferences(QDialog):
|
||||
self.sidebar.addButton(title, section)
|
||||
self.mainForm.addGroupLabel(title, section)
|
||||
|
||||
self.highlightQuotes = NSwitch(self)
|
||||
self.highlightQuotes.setChecked(CONFIG.highlightQuotes)
|
||||
self.highlightQuotes.toggled.connect(self._toggleHighlightQuotes)
|
||||
self.dialogStyle = NComboBox(self)
|
||||
self.dialogStyle.addItem(self.tr("None"), 0)
|
||||
self.dialogStyle.addItem(self.tr("Single Quotes"), 1)
|
||||
self.dialogStyle.addItem(self.tr("Double Quotes"), 2)
|
||||
self.dialogStyle.addItem(self.tr("Both"), 3)
|
||||
self.dialogStyle.setCurrentData(CONFIG.dialogStyle, 2)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Highlight text wrapped in quotes"), self.highlightQuotes,
|
||||
self.tr("Applies to the document editor only.")
|
||||
self.tr("Highlight dialogue"), self.dialogStyle,
|
||||
self.tr("Applies to the selected quote styles.")
|
||||
)
|
||||
|
||||
self.allowOpenSQuote = NSwitch(self)
|
||||
self.allowOpenSQuote.setChecked(CONFIG.allowOpenSQuote)
|
||||
self.allowOpenDial = NSwitch(self)
|
||||
self.allowOpenDial.setChecked(CONFIG.allowOpenDial)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Allow open-ended single quotes"), self.allowOpenSQuote,
|
||||
self.tr("Highlight single-quoted line with no closing quote.")
|
||||
self.tr("Allow open-ended sialogue"), self.allowOpenDial,
|
||||
self.tr("Highlight dialogue line with no closing quote.")
|
||||
)
|
||||
|
||||
self.allowOpenDQuote = NSwitch(self)
|
||||
self.allowOpenDQuote.setChecked(CONFIG.allowOpenDQuote)
|
||||
self.narratorBreak = QLineEdit(self)
|
||||
self.narratorBreak.setMaxLength(1)
|
||||
self.narratorBreak.setFixedWidth(boxFixed)
|
||||
self.narratorBreak.setAlignment(QtAlignCenter)
|
||||
self.narratorBreak.setText(CONFIG.narratorBreak)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Allow open-ended double quotes"), self.allowOpenDQuote,
|
||||
self.tr("Highlight double-quoted line with no closing quote.")
|
||||
self.tr("Dialogue narrator break symbol"), self.narratorBreak,
|
||||
self.tr("Symbol to indicate injected narrator break.")
|
||||
)
|
||||
|
||||
self.dialogLine = QLineEdit(self)
|
||||
self.dialogLine.setMaxLength(1)
|
||||
self.dialogLine.setFixedWidth(boxFixed)
|
||||
self.dialogLine.setAlignment(QtAlignCenter)
|
||||
self.dialogLine.setText(CONFIG.dialogLine)
|
||||
self.mainForm.addRow(
|
||||
self.tr("Dialogue line symbol"), self.dialogLine,
|
||||
self.tr("Lines starting with this symbol are dialogue.")
|
||||
)
|
||||
|
||||
self.altDialogOpen = QLineEdit(self)
|
||||
self.altDialogOpen.setMaxLength(4)
|
||||
self.altDialogOpen.setFixedWidth(boxFixed)
|
||||
self.altDialogOpen.setAlignment(QtAlignCenter)
|
||||
self.altDialogOpen.setText(CONFIG.altDialogOpen)
|
||||
|
||||
self.altDialogClose = QLineEdit(self)
|
||||
self.altDialogClose.setMaxLength(4)
|
||||
self.altDialogClose.setFixedWidth(boxFixed)
|
||||
self.altDialogClose.setAlignment(QtAlignCenter)
|
||||
self.altDialogClose.setText(CONFIG.altDialogClose)
|
||||
|
||||
self.mainForm.addRow(
|
||||
self.tr("Alternative dialog symbols"), [self.altDialogOpen, self.altDialogClose],
|
||||
self.tr("Custom highlighting of dialog text.")
|
||||
)
|
||||
|
||||
self.highlightEmph = NSwitch(self)
|
||||
@@ -667,16 +694,15 @@ class GuiPreferences(QDialog):
|
||||
self.mainForm.addGroupLabel(title, section)
|
||||
|
||||
self.quoteSym = {}
|
||||
qWidth = CONFIG.pxInt(40)
|
||||
|
||||
# Single Quote Style
|
||||
self.quoteSym["SO"] = QLineEdit(self)
|
||||
self.quoteSym["SO"].setMaxLength(1)
|
||||
self.quoteSym["SO"].setReadOnly(True)
|
||||
self.quoteSym["SO"].setFixedWidth(qWidth)
|
||||
self.quoteSym["SO"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["SO"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["SO"].setText(CONFIG.fmtSQuoteOpen)
|
||||
self.btnSingleStyleO = NIconToolButton(self, iSz, "more")
|
||||
self.btnSingleStyleO = NIconToolButton(self, iSz, "quote")
|
||||
self.btnSingleStyleO.clicked.connect(lambda: self._getQuote("SO"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Single quote open style"), self.quoteSym["SO"],
|
||||
@@ -687,10 +713,10 @@ class GuiPreferences(QDialog):
|
||||
self.quoteSym["SC"] = QLineEdit(self)
|
||||
self.quoteSym["SC"].setMaxLength(1)
|
||||
self.quoteSym["SC"].setReadOnly(True)
|
||||
self.quoteSym["SC"].setFixedWidth(qWidth)
|
||||
self.quoteSym["SC"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["SC"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["SC"].setText(CONFIG.fmtSQuoteClose)
|
||||
self.btnSingleStyleC = NIconToolButton(self, iSz, "more")
|
||||
self.btnSingleStyleC = NIconToolButton(self, iSz, "quote")
|
||||
self.btnSingleStyleC.clicked.connect(lambda: self._getQuote("SC"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Single quote close style"), self.quoteSym["SC"],
|
||||
@@ -702,10 +728,10 @@ class GuiPreferences(QDialog):
|
||||
self.quoteSym["DO"] = QLineEdit(self)
|
||||
self.quoteSym["DO"].setMaxLength(1)
|
||||
self.quoteSym["DO"].setReadOnly(True)
|
||||
self.quoteSym["DO"].setFixedWidth(qWidth)
|
||||
self.quoteSym["DO"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["DO"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["DO"].setText(CONFIG.fmtDQuoteOpen)
|
||||
self.btnDoubleStyleO = NIconToolButton(self, iSz, "more")
|
||||
self.btnDoubleStyleO = NIconToolButton(self, iSz, "quote")
|
||||
self.btnDoubleStyleO.clicked.connect(lambda: self._getQuote("DO"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Double quote open style"), self.quoteSym["DO"],
|
||||
@@ -716,10 +742,10 @@ class GuiPreferences(QDialog):
|
||||
self.quoteSym["DC"] = QLineEdit(self)
|
||||
self.quoteSym["DC"].setMaxLength(1)
|
||||
self.quoteSym["DC"].setReadOnly(True)
|
||||
self.quoteSym["DC"].setFixedWidth(qWidth)
|
||||
self.quoteSym["DC"].setFixedWidth(boxFixed)
|
||||
self.quoteSym["DC"].setAlignment(QtAlignCenter)
|
||||
self.quoteSym["DC"].setText(CONFIG.fmtDQuoteClose)
|
||||
self.btnDoubleStyleC = NIconToolButton(self, iSz, "more")
|
||||
self.btnDoubleStyleC = NIconToolButton(self, iSz, "quote")
|
||||
self.btnDoubleStyleC.clicked.connect(lambda: self._getQuote("DC"))
|
||||
self.mainForm.addRow(
|
||||
self.tr("Double quote close style"), self.quoteSym["DC"],
|
||||
@@ -785,25 +811,21 @@ class GuiPreferences(QDialog):
|
||||
@pyqtSlot()
|
||||
def _selectGuiFont(self) -> None:
|
||||
"""Open the QFontDialog and set a font for the font style."""
|
||||
current = QFont()
|
||||
current.setFamily(CONFIG.guiFont)
|
||||
current.setPointSize(CONFIG.guiFontSize)
|
||||
font, status = QFontDialog.getFont(current, self)
|
||||
font, status = SHARED.getFont(self._guiFont, self.nativeFont.isChecked())
|
||||
if status:
|
||||
self.guiFont.setText(font.family())
|
||||
self.guiFontSize.setValue(font.pointSize())
|
||||
self.guiFont.setText(describeFont(font))
|
||||
self.guiFont.setCursorPosition(0)
|
||||
self._guiFont = font
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectTextFont(self) -> None:
|
||||
"""Open the QFontDialog and set a font for the font style."""
|
||||
current = QFont()
|
||||
current.setFamily(CONFIG.textFont)
|
||||
current.setPointSize(CONFIG.textSize)
|
||||
font, status = QFontDialog.getFont(current, self)
|
||||
font, status = SHARED.getFont(self._textFont, self.nativeFont.isChecked())
|
||||
if status:
|
||||
self.textFont.setText(font.family())
|
||||
self.textSize.setValue(font.pointSize())
|
||||
self.textFont.setText(describeFont(font))
|
||||
self.textFont.setCursorPosition(0)
|
||||
self._textFont = font
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
@@ -823,13 +845,6 @@ class GuiPreferences(QDialog):
|
||||
self.askBeforeBackup.setEnabled(state)
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _toggleHighlightQuotes(self, state: bool) -> None:
|
||||
"""Toggle switches controlled by the highlight quotes switch."""
|
||||
self.allowOpenSQuote.setEnabled(state)
|
||||
self.allowOpenDQuote.setEnabled(state)
|
||||
return
|
||||
|
||||
@pyqtSlot(bool)
|
||||
def _toggleAutoReplaceMain(self, state: bool) -> None:
|
||||
"""Toggle switches controlled by the auto replace switch."""
|
||||
@@ -866,20 +881,17 @@ class GuiPreferences(QDialog):
|
||||
# Appearance
|
||||
guiLocale = self.guiLocale.currentData()
|
||||
guiTheme = self.guiTheme.currentData()
|
||||
guiFont = self.guiFont.text()
|
||||
guiFontSize = self.guiFontSize.value()
|
||||
|
||||
updateTheme |= CONFIG.guiTheme != guiTheme
|
||||
needsRestart |= CONFIG.guiLocale != guiLocale
|
||||
needsRestart |= CONFIG.guiFont != guiFont
|
||||
needsRestart |= CONFIG.guiFontSize != guiFontSize
|
||||
needsRestart |= CONFIG.guiFont != self._guiFont
|
||||
|
||||
CONFIG.guiLocale = guiLocale
|
||||
CONFIG.guiTheme = guiTheme
|
||||
CONFIG.guiFont = guiFont
|
||||
CONFIG.guiFontSize = guiFontSize
|
||||
CONFIG.hideVScroll = self.hideVScroll.isChecked()
|
||||
CONFIG.hideHScroll = self.hideHScroll.isChecked()
|
||||
CONFIG.nativeFont = self.nativeFont.isChecked()
|
||||
CONFIG.setGuiFont(self._guiFont)
|
||||
|
||||
# Document Style
|
||||
guiSyntax = self.guiSyntax.currentData()
|
||||
@@ -892,7 +904,7 @@ class GuiPreferences(QDialog):
|
||||
CONFIG.emphLabels = emphLabels
|
||||
CONFIG.showFullPath = self.showFullPath.isChecked()
|
||||
CONFIG.incNotesWCount = self.incNotesWCount.isChecked()
|
||||
CONFIG.setTextFont(self.textFont.text(), self.textSize.value())
|
||||
CONFIG.setTextFont(self._textFont)
|
||||
|
||||
# Auto Save
|
||||
CONFIG.autoSaveDoc = self.autoSaveDoc.value()
|
||||
@@ -927,19 +939,32 @@ class GuiPreferences(QDialog):
|
||||
CONFIG.scrollPastEnd = self.scrollPastEnd.isChecked()
|
||||
|
||||
# Text Highlighting
|
||||
highlightQuotes = self.highlightQuotes.isChecked()
|
||||
dialogueStyle = self.dialogStyle.currentData()
|
||||
allowOpenDial = self.allowOpenDial.isChecked()
|
||||
narratorBreak = self.narratorBreak.text()
|
||||
dialogueLine = self.dialogLine.text()
|
||||
altDialogOpen = self.altDialogOpen.text()
|
||||
altDialogClose = self.altDialogClose.text()
|
||||
highlightEmph = self.highlightEmph.isChecked()
|
||||
showMultiSpaces = self.showMultiSpaces.isChecked()
|
||||
|
||||
updateSyntax |= CONFIG.highlightQuotes != highlightQuotes
|
||||
updateSyntax |= CONFIG.dialogStyle != dialogueStyle
|
||||
updateSyntax |= CONFIG.allowOpenDial != allowOpenDial
|
||||
updateSyntax |= CONFIG.narratorBreak != narratorBreak
|
||||
updateSyntax |= CONFIG.dialogLine != dialogueLine
|
||||
updateSyntax |= CONFIG.altDialogOpen != altDialogOpen
|
||||
updateSyntax |= CONFIG.altDialogClose != altDialogClose
|
||||
updateSyntax |= CONFIG.highlightEmph != highlightEmph
|
||||
updateSyntax |= CONFIG.showMultiSpaces != showMultiSpaces
|
||||
|
||||
CONFIG.highlightQuotes = highlightQuotes
|
||||
CONFIG.dialogStyle = dialogueStyle
|
||||
CONFIG.allowOpenDial = allowOpenDial
|
||||
CONFIG.narratorBreak = narratorBreak
|
||||
CONFIG.dialogLine = dialogueLine
|
||||
CONFIG.altDialogOpen = altDialogOpen
|
||||
CONFIG.altDialogClose = altDialogClose
|
||||
CONFIG.highlightEmph = highlightEmph
|
||||
CONFIG.showMultiSpaces = showMultiSpaces
|
||||
CONFIG.allowOpenSQuote = self.allowOpenSQuote.isChecked()
|
||||
CONFIG.allowOpenDQuote = self.allowOpenDQuote.isChecked()
|
||||
|
||||
# Text Automation
|
||||
CONFIG.doReplace = self.doReplace.isChecked()
|
||||
@@ -962,5 +987,3 @@ class GuiPreferences(QDialog):
|
||||
self.newPreferencesReady.emit(needsRestart, refreshTree, updateTheme, updateSyntax)
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiPreferences
|
||||
|
||||
@@ -27,20 +27,26 @@ from __future__ import annotations
|
||||
import logging
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QCloseEvent, QColor, QIcon, QPixmap
|
||||
from PyQt5.QtGui import QCloseEvent, QColor
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QColorDialog, QDialog, QDialogButtonBox, QHBoxLayout,
|
||||
QLineEdit, QPushButton, QStackedWidget, QTreeWidget, QTreeWidgetItem,
|
||||
QVBoxLayout, QWidget
|
||||
QAbstractItemView, QApplication, QColorDialog, QDialog, QDialogButtonBox,
|
||||
QHBoxLayout, QLineEdit, QMenu, QStackedWidget, QToolButton, QTreeWidget,
|
||||
QTreeWidgetItem, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.common import simplified
|
||||
from novelwriter.constants import nwLabels, trConst
|
||||
from novelwriter.core.status import NWStatus, StatusEntry
|
||||
from novelwriter.enum import nwStatusShape
|
||||
from novelwriter.extensions.configlayout import NColourLabel, NFixedPage, NScrollableForm
|
||||
from novelwriter.extensions.modified import NComboBox, NIconToolButton
|
||||
from novelwriter.extensions.pagedsidebar import NPagedSideBar
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.types import QtDialogCancel, QtDialogSave, QtUserRole
|
||||
from novelwriter.types import (
|
||||
QtDialogCancel, QtDialogSave, QtSizeMinimum, QtSizeMinimumExpanding,
|
||||
QtUserRole
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -179,19 +185,19 @@ class GuiProjectSettings(QDialog):
|
||||
|
||||
rebuildTrees = False
|
||||
|
||||
if self.statusPage.wasChanged:
|
||||
newList, delList = self.statusPage.getNewList()
|
||||
project.setStatusColours(newList, delList)
|
||||
if self.statusPage.changed:
|
||||
logger.debug("Updating status labels")
|
||||
project.data.itemStatus.update(self.statusPage.getNewList())
|
||||
rebuildTrees = True
|
||||
|
||||
if self.importPage.wasChanged:
|
||||
newList, delList = self.importPage.getNewList()
|
||||
project.setImportColours(newList, delList)
|
||||
if self.importPage.changed:
|
||||
logger.debug("Updating importance labels")
|
||||
project.data.itemImport.update(self.importPage.getNewList())
|
||||
rebuildTrees = True
|
||||
|
||||
if self.replacePage.wasChanged:
|
||||
newList = self.replacePage.getNewList()
|
||||
project.data.setAutoReplace(newList)
|
||||
if self.replacePage.changed:
|
||||
logger.debug("Updating auto-replace settings")
|
||||
project.data.setAutoReplace(self.replacePage.getNewList())
|
||||
|
||||
self.newProjectSettingsReady.emit(rebuildTrees)
|
||||
QApplication.processEvents()
|
||||
@@ -221,8 +227,6 @@ class GuiProjectSettings(QDialog):
|
||||
|
||||
return
|
||||
|
||||
# END Class GuiProjectSettings
|
||||
|
||||
|
||||
class _SettingsPage(NScrollableForm):
|
||||
|
||||
@@ -296,17 +300,15 @@ class _SettingsPage(NScrollableForm):
|
||||
|
||||
return
|
||||
|
||||
# END Class _SettingsPage
|
||||
|
||||
|
||||
class _StatusPage(NFixedPage):
|
||||
|
||||
COL_LABEL = 0
|
||||
COL_USAGE = 1
|
||||
C_DATA = 0
|
||||
C_LABEL = 0
|
||||
C_USAGE = 1
|
||||
|
||||
KEY_ROLE = QtUserRole
|
||||
COL_ROLE = QtUserRole + 1
|
||||
NUM_ROLE = QtUserRole + 2
|
||||
D_KEY = QtUserRole
|
||||
D_ENTRY = QtUserRole + 1
|
||||
|
||||
def __init__(self, parent: QWidget, isStatus: bool) -> None:
|
||||
super().__init__(parent=parent)
|
||||
@@ -325,12 +327,21 @@ class _StatusPage(NFixedPage):
|
||||
)
|
||||
|
||||
self._changed = False
|
||||
self._colDeleted = []
|
||||
self._selColour = QColor(100, 100, 100)
|
||||
self._color = QColor(100, 100, 100)
|
||||
self._shape = nwStatusShape.SQUARE
|
||||
self._icons = {}
|
||||
|
||||
self.iPx = SHARED.theme.baseIconHeight
|
||||
self._iPx = SHARED.theme.baseIconHeight
|
||||
iSz = SHARED.theme.baseIconSize
|
||||
bSz = SHARED.theme.buttonIconSize
|
||||
bPd = CONFIG.pxInt(4)
|
||||
|
||||
iColor = self.palette().text().color()
|
||||
|
||||
# Labels
|
||||
self.trCountNone = self.tr("Not in use")
|
||||
self.trCountOne = self.tr("Used once")
|
||||
self.trCountMore = self.tr("Used by {0} items")
|
||||
self.trSelColor = self.tr("Select Colour")
|
||||
|
||||
# Title
|
||||
self.pageTitle = NColourLabel(
|
||||
@@ -341,12 +352,14 @@ class _StatusPage(NFixedPage):
|
||||
# List Box
|
||||
self.listBox = QTreeWidget(self)
|
||||
self.listBox.setHeaderLabels([self.tr("Label"), self.tr("Usage")])
|
||||
self.listBox.itemSelectionChanged.connect(self._selectedItem)
|
||||
self.listBox.setColumnWidth(self.COL_LABEL, wCol0)
|
||||
self.listBox.setColumnWidth(self.C_LABEL, wCol0)
|
||||
self.listBox.setIndentation(0)
|
||||
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self.listBox.itemSelectionChanged.connect(self._selectionChanged)
|
||||
|
||||
for key, entry in status.items():
|
||||
self._addItem(key, entry["name"], entry["cols"], entry["count"])
|
||||
for key, entry in status.iterItems():
|
||||
self._addItem(key, StatusEntry.duplicate(entry))
|
||||
|
||||
# List Controls
|
||||
self.addButton = NIconToolButton(self, iSz, "add")
|
||||
@@ -367,16 +380,43 @@ class _StatusPage(NFixedPage):
|
||||
self.editName.setPlaceholderText(self.tr("Select item to edit"))
|
||||
self.editName.setEnabled(False)
|
||||
|
||||
self.colPixmap = QPixmap(self.iPx, self.iPx)
|
||||
self.colPixmap.fill(QColor(100, 100, 100))
|
||||
self.colButton = QPushButton(QIcon(self.colPixmap), self.tr("Colour"), self)
|
||||
self.colButton.setIconSize(bSz)
|
||||
self.colButton.setEnabled(False)
|
||||
self.colButton.clicked.connect(self._selectColour)
|
||||
buttonStyle = (
|
||||
f"QToolButton {{padding: 0 {bPd}px;}} "
|
||||
"QToolButton::menu-indicator {image: none;}"
|
||||
)
|
||||
|
||||
self.saveButton = QPushButton(self.tr("Save"), self)
|
||||
self.saveButton.setEnabled(False)
|
||||
self.saveButton.clicked.connect(self._saveItem)
|
||||
self.colorButton = NIconToolButton(self, iSz)
|
||||
self.colorButton.setToolTip(self.tr("Colour"))
|
||||
self.colorButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
|
||||
self.colorButton.setStyleSheet(buttonStyle)
|
||||
self.colorButton.setEnabled(False)
|
||||
self.colorButton.clicked.connect(self._selectColour)
|
||||
|
||||
def buildMenu(menu: QMenu, items: dict[nwStatusShape, str]) -> None:
|
||||
for shape, label in items.items():
|
||||
icon = NWStatus.createIcon(self._iPx, iColor, shape)
|
||||
action = menu.addAction(icon, trConst(label))
|
||||
action.triggered.connect(lambda _, shape=shape: self._selectShape(shape))
|
||||
self._icons[shape] = icon
|
||||
|
||||
self.shapeMenu = QMenu(self)
|
||||
buildMenu(self.shapeMenu, nwLabels.SHAPES_PLAIN)
|
||||
buildMenu(self.shapeMenu.addMenu(self.tr("Circles ...")), nwLabels.SHAPES_CIRCLE)
|
||||
buildMenu(self.shapeMenu.addMenu(self.tr("Bars ...")), nwLabels.SHAPES_BARS)
|
||||
buildMenu(self.shapeMenu.addMenu(self.tr("Blocks ...")), nwLabels.SHAPES_BLOCKS)
|
||||
|
||||
self.shapeButton = NIconToolButton(self, iSz)
|
||||
self.shapeButton.setMenu(self.shapeMenu)
|
||||
self.shapeButton.setToolTip(self.tr("Shape"))
|
||||
self.shapeButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
|
||||
self.shapeButton.setStyleSheet(buttonStyle)
|
||||
self.shapeButton.setEnabled(False)
|
||||
|
||||
self.applyButton = QToolButton(self)
|
||||
self.applyButton.setText(self.tr("Apply"))
|
||||
self.applyButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
|
||||
self.applyButton.setEnabled(False)
|
||||
self.applyButton.clicked.connect(self._applyChanges)
|
||||
|
||||
# Assemble
|
||||
self.listControls = QVBoxLayout()
|
||||
@@ -387,28 +427,30 @@ class _StatusPage(NFixedPage):
|
||||
self.listControls.addStretch(1)
|
||||
|
||||
self.editBox = QHBoxLayout()
|
||||
self.editBox.addWidget(self.editName)
|
||||
self.editBox.addWidget(self.colButton)
|
||||
self.editBox.addWidget(self.saveButton)
|
||||
self.editBox.addWidget(self.editName, 1)
|
||||
self.editBox.addWidget(self.colorButton, 0)
|
||||
self.editBox.addWidget(self.shapeButton, 0)
|
||||
self.editBox.addWidget(self.applyButton, 0)
|
||||
|
||||
self.mainBox = QVBoxLayout()
|
||||
self.mainBox.addWidget(self.listBox)
|
||||
self.mainBox.addLayout(self.editBox)
|
||||
self.mainBox.addWidget(self.listBox, 1)
|
||||
self.mainBox.addLayout(self.editBox, 0)
|
||||
|
||||
self.innerBox = QHBoxLayout()
|
||||
self.innerBox.addLayout(self.mainBox)
|
||||
self.innerBox.addLayout(self.listControls)
|
||||
self.innerBox.addLayout(self.mainBox, 1)
|
||||
self.innerBox.addLayout(self.listControls, 0)
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.outerBox.addWidget(self.pageTitle)
|
||||
self.outerBox.addLayout(self.innerBox)
|
||||
self.outerBox.addWidget(self.pageTitle, 0)
|
||||
self.outerBox.addLayout(self.innerBox, 1)
|
||||
|
||||
self.setCentralLayout(self.outerBox)
|
||||
self._setButtonIcons()
|
||||
|
||||
return
|
||||
|
||||
@property
|
||||
def wasChanged(self) -> bool:
|
||||
def changed(self) -> bool:
|
||||
"""The user changed these settings."""
|
||||
return self._changed
|
||||
|
||||
@@ -416,20 +458,17 @@ class _StatusPage(NFixedPage):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def getNewList(self) -> tuple[list, list]:
|
||||
def getNewList(self) -> list[tuple[str | None, StatusEntry]]:
|
||||
"""Return list of entries."""
|
||||
if self._changed:
|
||||
newList = []
|
||||
update = []
|
||||
for n in range(self.listBox.topLevelItemCount()):
|
||||
item = self.listBox.topLevelItem(n)
|
||||
if item is not None:
|
||||
newList.append({
|
||||
"key": item.data(self.COL_LABEL, self.KEY_ROLE),
|
||||
"name": item.text(self.COL_LABEL),
|
||||
"cols": item.data(self.COL_LABEL, self.COL_ROLE),
|
||||
})
|
||||
return newList, self._colDeleted
|
||||
return [], []
|
||||
if item := self.listBox.topLevelItem(n):
|
||||
key = item.data(self.C_DATA, self.D_KEY)
|
||||
entry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
update.append((key, entry))
|
||||
return update
|
||||
return []
|
||||
|
||||
def columnWidth(self) -> int:
|
||||
"""Return the size of the header column."""
|
||||
@@ -442,124 +481,119 @@ class _StatusPage(NFixedPage):
|
||||
@pyqtSlot()
|
||||
def _selectColour(self) -> None:
|
||||
"""Open a dialog to select the status icon colour."""
|
||||
if self._selColour is not None:
|
||||
newCol = QColorDialog.getColor(
|
||||
self._selColour, self, self.tr("Select Colour")
|
||||
)
|
||||
if newCol.isValid():
|
||||
self._selColour = newCol
|
||||
pixmap = QPixmap(self.iPx, self.iPx)
|
||||
pixmap.fill(newCol)
|
||||
self.colButton.setIcon(QIcon(pixmap))
|
||||
self.colButton.setIconSize(pixmap.rect().size())
|
||||
if (color := QColorDialog.getColor(self._color, self, self.trSelColor)).isValid():
|
||||
self._color = color
|
||||
self._setButtonIcons()
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _newItem(self) -> None:
|
||||
"""Create a new status item."""
|
||||
self._addItem(None, self.tr("New Item"), (100, 100, 100), 0)
|
||||
color = QColor(100, 100, 100)
|
||||
shape = nwStatusShape.SQUARE
|
||||
icon = NWStatus.createIcon(self._iPx, color, shape)
|
||||
self._addItem(None, StatusEntry(self.tr("New Item"), color, shape, icon, 0))
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _delItem(self) -> None:
|
||||
"""Delete a status item."""
|
||||
selItem = self._getSelectedItem()
|
||||
if isinstance(selItem, QTreeWidgetItem):
|
||||
iRow = self.listBox.indexOfTopLevelItem(selItem)
|
||||
if selItem.data(self.COL_LABEL, self.NUM_ROLE) > 0:
|
||||
if item := self._getSelectedItem():
|
||||
iRow = self.listBox.indexOfTopLevelItem(item)
|
||||
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
if entry.count > 0:
|
||||
SHARED.error(self.tr("Cannot delete a status item that is in use."))
|
||||
else:
|
||||
self.listBox.takeTopLevelItem(iRow)
|
||||
self._colDeleted.append(selItem.data(self.COL_LABEL, self.KEY_ROLE))
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _saveItem(self) -> None:
|
||||
def _applyChanges(self) -> None:
|
||||
"""Save changes made to a status item."""
|
||||
selItem = self._getSelectedItem()
|
||||
if isinstance(selItem, QTreeWidgetItem):
|
||||
selItem.setText(self.COL_LABEL, simplified(self.editName.text()))
|
||||
selItem.setIcon(self.COL_LABEL, self.colButton.icon())
|
||||
selItem.setData(self.COL_LABEL, self.COL_ROLE, (
|
||||
self._selColour.red(), self._selColour.green(), self._selColour.blue()
|
||||
))
|
||||
if item := self._getSelectedItem():
|
||||
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
|
||||
name = simplified(self.editName.text())
|
||||
icon = NWStatus.createIcon(self._iPx, self._color, self._shape)
|
||||
|
||||
entry.name = name
|
||||
entry.color = self._color
|
||||
entry.shape = self._shape
|
||||
entry.icon = icon
|
||||
|
||||
item.setText(self.C_LABEL, name)
|
||||
item.setIcon(self.C_LABEL, icon)
|
||||
|
||||
self._changed = True
|
||||
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectedItem(self) -> None:
|
||||
def _selectionChanged(self) -> None:
|
||||
"""Extract the info of a selected item and populate the settings
|
||||
boxes and button. If no item is selected, clear the form.
|
||||
"""
|
||||
selItem = self._getSelectedItem()
|
||||
if isinstance(selItem, QTreeWidgetItem):
|
||||
cols = selItem.data(self.COL_LABEL, self.COL_ROLE)
|
||||
name = selItem.text(self.COL_LABEL)
|
||||
pixmap = QPixmap(self.iPx, self.iPx)
|
||||
pixmap.fill(QColor(*cols))
|
||||
self._selColour = QColor(*cols)
|
||||
self.editName.setText(name)
|
||||
self.colButton.setIcon(QIcon(pixmap))
|
||||
if item := self._getSelectedItem():
|
||||
entry: StatusEntry = item.data(self.C_DATA, self.D_ENTRY)
|
||||
self._color = entry.color
|
||||
self._shape = entry.shape
|
||||
self._setButtonIcons()
|
||||
|
||||
self.editName.setText(entry.name)
|
||||
self.editName.selectAll()
|
||||
self.editName.setFocus()
|
||||
|
||||
self.editName.setEnabled(True)
|
||||
self.colButton.setEnabled(True)
|
||||
self.saveButton.setEnabled(True)
|
||||
self.colorButton.setEnabled(True)
|
||||
self.shapeButton.setEnabled(True)
|
||||
self.applyButton.setEnabled(True)
|
||||
|
||||
else:
|
||||
pixmap = QPixmap(self.iPx, self.iPx)
|
||||
pixmap.fill(QColor(100, 100, 100))
|
||||
self._selColour = QColor(100, 100, 100)
|
||||
self._color = QColor(100, 100, 100)
|
||||
self._shape = nwStatusShape.SQUARE
|
||||
self._setButtonIcons()
|
||||
self.editName.setText("")
|
||||
self.colButton.setIcon(QIcon(pixmap))
|
||||
|
||||
self.editName.setEnabled(False)
|
||||
self.colButton.setEnabled(False)
|
||||
self.saveButton.setEnabled(False)
|
||||
self.colorButton.setEnabled(False)
|
||||
self.shapeButton.setEnabled(False)
|
||||
self.applyButton.setEnabled(False)
|
||||
return
|
||||
|
||||
##
|
||||
# Internal Functions
|
||||
##
|
||||
|
||||
def _addItem(self, key: str | None, name: str,
|
||||
colour: tuple[int, int, int], count: int) -> None:
|
||||
def _selectShape(self, shape: nwStatusShape) -> None:
|
||||
"""Set the current shape."""
|
||||
self._shape = shape
|
||||
self._setButtonIcons()
|
||||
return
|
||||
|
||||
def _addItem(self, key: str | None, entry: StatusEntry) -> None:
|
||||
"""Add a status item to the list."""
|
||||
pixmap = QPixmap(self.iPx, self.iPx)
|
||||
pixmap.fill(QColor(*colour))
|
||||
|
||||
item = QTreeWidgetItem()
|
||||
item.setText(self.COL_LABEL, name)
|
||||
item.setIcon(self.COL_LABEL, QIcon(pixmap))
|
||||
item.setData(self.COL_LABEL, self.KEY_ROLE, key)
|
||||
item.setData(self.COL_LABEL, self.COL_ROLE, colour)
|
||||
item.setData(self.COL_LABEL, self.NUM_ROLE, count)
|
||||
item.setText(self.COL_USAGE, self._usageString(count))
|
||||
|
||||
item.setText(self.C_LABEL, entry.name)
|
||||
item.setIcon(self.C_LABEL, entry.icon)
|
||||
item.setText(self.C_USAGE, self._usageString(entry.count))
|
||||
item.setData(self.C_DATA, self.D_KEY, key)
|
||||
item.setData(self.C_DATA, self.D_ENTRY, entry)
|
||||
self.listBox.addTopLevelItem(item)
|
||||
|
||||
return
|
||||
|
||||
def _moveItem(self, step: int) -> None:
|
||||
"""Move and item up or down step."""
|
||||
selItem = self._getSelectedItem()
|
||||
if selItem is None:
|
||||
return
|
||||
|
||||
tIndex = self.listBox.indexOfTopLevelItem(selItem)
|
||||
nChild = self.listBox.topLevelItemCount()
|
||||
nIndex = tIndex + step
|
||||
if nIndex < 0 or nIndex >= nChild:
|
||||
return
|
||||
|
||||
cItem = self.listBox.takeTopLevelItem(tIndex)
|
||||
self.listBox.insertTopLevelItem(nIndex, cItem)
|
||||
self.listBox.clearSelection()
|
||||
|
||||
if cItem is not None:
|
||||
cItem.setSelected(True)
|
||||
self._changed = True
|
||||
|
||||
if item := self._getSelectedItem():
|
||||
tIdx = self.listBox.indexOfTopLevelItem(item)
|
||||
nItm = self.listBox.topLevelItemCount()
|
||||
nIdx = tIdx + step
|
||||
if (0 <= nIdx < nItm) and (cItem := self.listBox.takeTopLevelItem(tIdx)):
|
||||
self.listBox.insertTopLevelItem(nIdx, cItem)
|
||||
self.listBox.clearSelection()
|
||||
cItem.setSelected(True)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
def _getSelectedItem(self) -> QTreeWidgetItem | None:
|
||||
@@ -571,19 +605,24 @@ class _StatusPage(NFixedPage):
|
||||
def _usageString(self, count: int) -> str:
|
||||
"""Generate usage string."""
|
||||
if count == 0:
|
||||
return self.tr("Not in use")
|
||||
return self.trCountNone
|
||||
elif count == 1:
|
||||
return self.tr("Used once")
|
||||
return self.trCountOne
|
||||
else:
|
||||
return self.tr("Used by {0} items").format(count)
|
||||
return self.trCountMore.format(count)
|
||||
|
||||
# END Class _StatusPage
|
||||
def _setButtonIcons(self) -> None:
|
||||
"""Set the colour of the colour button."""
|
||||
icon = NWStatus.createIcon(self._iPx, self._color, nwStatusShape.SQUARE)
|
||||
self.colorButton.setIcon(icon)
|
||||
self.shapeButton.setIcon(self._icons[self._shape])
|
||||
return
|
||||
|
||||
|
||||
class _ReplacePage(NFixedPage):
|
||||
|
||||
COL_KEY = 0
|
||||
COL_REPL = 1
|
||||
C_KEY = 0
|
||||
C_REPL = 1
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
@@ -605,15 +644,17 @@ class _ReplacePage(NFixedPage):
|
||||
# List Box
|
||||
self.listBox = QTreeWidget(self)
|
||||
self.listBox.setHeaderLabels([self.tr("Keyword"), self.tr("Replace With")])
|
||||
self.listBox.setColumnWidth(self.COL_KEY, wCol0)
|
||||
self.listBox.setColumnWidth(self.C_KEY, wCol0)
|
||||
self.listBox.setIndentation(0)
|
||||
self.listBox.itemSelectionChanged.connect(self._selectedItem)
|
||||
self.listBox.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectRows)
|
||||
self.listBox.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self.listBox.itemSelectionChanged.connect(self._selectionChanged)
|
||||
|
||||
for aKey, aVal in SHARED.project.data.autoReplace.items():
|
||||
newItem = QTreeWidgetItem(["<%s>" % aKey, aVal])
|
||||
self.listBox.addTopLevelItem(newItem)
|
||||
|
||||
self.listBox.sortByColumn(self.COL_KEY, Qt.SortOrder.AscendingOrder)
|
||||
self.listBox.sortByColumn(self.C_KEY, Qt.SortOrder.AscendingOrder)
|
||||
self.listBox.setSortingEnabled(True)
|
||||
|
||||
# List Controls
|
||||
@@ -633,8 +674,10 @@ class _ReplacePage(NFixedPage):
|
||||
self.editValue.setEnabled(False)
|
||||
self.editValue.setMaxLength(80)
|
||||
|
||||
self.saveButton = QPushButton(self.tr("Save"), self)
|
||||
self.saveButton.clicked.connect(self._saveEntry)
|
||||
self.applyButton = QToolButton(self)
|
||||
self.applyButton.setText(self.tr("Apply"))
|
||||
self.applyButton.setSizePolicy(QtSizeMinimum, QtSizeMinimumExpanding)
|
||||
self.applyButton.clicked.connect(self._applyChanges)
|
||||
|
||||
# Assemble
|
||||
self.listControls = QVBoxLayout()
|
||||
@@ -645,11 +688,11 @@ class _ReplacePage(NFixedPage):
|
||||
self.editBox = QHBoxLayout()
|
||||
self.editBox.addWidget(self.editKey, 4)
|
||||
self.editBox.addWidget(self.editValue, 5)
|
||||
self.editBox.addWidget(self.saveButton, 0)
|
||||
self.editBox.addWidget(self.applyButton, 0)
|
||||
|
||||
self.mainBox = QVBoxLayout()
|
||||
self.mainBox.addWidget(self.listBox)
|
||||
self.mainBox.addLayout(self.editBox)
|
||||
self.mainBox.addWidget(self.listBox, 1)
|
||||
self.mainBox.addLayout(self.editBox, 0)
|
||||
|
||||
self.innerBox = QHBoxLayout()
|
||||
self.innerBox.addLayout(self.mainBox)
|
||||
@@ -664,7 +707,7 @@ class _ReplacePage(NFixedPage):
|
||||
return
|
||||
|
||||
@property
|
||||
def wasChanged(self) -> bool:
|
||||
def changed(self) -> bool:
|
||||
"""The user changed these settings."""
|
||||
return self._changed
|
||||
|
||||
@@ -672,15 +715,13 @@ class _ReplacePage(NFixedPage):
|
||||
# Methods
|
||||
##
|
||||
|
||||
def getNewList(self) -> dict:
|
||||
def getNewList(self) -> dict[str, str]:
|
||||
"""Extract the list from the widget."""
|
||||
new = {}
|
||||
for n in range(self.listBox.topLevelItemCount()):
|
||||
if tItem := self.listBox.topLevelItem(n):
|
||||
aKey = self._stripNotAllowed(tItem.text(0))
|
||||
aVal = tItem.text(1)
|
||||
if len(aKey) > 0:
|
||||
new[aKey] = aVal
|
||||
if item := self.listBox.topLevelItem(n):
|
||||
if key := self._stripNotAllowed(item.text(self.C_KEY)):
|
||||
new[key] = item.text(self.C_REPL)
|
||||
return new
|
||||
|
||||
def columnWidth(self) -> int:
|
||||
@@ -692,51 +733,48 @@ class _ReplacePage(NFixedPage):
|
||||
##
|
||||
|
||||
@pyqtSlot()
|
||||
def _selectedItem(self) -> None:
|
||||
def _selectionChanged(self) -> None:
|
||||
"""Extract the details from the selected item and populate the
|
||||
edit form.
|
||||
"""
|
||||
if selItem := self._getSelectedItem():
|
||||
editKey = self._stripNotAllowed(selItem.text(0))
|
||||
editVal = selItem.text(1)
|
||||
self.editKey.setText(editKey)
|
||||
self.editValue.setText(editVal)
|
||||
if item := self._getSelectedItem():
|
||||
self.editKey.setText(self._stripNotAllowed(item.text(self.C_KEY)))
|
||||
self.editValue.setText(item.text(self.C_REPL))
|
||||
self.editKey.setEnabled(True)
|
||||
self.editValue.setEnabled(True)
|
||||
self.editKey.selectAll()
|
||||
self.editKey.setFocus()
|
||||
else:
|
||||
self.editKey.setText("")
|
||||
self.editValue.setText("")
|
||||
self.editKey.setEnabled(False)
|
||||
self.editValue.setEnabled(False)
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _saveEntry(self) -> None:
|
||||
def _applyChanges(self) -> None:
|
||||
"""Save the form data into the list widget."""
|
||||
if selItem := self._getSelectedItem():
|
||||
newKey = self.editKey.text()
|
||||
newVal = self.editValue.text()
|
||||
saveKey = self._stripNotAllowed(newKey)
|
||||
if len(saveKey) > 0 and len(newVal) > 0:
|
||||
selItem.setText(self.COL_KEY, "<%s>" % saveKey)
|
||||
selItem.setText(self.COL_REPL, newVal)
|
||||
self.editKey.clear()
|
||||
self.editValue.clear()
|
||||
self.editKey.setEnabled(False)
|
||||
self.editValue.setEnabled(False)
|
||||
self.listBox.clearSelection()
|
||||
if item := self._getSelectedItem():
|
||||
key = self._stripNotAllowed(self.editKey.text())
|
||||
value = self.editValue.text()
|
||||
if key and value:
|
||||
item.setText(self.C_KEY, f"<{key}>")
|
||||
item.setText(self.C_REPL, value)
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _addEntry(self) -> None:
|
||||
"""Add a new list entry."""
|
||||
saveKey = "<keyword%d>" % (self.listBox.topLevelItemCount() + 1)
|
||||
self.listBox.addTopLevelItem(QTreeWidgetItem([saveKey, ""]))
|
||||
key = f"<keyword{self.listBox.topLevelItemCount() + 1:d}>"
|
||||
self.listBox.addTopLevelItem(QTreeWidgetItem([key, ""]))
|
||||
return
|
||||
|
||||
@pyqtSlot()
|
||||
def _delEntry(self) -> None:
|
||||
"""Delete the selected entry."""
|
||||
if selItem := self._getSelectedItem():
|
||||
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(selItem))
|
||||
if item := self._getSelectedItem():
|
||||
self.listBox.takeTopLevelItem(self.listBox.indexOfTopLevelItem(item))
|
||||
self._changed = True
|
||||
return
|
||||
|
||||
@@ -753,5 +791,3 @@ class _ReplacePage(NFixedPage):
|
||||
def _stripNotAllowed(self, key: str) -> str:
|
||||
"""Clean up the replace key string."""
|
||||
return "".join(c for c in key if c.isalnum())
|
||||
|
||||
# END Class _ReplacePage
|
||||
|
||||
@@ -25,15 +25,15 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt5.QtGui import QFontMetrics
|
||||
from PyQt5.QtCore import QSize, pyqtSlot
|
||||
from PyQt5.QtGui import QFontMetrics
|
||||
from PyQt5.QtWidgets import (
|
||||
QDialog, QDialogButtonBox, QFrame, QHBoxLayout, QLabel, QListWidget,
|
||||
QListWidgetItem, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG
|
||||
from novelwriter.constants import trConst, nwQuotes
|
||||
from novelwriter.constants import nwQuotes, trConst
|
||||
from novelwriter.types import QtAlignCenter, QtAlignTop, QtDialogCancel, QtDialogOk, QtUserRole
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
@@ -50,6 +50,7 @@ class GuiQuoteSelect(QDialog):
|
||||
|
||||
logger.debug("Create: GuiQuoteSelect")
|
||||
self.setObjectName("GuiQuoteSelect")
|
||||
self.setWindowTitle(self.tr("Select Quote Style"))
|
||||
|
||||
self.outerBox = QVBoxLayout()
|
||||
self.innerBox = QHBoxLayout()
|
||||
@@ -141,5 +142,3 @@ class GuiQuoteSelect(QDialog):
|
||||
self.previewLabel.setText(quote)
|
||||
self._selected = quote
|
||||
return
|
||||
|
||||
# END Class GuiQuoteSelect
|
||||
|
||||
@@ -25,14 +25,13 @@ from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from pathlib import Path
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QCloseEvent
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractItemView, QApplication, QDialog, QDialogButtonBox, QFileDialog,
|
||||
QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout
|
||||
QHBoxLayout, QLineEdit, QListWidget, QVBoxLayout, QWidget
|
||||
)
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
@@ -42,9 +41,6 @@ from novelwriter.extensions.configlayout import NColourLabel
|
||||
from novelwriter.extensions.modified import NIconToolButton
|
||||
from novelwriter.types import QtDialogClose, QtDialogSave
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -52,8 +48,8 @@ class GuiWordList(QDialog):
|
||||
|
||||
newWordListReady = pyqtSignal()
|
||||
|
||||
def __init__(self, mainGui: GuiMain) -> None:
|
||||
super().__init__(parent=mainGui)
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
logger.debug("Create: GuiWordList")
|
||||
self.setObjectName("GuiWordList")
|
||||
@@ -257,5 +253,3 @@ class GuiWordList(QDialog):
|
||||
if (item := self.listBox.item(i)) and (word := item.text().strip()):
|
||||
result.append(word)
|
||||
return result
|
||||
|
||||
# END Class GuiWordList
|
||||
|
||||
@@ -32,8 +32,6 @@ class nwItemType(Enum):
|
||||
FOLDER = 2
|
||||
FILE = 3
|
||||
|
||||
# END Enum nwItemType
|
||||
|
||||
|
||||
class nwItemClass(Enum):
|
||||
|
||||
@@ -50,8 +48,6 @@ class nwItemClass(Enum):
|
||||
TEMPLATE = 10
|
||||
TRASH = 11
|
||||
|
||||
# END Enum nwItemClass
|
||||
|
||||
|
||||
class nwItemLayout(Enum):
|
||||
|
||||
@@ -59,16 +55,17 @@ class nwItemLayout(Enum):
|
||||
DOCUMENT = 1
|
||||
NOTE = 2
|
||||
|
||||
# END Enum nwItemLayout
|
||||
|
||||
|
||||
class nwComment(Enum):
|
||||
|
||||
PLAIN = 0
|
||||
SYNOPSIS = 1
|
||||
SHORT = 2
|
||||
|
||||
# END Enum nwComment
|
||||
IGNORE = 1
|
||||
SYNOPSIS = 2
|
||||
SHORT = 3
|
||||
NOTE = 4
|
||||
FOOTNOTE = 5
|
||||
COMMENT = 6
|
||||
STORY = 7
|
||||
|
||||
|
||||
class nwTrinary(Enum):
|
||||
@@ -77,16 +74,12 @@ class nwTrinary(Enum):
|
||||
NEUTRAL = 0
|
||||
POSITIVE = 1
|
||||
|
||||
# END Enum nwTrinary
|
||||
|
||||
|
||||
class nwDocMode(Enum):
|
||||
|
||||
VIEW = 0
|
||||
EDIT = 1
|
||||
|
||||
# END Enum nwDocMode
|
||||
|
||||
|
||||
class nwDocAction(Enum):
|
||||
|
||||
@@ -129,8 +122,6 @@ class nwDocAction(Enum):
|
||||
SC_SUP = 36
|
||||
SC_SUB = 37
|
||||
|
||||
# END Enum nwDocAction
|
||||
|
||||
|
||||
class nwDocInsert(Enum):
|
||||
|
||||
@@ -145,8 +136,7 @@ class nwDocInsert(Enum):
|
||||
VSPACE_S = 8
|
||||
VSPACE_M = 9
|
||||
LIPSUM = 10
|
||||
|
||||
# END Enum nwDocInsert
|
||||
FOOTNOTE = 11
|
||||
|
||||
|
||||
class nwView(Enum):
|
||||
@@ -157,8 +147,6 @@ class nwView(Enum):
|
||||
OUTLINE = 3
|
||||
SEARCH = 4
|
||||
|
||||
# END Enum nwView
|
||||
|
||||
|
||||
class nwWidget(Enum):
|
||||
|
||||
@@ -167,8 +155,6 @@ class nwWidget(Enum):
|
||||
VIEWER = 3
|
||||
OUTLINE = 4
|
||||
|
||||
# END Enum nwWidget
|
||||
|
||||
|
||||
class nwOutline(Enum):
|
||||
|
||||
@@ -190,8 +176,6 @@ class nwOutline(Enum):
|
||||
CUSTOM = 15
|
||||
SYNOP = 16
|
||||
|
||||
# END Enum nwOutline
|
||||
|
||||
|
||||
class nwBuildFmt(Enum):
|
||||
|
||||
@@ -204,4 +188,26 @@ class nwBuildFmt(Enum):
|
||||
J_HTML = 6
|
||||
J_NWD = 7
|
||||
|
||||
# END Enum nwBuildFormat
|
||||
|
||||
class nwStatusShape(Enum):
|
||||
|
||||
SQUARE = 0
|
||||
TRIANGLE = 1
|
||||
NABLA = 2
|
||||
DIAMOND = 3
|
||||
PENTAGON = 4
|
||||
HEXAGON = 5
|
||||
STAR = 6
|
||||
PACMAN = 7
|
||||
CIRCLE_Q = 8
|
||||
CIRCLE_H = 9
|
||||
CIRCLE_T = 10
|
||||
CIRCLE = 11
|
||||
BARS_1 = 12
|
||||
BARS_2 = 13
|
||||
BARS_3 = 14
|
||||
BARS_4 = 15
|
||||
BLOCK_1 = 16
|
||||
BLOCK_2 = 17
|
||||
BLOCK_3 = 18
|
||||
BLOCK_4 = 19
|
||||
|
||||
@@ -23,17 +23,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
import random
|
||||
import logging
|
||||
import random
|
||||
import sys
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSlot
|
||||
from PyQt5.QtGui import QFont, QFontDatabase
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QWidget, QDialog, QGridLayout, QStyle, QPlainTextEdit,
|
||||
QLabel, QDialogButtonBox
|
||||
QApplication, QDialog, QDialogButtonBox, QGridLayout, QLabel,
|
||||
QPlainTextEdit, QStyle, QWidget
|
||||
)
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
@@ -42,10 +42,6 @@ if TYPE_CHECKING: # pragma: no cover
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# Utility Functions
|
||||
# =============================================================================================== #
|
||||
|
||||
def logException() -> None:
|
||||
"""Log the content of an exception message."""
|
||||
exType, exValue, _ = sys.exc_info()
|
||||
@@ -61,10 +57,6 @@ def formatException(exc: BaseException) -> str:
|
||||
return f"{type(exc).__name__}: {str(exc)}"
|
||||
|
||||
|
||||
# =============================================================================================== #
|
||||
# Error Handler
|
||||
# =============================================================================================== #
|
||||
|
||||
class NWErrorMessage(QDialog):
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
@@ -125,9 +117,11 @@ class NWErrorMessage(QDialog):
|
||||
error traceback.
|
||||
"""
|
||||
from traceback import format_tb
|
||||
|
||||
from PyQt5.QtCore import PYQT_VERSION_STR, QT_VERSION_STR, QSysInfo
|
||||
|
||||
from novelwriter import __version__
|
||||
from novelwriter.constants import nwConst
|
||||
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR, QSysInfo
|
||||
|
||||
self.msgHead.setText(
|
||||
"<p>An unhandled error has been encountered.</p>"
|
||||
@@ -175,12 +169,11 @@ class NWErrorMessage(QDialog):
|
||||
self.close()
|
||||
return
|
||||
|
||||
# END Class NWErrorMessage
|
||||
|
||||
|
||||
def exceptionHandler(exType: type, exValue: BaseException, exTrace: TracebackType) -> None:
|
||||
"""Function to catch unhandled global exceptions."""
|
||||
from traceback import print_tb
|
||||
|
||||
from PyQt5.QtWidgets import QApplication
|
||||
|
||||
logger.critical("%s: %s", exType.__name__, str(exValue))
|
||||
|
||||
@@ -26,11 +26,12 @@ from __future__ import annotations
|
||||
from math import ceil
|
||||
|
||||
from PyQt5.QtCore import QRect
|
||||
from PyQt5.QtGui import QBrush, QColor, QPaintEvent, QPainter, QPen
|
||||
from PyQt5.QtWidgets import QProgressBar, QSizePolicy, QWidget
|
||||
from PyQt5.QtGui import QBrush, QColor, QPainter, QPaintEvent, QPen
|
||||
from PyQt5.QtWidgets import QProgressBar, QWidget
|
||||
|
||||
from novelwriter.types import (
|
||||
QtPaintAnitAlias, QtAlignCenter, QtRoundCap, QtSolidLine, QtTransparent
|
||||
QtAlignCenter, QtPaintAnitAlias, QtRoundCap, QtSizeFixed, QtSolidLine,
|
||||
QtTransparent
|
||||
)
|
||||
|
||||
|
||||
@@ -59,7 +60,7 @@ class NProgressCircle(QProgressBar):
|
||||
bar=self.palette().highlight().color(),
|
||||
text=self.palette().text().color()
|
||||
)
|
||||
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||
self.setSizePolicy(QtSizeFixed, QtSizeFixed)
|
||||
self.setFixedWidth(size)
|
||||
self.setFixedHeight(size)
|
||||
return
|
||||
@@ -100,5 +101,3 @@ class NProgressCircle(QProgressBar):
|
||||
painter.setPen(self._tColor)
|
||||
painter.drawText(self._cRect, QtAlignCenter, self._text or f"{progress:.1f} %")
|
||||
return
|
||||
|
||||
# END Class NProgressCircle
|
||||
|
||||
@@ -27,8 +27,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QColor, QFont, QPalette
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtGui import QColor, QFont, QPalette
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractButton, QFrame, QHBoxLayout, QLabel, QLayout, QScrollArea,
|
||||
QVBoxLayout, QWidget
|
||||
@@ -64,8 +64,6 @@ class NFixedPage(QFrame):
|
||||
self.setLayout(layout)
|
||||
return
|
||||
|
||||
# END Class NFixedPage
|
||||
|
||||
|
||||
class NScrollablePage(QScrollArea):
|
||||
"""Extension: Scrollable Page Widget
|
||||
@@ -89,8 +87,6 @@ class NScrollablePage(QScrollArea):
|
||||
self._widget.setLayout(layout)
|
||||
return
|
||||
|
||||
# END Class NScrollablePage
|
||||
|
||||
|
||||
class NScrollableForm(QScrollArea):
|
||||
"""Extension: Scrollable Form Widget
|
||||
@@ -184,16 +180,26 @@ class NScrollableForm(QScrollArea):
|
||||
self._sections[identifier] = qLabel
|
||||
return
|
||||
|
||||
def addRow(self, label: str, widget: QWidget, helpText: str = "", unit: str | None = None,
|
||||
button: QWidget | None = None, editable: str | None = None,
|
||||
def addRow(self, label: str, widget: QWidget | list[QWidget], helpText: str = "",
|
||||
unit: str | None = None, button: QWidget | None = None, editable: str | None = None,
|
||||
stretch: tuple[int, int] = (1, 0)) -> None:
|
||||
"""Add a label and a widget as a new row of the form."""
|
||||
row = QHBoxLayout()
|
||||
row.setSpacing(CONFIG.pxInt(12))
|
||||
|
||||
if isinstance(widget, list):
|
||||
wBox = QHBoxLayout()
|
||||
wBox.setContentsMargins(0, 0, 0, 0)
|
||||
for item in widget:
|
||||
wBox.addWidget(item)
|
||||
qWidget = QWidget(self)
|
||||
qWidget.setLayout(wBox)
|
||||
else:
|
||||
qWidget = widget
|
||||
|
||||
qLabel = QLabel(label, self)
|
||||
qLabel.setIndent(self._indent)
|
||||
qLabel.setBuddy(widget)
|
||||
qLabel.setBuddy(qWidget)
|
||||
|
||||
if helpText:
|
||||
qHelp = NColourLabel(
|
||||
@@ -212,19 +218,19 @@ class NScrollableForm(QScrollArea):
|
||||
|
||||
if isinstance(unit, str):
|
||||
box = QHBoxLayout()
|
||||
box.addWidget(widget, 1)
|
||||
box.addWidget(qWidget, 1)
|
||||
box.addWidget(QLabel(unit, self), 0)
|
||||
row.addLayout(box, stretch[1])
|
||||
elif isinstance(button, QAbstractButton):
|
||||
box = QHBoxLayout()
|
||||
box.addWidget(widget, 1)
|
||||
box.addWidget(qWidget, 1)
|
||||
box.addWidget(button, 0)
|
||||
row.addLayout(box, stretch[1])
|
||||
else:
|
||||
row.addWidget(widget, stretch[1])
|
||||
row.addWidget(qWidget, stretch[1])
|
||||
|
||||
self._layout.addLayout(row)
|
||||
self._index[label.strip()] = widget
|
||||
self._index[label.strip()] = qWidget
|
||||
self._first = False
|
||||
|
||||
return
|
||||
@@ -235,8 +241,6 @@ class NScrollableForm(QScrollArea):
|
||||
self._layout.addStretch(1)
|
||||
return
|
||||
|
||||
# END Class NScrollableForm
|
||||
|
||||
|
||||
class NColourLabel(QLabel):
|
||||
"""Extension: A Coloured Label
|
||||
@@ -267,8 +271,6 @@ class NColourLabel(QLabel):
|
||||
|
||||
return
|
||||
|
||||
# END Class NColourLabel
|
||||
|
||||
|
||||
class NWrappedWidgetBox(QHBoxLayout):
|
||||
"""Extension: A Text-Wrapped Widget Box
|
||||
@@ -287,5 +289,3 @@ class NWrappedWidgetBox(QHBoxLayout):
|
||||
if after:
|
||||
self.addWidget(QLabel(after.lstrip()))
|
||||
return
|
||||
|
||||
# END Class NWrappedWidgetBox
|
||||
|
||||
@@ -24,8 +24,8 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QStatusTipEvent, QWheelEvent
|
||||
from PyQt5.QtCore import QEvent, QObject
|
||||
from PyQt5.QtGui import QStatusTipEvent, QWheelEvent
|
||||
from PyQt5.QtWidgets import QWidget
|
||||
|
||||
|
||||
@@ -63,13 +63,9 @@ class WheelEventFilter(QObject):
|
||||
self._locked = False
|
||||
return False
|
||||
|
||||
# END Class WheelEventFilter
|
||||
|
||||
|
||||
class StatusTipFilter(QObject):
|
||||
|
||||
def eventFilter(self, obj: QObject, event: QEvent) -> bool:
|
||||
"""Filter out status tip events on menus."""
|
||||
return True if isinstance(event, QStatusTipEvent) else super().eventFilter(obj, event)
|
||||
|
||||
# END Class StatusTipFilter
|
||||
|
||||
@@ -6,6 +6,8 @@ File History:
|
||||
Created: 2024-02-01 [2.3b1] NComboBox
|
||||
Created: 2024-02-01 [2.3b1] NSpinBox
|
||||
Created: 2024-02-01 [2.3b1] NDoubleSpinBox
|
||||
Created: 2024-05-01 [2.5b1] NToolDialog
|
||||
Created: 2024-05-01 [2.5b1] NNonBlockingDialog
|
||||
|
||||
This file is a part of novelWriter
|
||||
Copyright 2018–2024, Veronica Berglyd Olsen
|
||||
@@ -25,11 +27,56 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from PyQt5.QtCore import QSize, Qt
|
||||
from PyQt5.QtGui import QWheelEvent
|
||||
from PyQt5.QtWidgets import QComboBox, QDoubleSpinBox, QSpinBox, QToolButton, QWidget
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QComboBox, QDialog, QDoubleSpinBox, QSpinBox, QToolButton,
|
||||
QWidget
|
||||
)
|
||||
|
||||
from novelwriter import SHARED
|
||||
from novelwriter import CONFIG, SHARED
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from novelwriter.guimain import GuiMain
|
||||
|
||||
|
||||
class NToolDialog(QDialog):
|
||||
|
||||
def __init__(self, parent: GuiMain) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self.setModal(False)
|
||||
if CONFIG.osDarwin:
|
||||
self.setWindowFlag(Qt.WindowType.Tool)
|
||||
return
|
||||
|
||||
def activateDialog(self) -> None:
|
||||
"""Helper function to activate dialog on various systems."""
|
||||
self.show()
|
||||
if CONFIG.osWindows:
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
QApplication.processEvents()
|
||||
return
|
||||
|
||||
|
||||
class NNonBlockingDialog(QDialog):
|
||||
|
||||
def __init__(self, parent: QWidget | None = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self.setModal(True)
|
||||
return
|
||||
|
||||
def activateDialog(self) -> None:
|
||||
"""Helper function to activate dialog on various systems."""
|
||||
self.show()
|
||||
if CONFIG.osWindows:
|
||||
self.activateWindow()
|
||||
self.raise_()
|
||||
QApplication.processEvents()
|
||||
return
|
||||
|
||||
|
||||
class NComboBox(QComboBox):
|
||||
@@ -46,14 +93,12 @@ class NComboBox(QComboBox):
|
||||
event.ignore()
|
||||
return
|
||||
|
||||
def setCurrentData(self, data: str, default: str) -> None:
|
||||
def setCurrentData(self, data: str | int | Enum, default: str | int | Enum) -> None:
|
||||
"""Set the current index from data, with a fallback."""
|
||||
idx = self.findData(data)
|
||||
self.setCurrentIndex(self.findData(default) if idx < 0 else idx)
|
||||
return
|
||||
|
||||
# END Class NComboBox
|
||||
|
||||
|
||||
class NSpinBox(QSpinBox):
|
||||
|
||||
@@ -69,8 +114,6 @@ class NSpinBox(QSpinBox):
|
||||
event.ignore()
|
||||
return
|
||||
|
||||
# END Class NSpinBox
|
||||
|
||||
|
||||
class NDoubleSpinBox(QDoubleSpinBox):
|
||||
|
||||
@@ -86,8 +129,6 @@ class NDoubleSpinBox(QDoubleSpinBox):
|
||||
event.ignore()
|
||||
return
|
||||
|
||||
# END Class NDoubleSpinBox
|
||||
|
||||
|
||||
class NIconToolButton(QToolButton):
|
||||
|
||||
@@ -105,8 +146,6 @@ class NIconToolButton(QToolButton):
|
||||
self.setIcon(SHARED.theme.getIcon(iconKey))
|
||||
return
|
||||
|
||||
# END Class NIconToolButton
|
||||
|
||||
|
||||
class NIconToggleButton(QToolButton):
|
||||
|
||||
@@ -126,5 +165,3 @@ class NIconToggleButton(QToolButton):
|
||||
iconSize = self.iconSize()
|
||||
self.setIcon(SHARED.theme.getToggleIcon(iconKey, (iconSize.width(), iconSize.height())))
|
||||
return
|
||||
|
||||
# END Class NUnfoldButton
|
||||
|
||||
@@ -29,8 +29,8 @@ from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtWidgets import QComboBox, QWidget
|
||||
|
||||
from novelwriter import SHARED
|
||||
from novelwriter.enum import nwItemClass
|
||||
from novelwriter.constants import nwLabels
|
||||
from novelwriter.enum import nwItemClass
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -126,5 +126,3 @@ class NovelSelector(QComboBox):
|
||||
if not self._blockSignal:
|
||||
self.novelSelectionChanged.emit(self.currentData())
|
||||
return
|
||||
|
||||
# END Class NovelSelector
|
||||
|
||||
@@ -25,14 +25,17 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QColor, QPaintEvent, QPainter, QPolygon
|
||||
from PyQt5.QtCore import QPoint, QRectF, QSize, Qt, pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QColor, QPainter, QPaintEvent, QPolygon
|
||||
from PyQt5.QtWidgets import (
|
||||
QAbstractButton, QAction, QButtonGroup, QLabel, QSizePolicy, QStyle,
|
||||
QAbstractButton, QAction, QButtonGroup, QLabel, QStyle,
|
||||
QStyleOptionToolButton, QToolBar, QToolButton, QWidget
|
||||
)
|
||||
|
||||
from novelwriter.types import QtPaintAnitAlias, QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen
|
||||
from novelwriter.types import (
|
||||
QtAlignLeft, QtMouseOver, QtNoBrush, QtNoPen, QtPaintAnitAlias,
|
||||
QtSizeExpanding, QtSizeFixed
|
||||
)
|
||||
|
||||
|
||||
class NPagedSideBar(QToolBar):
|
||||
@@ -59,7 +62,7 @@ class NPagedSideBar(QToolBar):
|
||||
self.setOrientation(Qt.Orientation.Vertical)
|
||||
|
||||
stretch = QWidget(self)
|
||||
stretch.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||
stretch.setSizePolicy(QtSizeExpanding, QtSizeExpanding)
|
||||
self._stretchAction = self.addWidget(stretch)
|
||||
|
||||
return
|
||||
@@ -109,8 +112,6 @@ class NPagedSideBar(QToolBar):
|
||||
self.buttonClicked.emit(buttonId)
|
||||
return
|
||||
|
||||
# END Class NPagedSideBar
|
||||
|
||||
|
||||
class _NPagedToolButton(QToolButton):
|
||||
|
||||
@@ -119,7 +120,7 @@ class _NPagedToolButton(QToolButton):
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
self.setSizePolicy(QtSizeExpanding, QtSizeFixed)
|
||||
self.setCheckable(True)
|
||||
|
||||
fH = self.fontMetrics().height()
|
||||
@@ -187,8 +188,6 @@ class _NPagedToolButton(QToolButton):
|
||||
|
||||
return
|
||||
|
||||
# END Class _NPagedToolButton
|
||||
|
||||
|
||||
class _NPagedToolLabel(QLabel):
|
||||
|
||||
@@ -197,7 +196,7 @@ class _NPagedToolLabel(QLabel):
|
||||
def __init__(self, parent: QWidget, textColor: QColor | None = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
self.setSizePolicy(QtSizeExpanding, QtSizeFixed)
|
||||
|
||||
fH = self.fontMetrics().height()
|
||||
self._bH = round(fH * 1.7)
|
||||
@@ -228,5 +227,3 @@ class _NPagedToolLabel(QLabel):
|
||||
paint.drawText(QRectF(self._lM, self._tM, tW, tH), QtAlignLeft, self.text())
|
||||
|
||||
return
|
||||
|
||||
# END Class _NPagedToolLabel
|
||||
|
||||
@@ -25,7 +25,7 @@ from __future__ import annotations
|
||||
|
||||
from math import ceil
|
||||
|
||||
from PyQt5.QtGui import QPaintEvent, QPainter
|
||||
from PyQt5.QtGui import QPainter, QPaintEvent
|
||||
from PyQt5.QtWidgets import QProgressBar, QWidget
|
||||
|
||||
from novelwriter.types import QtPaintAnitAlias
|
||||
@@ -51,5 +51,3 @@ class NProgressSimple(QProgressBar):
|
||||
painter.setBrush(self.palette().highlight())
|
||||
painter.drawRect(0, 0, progress, self.height())
|
||||
return
|
||||
|
||||
# END Class NProgressSimple
|
||||
|
||||
@@ -27,7 +27,7 @@ import logging
|
||||
|
||||
from typing import Literal
|
||||
|
||||
from PyQt5.QtGui import QColor, QPaintEvent, QPainter
|
||||
from PyQt5.QtGui import QColor, QPainter, QPaintEvent
|
||||
from PyQt5.QtWidgets import QAbstractButton, QWidget
|
||||
|
||||
from novelwriter.types import QtPaintAnitAlias
|
||||
@@ -75,5 +75,3 @@ class StatusLED(QAbstractButton):
|
||||
painter.setOpacity(1.0)
|
||||
painter.drawEllipse(1, 1, self.width() - 2, self.height() - 2)
|
||||
return
|
||||
|
||||
# END Class StatusLED
|
||||
|
||||
@@ -23,12 +23,12 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
|
||||
from PyQt5.QtCore import QEvent, QPropertyAnimation, Qt, pyqtProperty
|
||||
from PyQt5.QtWidgets import QAbstractButton, QSizePolicy, QWidget
|
||||
from PyQt5.QtGui import QMouseEvent, QPainter, QPaintEvent, QResizeEvent
|
||||
from PyQt5.QtWidgets import QAbstractButton, QWidget
|
||||
|
||||
from novelwriter import CONFIG, SHARED
|
||||
from novelwriter.types import QtPaintAnitAlias, QtMouseLeft, QtNoPen
|
||||
from novelwriter.types import QtMouseLeft, QtNoPen, QtPaintAnitAlias, QtSizeFixed
|
||||
|
||||
|
||||
class NSwitch(QAbstractButton):
|
||||
@@ -46,7 +46,7 @@ class NSwitch(QAbstractButton):
|
||||
self._rR = self._xR - self._rB
|
||||
|
||||
self.setCheckable(True)
|
||||
self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed)
|
||||
self.setSizePolicy(QtSizeFixed, QtSizeFixed)
|
||||
self.setFixedWidth(self._xW)
|
||||
self.setFixedHeight(self._xH)
|
||||
self._offset = self._xR
|
||||
@@ -133,5 +133,3 @@ class NSwitch(QAbstractButton):
|
||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
super().enterEvent(event)
|
||||
return
|
||||
|
||||
# END Class NSwitch
|
||||
|
||||
@@ -23,12 +23,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QSizePolicy, QWidget
|
||||
from PyQt5.QtGui import QIcon
|
||||
from PyQt5.QtWidgets import QGridLayout, QLabel, QScrollArea, QWidget
|
||||
|
||||
from novelwriter.extensions.switch import NSwitch
|
||||
from novelwriter.types import QtAlignLeft, QtAlignRight, QtAlignRightMiddle
|
||||
from novelwriter.types import (
|
||||
QtAlignLeft, QtAlignRight, QtAlignRightMiddle, QtSizeMinimum,
|
||||
QtSizeMinimumExpanding
|
||||
)
|
||||
|
||||
|
||||
class NSwitchBox(QScrollArea):
|
||||
@@ -59,7 +62,7 @@ class NSwitchBox(QScrollArea):
|
||||
self._content.setColumnStretch(1, 1)
|
||||
|
||||
self._widget = QWidget(self)
|
||||
self._widget.setSizePolicy(QSizePolicy.Policy.MinimumExpanding, QSizePolicy.Policy.Minimum)
|
||||
self._widget.setSizePolicy(QtSizeMinimumExpanding, QtSizeMinimum)
|
||||
self._widget.setLayout(self._content)
|
||||
|
||||
self.setWidgetResizable(True)
|
||||
@@ -124,5 +127,3 @@ class NSwitchBox(QScrollArea):
|
||||
self._content.setRowStretch(self._index + 1, 1)
|
||||
self._index += 1
|
||||
return
|
||||
|
||||
# END Class NSwitchBox
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user