diff --git a/i18n/nw_base.ts b/i18n/nw_base.ts index b4728c00..7360cfe3 100644 --- a/i18n/nw_base.ts +++ b/i18n/nw_base.ts @@ -1313,6 +1313,11 @@ novelWriter is ready ... + + + You are now running novelWriter version {0}. + + Please check the {0}release notes{1} for further details. @@ -4169,73 +4174,67 @@ - + + Add {0} chapter documents + + + - Add + Add {0} scene documents (to each chapter) - - chapter documents - - - - - scene documents (to each chapter) - - - - + Add a folder for plot notes - + Add a folder for character notes - + Add a folder for location notes - + Add example notes to the above - + Chapters and Scenes - + Project Notes - + Create New Project - + Select Project Folder - + Fresh Project - + Example Project - + Template: {0} diff --git a/i18n/nw_de_DE.ts b/i18n/nw_de_DE.ts index 3ab9c8f6..9c7f2b15 100644 --- a/i18n/nw_de_DE.ts +++ b/i18n/nw_de_DE.ts @@ -311,7 +311,7 @@ Characters - Charaktere + Figuren @@ -394,7 +394,7 @@ Novel Scene - Roman Szene + Szene @@ -1313,6 +1313,11 @@ novelWriter is ready ... novelWriter ist bereit ... + + + You are now running novelWriter version {0}. + Sie verwenden jetzt die novelWriter-Version {0}. + Please check the {0}release notes{1} for further details. @@ -2322,7 +2327,7 @@ Characters - Charaktere + Zeichen @@ -3175,37 +3180,37 @@ GuiWelcome - + Welcome Willkommen - + List Liste - + New Neu - + Browse Auswählen - + Cancel Abbrechen - + Create Erstellen - + Open Öffnen @@ -4119,123 +4124,117 @@ _NewProjectForm - + Required Erforderlich - + Optional Optional - + Create a fresh project Neues Projekt erstellen - + Create an example project Beispielprojekt erstellen - + Copy an existing project Vorhandenes Projekt kopieren - + Project Name Projektname - + Author Autor - + Project Path Projektpfad - + Prefill Project Projekt vorbereiten - + Set to 0 to only add scenes Auf 0 setzen um nur Szenen hinzuzufügen + + + Add {0} chapter documents + {0} Kapiteldokumente hinzufügen + - - Add - + Add {0} scene documents (to each chapter) + {0} Szenendokumente hinzufügen (pro Kapitel) - - chapter documents - Kapitel - - - - scene documents (to each chapter) - Szenen (pro Kapitel) - - - + Add a folder for plot notes Ordner hinzufügen: Notizen für Handlungsstränge - + Add a folder for character notes Ordner hinzufügen: Notizen für Figuren - + Add a folder for location notes Ordner hinzufügen: Notizen für Schauplätze - + Add example notes to the above Beispielnotizen zur obigen Auswahl hinzufügen - + Chapters and Scenes Kapitel und Szenen - + Project Notes Projektnotizen - + Create New Project Neues Projekt erstellen - + Select Project Folder Speicherort wählen - + Fresh Project Neues Projekt - + Example Project Beispielprojekt - + Template: {0} Vorlage: {0} @@ -4243,7 +4242,7 @@ _NewProjectPage - + A project name is required. Ein Projektname ist erforderlich. @@ -4251,27 +4250,27 @@ _OpenProjectPage - + The project path is not reachable. Der Projektpfad ist nicht erreichbar. - + Path Pfad - + Remove '{0}' from the recent projects list? The project files will not be deleted. „{0}“ von der Liste der zuletzt geöffneten Projekte entfernen? Ihre Daten werden nicht gelöscht. - + Open Project Projekt öffnen - + Remove Project Projekt entfernen @@ -4362,12 +4361,12 @@ _ProjectListModel - + Word Count Wörter - + Last Opened Zuletzt geöffnet @@ -4382,7 +4381,7 @@ Keyword - Schlagwort + Stichwort diff --git a/i18n/nw_en_US.ts b/i18n/nw_en_US.ts index 89d04722..597c1248 100644 --- a/i18n/nw_en_US.ts +++ b/i18n/nw_en_US.ts @@ -1313,6 +1313,11 @@ novelWriter is ready ... novelWriter is ready ... + + + You are now running novelWriter version {0}. + You are now running novelWriter version {0}. + Please check the {0}release notes{1} for further details. @@ -3175,37 +3180,37 @@ GuiWelcome - + Welcome Welcome - + List List - + New New - + Browse Browse - + Cancel Cancel - + Create Create - + Open Open @@ -4119,123 +4124,117 @@ _NewProjectForm - + Required Required - + Optional Optional - + Create a fresh project Create a fresh project - + Create an example project Create an example project - + Copy an existing project Copy an existing project - + Project Name Project Name - + Author Author - + Project Path Project Path - + Prefill Project Prefill Project - + Set to 0 to only add scenes Set to 0 to only add scenes + + + Add {0} chapter documents + Add {0} chapter documents + - - Add - Add + Add {0} scene documents (to each chapter) + Add {0} scene documents (to each chapter) - - chapter documents - chapter documents - - - - scene documents (to each chapter) - scene documents (to each chapter) - - - + Add a folder for plot notes Add a folder for plot notes - + Add a folder for character notes Add a folder for character notes - + Add a folder for location notes Add a folder for location notes - + Add example notes to the above Add example notes to the above - + Chapters and Scenes Chapters and Scenes - + Project Notes Project Notes - + Create New Project Create New Project - + Select Project Folder Select Project Folder - + Fresh Project Fresh Project - + Example Project Example Project - + Template: {0} Template: {0} @@ -4243,7 +4242,7 @@ _NewProjectPage - + A project name is required. A project name is required. @@ -4251,27 +4250,27 @@ _OpenProjectPage - + The project path is not reachable. The project path is not reachable. - + Path Path - + Remove '{0}' from the recent projects list? The project files will not be deleted. Remove '{0}' from the recent projects list? The project files will not be deleted. - + Open Project Open Project - + Remove Project Remove Project @@ -4362,12 +4361,12 @@ _ProjectListModel - + Word Count Word Count - + Last Opened Last Opened diff --git a/i18n/nw_nb_NO.ts b/i18n/nw_nb_NO.ts index dc025e97..c06d29da 100644 --- a/i18n/nw_nb_NO.ts +++ b/i18n/nw_nb_NO.ts @@ -1313,6 +1313,11 @@ novelWriter is ready ... novelWriter er klar ... + + + You are now running novelWriter version {0}. + Du kjører nå novelWriter versjon {0}. + Please check the {0}release notes{1} for further details. @@ -3175,37 +3180,37 @@ GuiWelcome - + Welcome Velkommen - + List Liste - + New Nytt - + Browse Bla gjennom - + Cancel Avbryt - + Create Opprett - + Open Åpne @@ -4119,123 +4124,117 @@ _NewProjectForm - + Required Påkrevd - + Optional Valgfritt - + Create a fresh project Opprett et nytt prosjekt - + Create an example project Opprett et eksempelprosjekt - + Copy an existing project Kopier et eksisterende prosjekt - + Project Name Prosjektnavn - + Author Forfatter - + Project Path Filbane - + Prefill Project Forhåndsfyll prosjektet - + Set to 0 to only add scenes Satt til 0 for bare å legge til scener + + + Add {0} chapter documents + Legg til {0} kapitteldokumenter + - - Add - Legg til + Add {0} scene documents (to each chapter) + Legg til {0} scenedokumenter (til hvert kapittel) - - chapter documents - kapittel-dokumenter - - - - scene documents (to each chapter) - scene-dokumenter (i hvert kapittel) - - - + Add a folder for plot notes Legg til en mappe for plott-notater - + Add a folder for character notes Legg til en mappe for karakterer - + Add a folder for location notes Legg til en mappe for lokasjoner - + Add example notes to the above Lag eksempelfiler til ovennevnte - + Chapters and Scenes Kapittel og scener - + Project Notes Prosjektnotater - + Create New Project Opprett nytt prosjekt - + Select Project Folder Velg prosjektmappe - + Fresh Project Nytt prosjekt - + Example Project Eksempelprosjekt - + Template: {0} Mal: {0} @@ -4243,7 +4242,7 @@ _NewProjectPage - + A project name is required. Vennligst oppgi et prosjektnavn. @@ -4251,27 +4250,27 @@ _OpenProjectPage - + The project path is not reachable. Prosjektets bane er ikke tilgjengelig. - + Path Filbane - + Remove '{0}' from the recent projects list? The project files will not be deleted. Vil du fjerne {0} fra listen over tidligere åpnede prosjekter? Selve prosjektfilene blir ikke slettet. - + Open Project Åpne prosjekt - + Remove Project Fjern prosjekt @@ -4362,12 +4361,12 @@ _ProjectListModel - + Word Count Antall ord - + Last Opened Sist åpnet diff --git a/novelwriter/config.py b/novelwriter/config.py index 568c0376..85786119 100644 --- a/novelwriter/config.py +++ b/novelwriter/config.py @@ -30,6 +30,7 @@ import logging from time import time from pathlib import Path +from datetime import datetime from PyQt5.QtGui import QFontDatabase from PyQt5.QtCore import ( @@ -84,8 +85,11 @@ class Config: self._nwLangPath = self._appPath / "assets" / "i18n" self._qtLangPath = QLibraryInfo.location(QLibraryInfo.TranslationsPath) - wantedLocale = self._nwLangPath / f"nw_{QLocale.system().name()}.qm" - self._qLocale = QLocale.system() if wantedLocale.exists() else QLocale("en_GB") + hasLocale = (self._nwLangPath / f"nw_{QLocale.system().name()}.qm").exists() + self._qLocale = QLocale.system() if hasLocale else QLocale("en_GB") + self._dLocale = QLocale.system() + self._dShortDate = self._dLocale.dateFormat(QLocale.FormatType.ShortFormat) + self._dShortDateTime = self._dLocale.dateTimeFormat(QLocale.FormatType.ShortFormat) self._qtTrans = {} # PDF Manual @@ -414,6 +418,14 @@ class Config: self._errData = [] return message + def localDate(self, value: datetime) -> str: + """Return a localised date format.""" + return self._dLocale.toString(value, self._dShortDate) + + def localDateTime(self, value: datetime) -> str: + """Return a localised datetime format.""" + return self._dLocale.toString(value, self._dShortDateTime) + def listLanguages(self, lngSet: int) -> list[tuple[str, str]]: """List localisation files in the i18n folder. The default GUI language is British English (en_GB). @@ -496,6 +508,11 @@ class Config: QLocale.setDefault(self._qLocale) self._qtTrans = {} + hasLocale = (self._nwLangPath / f"nw_{self._qLocale.name()}.qm").exists() + self._dLocale = self._qLocale if hasLocale else QLocale.system() + self._dShortDate = self._dLocale.dateFormat(QLocale.FormatType.ShortFormat) + self._dShortDateTime = self._dLocale.dateTimeFormat(QLocale.FormatType.ShortFormat) + langList = [ (self._qtLangPath, "qtbase"), # Qt 5.x (str(self._nwLangPath), "nw"), # novelWriter diff --git a/novelwriter/dialogs/preferences.py b/novelwriter/dialogs/preferences.py index 690ad08e..142b837d 100644 --- a/novelwriter/dialogs/preferences.py +++ b/novelwriter/dialogs/preferences.py @@ -151,8 +151,7 @@ class GuiPreferences(QDialog): self.guiLocale.setMinimumWidth(minWidth) for lang, name in CONFIG.listLanguages(CONFIG.LANG_NW): self.guiLocale.addItem(name, lang) - if (idx := self.guiLocale.findData(CONFIG.guiLocale)) != -1: - self.guiLocale.setCurrentIndex(idx) + self.guiLocale.setCurrentData(CONFIG.guiLocale, "en_GB") self.mainForm.addRow( self.tr("Display language"), self.guiLocale, @@ -164,8 +163,7 @@ class GuiPreferences(QDialog): self.guiTheme.setMinimumWidth(minWidth) for theme, name in SHARED.theme.listThemes(): self.guiTheme.addItem(name, theme) - if (idx := self.guiTheme.findData(CONFIG.guiTheme)) != -1: - self.guiTheme.setCurrentIndex(idx) + self.guiTheme.setCurrentData(CONFIG.guiTheme, "default") self.mainForm.addRow( self.tr("Colour theme"), self.guiTheme, @@ -226,8 +224,7 @@ class GuiPreferences(QDialog): self.guiSyntax.setMinimumWidth(CONFIG.pxInt(200)) for syntax, name in SHARED.theme.listSyntax(): self.guiSyntax.addItem(name, syntax) - if (idx := self.guiSyntax.findData(CONFIG.guiSyntax)) != -1: - self.guiSyntax.setCurrentIndex(idx) + self.guiSyntax.setCurrentData(CONFIG.guiSyntax, "default_light") self.mainForm.addRow( self.tr("Document colour theme"), self.guiSyntax, diff --git a/novelwriter/extensions/configlayout.py b/novelwriter/extensions/configlayout.py index aa168778..280caedc 100644 --- a/novelwriter/extensions/configlayout.py +++ b/novelwriter/extensions/configlayout.py @@ -7,6 +7,7 @@ Created: 2020-05-03 [0.4.5] NColourLabel Created: 2024-01-08 [2.3b1] NScrollableForm Created: 2024-01-26 [2.3b1] NScrollablePage Created: 2024-01-26 [2.3b1] NFixedPage +Created: 2024-03-12 [2.4b1] NWrappedWidgetBox This file is a part of novelWriter Copyright 2018–2024, Veronica Berglyd Olsen @@ -269,3 +270,24 @@ class NColourLabel(QLabel): return # END Class NColourLabel + + +class NWrappedWidgetBox(QHBoxLayout): + """Extension: A Text-Wrapped Widget Box + + A custom layout box where a widget is wrapped in text labels on + either side within a layout box. The widget is inserted at the {0} + position so that it can be used for translation strings. + """ + + def __init__(self, text: str, widget: QWidget) -> None: + super().__init__() + before, _, after = text.partition(r"{0}") + if before: + self.addWidget(QLabel(before.rstrip())) + self.addWidget(widget) + if after: + self.addWidget(QLabel(after.lstrip())) + return + +# END Class NWrappedWidgetBox diff --git a/novelwriter/extensions/modified.py b/novelwriter/extensions/modified.py index cebb8b74..39416b23 100644 --- a/novelwriter/extensions/modified.py +++ b/novelwriter/extensions/modified.py @@ -44,6 +44,12 @@ class NComboBox(QComboBox): event.ignore() return + def setCurrentData(self, data: str, default: str) -> 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 diff --git a/novelwriter/extensions/versioninfo.py b/novelwriter/extensions/versioninfo.py index 08cbc74e..6ac78794 100644 --- a/novelwriter/extensions/versioninfo.py +++ b/novelwriter/extensions/versioninfo.py @@ -57,7 +57,7 @@ class VersionInfoWidget(QWidget): # Labels self._lblInfo = QLabel("{0} {1} \u2013 {2} {3} \u2013 {4}".format( self.tr("Version"), formatVersion(__version__), - self.tr("Released on"), datetime.strptime(__date__, "%Y-%m-%d").strftime("%x"), + self.tr("Released on"), CONFIG.localDate(datetime.strptime(__date__, "%Y-%m-%d")), "{0}".format(self.tr("Release Notes")), ), self) self._lblInfo.linkActivated.connect(self._processLink) diff --git a/novelwriter/guimain.py b/novelwriter/guimain.py index 9ca97ba7..f2a3e8ff 100644 --- a/novelwriter/guimain.py +++ b/novelwriter/guimain.py @@ -355,8 +355,8 @@ class GuiMain(QMainWindow): if hexToInt(CONFIG.lastNotes) < hexToInt(__hexversion__): CONFIG.lastNotes = __hexversion__ trVersion = self.tr( - "You are now running novelWriter version {0}.".format(formatVersion(__version__)) - ) + "You are now running novelWriter version {0}." + ).format(formatVersion(__version__)) trRelease = self.tr( "Please check the {0}release notes{1} for further details." ).format(f"", "") @@ -457,7 +457,7 @@ class GuiMain(QMainWindow): "'{0}' ({1} {2}), last active on {3}." ).format( lockStatus[0], lockStatus[1], lockStatus[2], - datetime.fromtimestamp(int(lockStatus[3])).strftime("%x %X") + CONFIG.localDateTime(datetime.fromtimestamp(int(lockStatus[3]))) ) except Exception: lockDetails = "" diff --git a/novelwriter/tools/manuscript.py b/novelwriter/tools/manuscript.py index aa686d74..3f52e9c8 100644 --- a/novelwriter/tools/manuscript.py +++ b/novelwriter/tools/manuscript.py @@ -827,7 +827,7 @@ class _PreviewWidget(QTextBrowser): """Update the build time and the fuzzy age.""" if self._docTime > 0: strBuildTime = "%s (%s)" % ( - datetime.fromtimestamp(self._docTime).strftime("%x %X"), + CONFIG.localDateTime(datetime.fromtimestamp(self._docTime)), fuzzyTime(int(time()) - self._docTime) ) else: diff --git a/novelwriter/tools/welcome.py b/novelwriter/tools/welcome.py index 99d0c901..ec7869f5 100644 --- a/novelwriter/tools/welcome.py +++ b/novelwriter/tools/welcome.py @@ -45,6 +45,7 @@ from novelwriter.enum import nwItemClass from novelwriter.common import formatInt, makeFileNameSafe from novelwriter.constants import nwFiles from novelwriter.core.coretools import ProjectBuilder +from novelwriter.extensions.configlayout import NWrappedWidgetBox from novelwriter.extensions.switch import NSwitch from novelwriter.extensions.modified import NSpinBox from novelwriter.extensions.versioninfo import VersionInfoWidget @@ -455,7 +456,7 @@ class _ProjectListModel(QAbstractListModel): opened = self.tr("Last Opened") records = sorted(CONFIG.recentProjects.listEntries(), key=lambda x: x[3], reverse=True) for path, title, count, time in records: - when = datetime.fromtimestamp(time).strftime("%x") + when = CONFIG.localDate(datetime.fromtimestamp(time)) data.append((title, path, f"{opened}: {when}, {words}: {formatInt(count)}")) self._data = data return @@ -630,20 +631,18 @@ class _NewProjectForm(QWidget): self.numChapters.setValue(5) self.numChapters.setToolTip(self.tr("Set to 0 to only add scenes")) - self.chapterBox = QHBoxLayout() - self.chapterBox.addWidget(QLabel(self.tr("Add"))) - self.chapterBox.addWidget(self.numChapters) - self.chapterBox.addWidget(QLabel(self.tr("chapter documents"))) + self.chapterBox = NWrappedWidgetBox( + self.tr("Add {0} chapter documents"), self.numChapters + ) self.chapterBox.addStretch(1) self.numScenes = NSpinBox(self) self.numScenes.setRange(0, 200) self.numScenes.setValue(5) - self.sceneBox = QHBoxLayout() - self.sceneBox.addWidget(QLabel(self.tr("Add"))) - self.sceneBox.addWidget(self.numScenes) - self.sceneBox.addWidget(QLabel(self.tr("scene documents (to each chapter)"))) + self.sceneBox = NWrappedWidgetBox( + self.tr("Add {0} scene documents (to each chapter)"), self.numScenes + ) self.sceneBox.addStretch(1) self.novelForm = QVBoxLayout() diff --git a/tests/test_tools/test_tools_welcome.py b/tests/test_tools/test_tools_welcome.py index 11d2e6c3..29900674 100644 --- a/tests/test_tools/test_tools_welcome.py +++ b/tests/test_tools/test_tools_welcome.py @@ -75,8 +75,8 @@ def testToolWelcome_Open(qtbot: QtBot, monkeypatch, nwGUI, fncPath): CONFIG.recentProjects.update("/stuff/project_one", "Project One", 12345, 1690000000) CONFIG.recentProjects.update("/stuff/project_two", "Project Two", 54321, 1700000000) - dateOne = datetime.fromtimestamp(1700000000).strftime("%x") - dateTwo = datetime.fromtimestamp(1690000000).strftime("%x") + dateOne = CONFIG.localDate(datetime.fromtimestamp(1700000000)) + dateTwo = CONFIG.localDate(datetime.fromtimestamp(1690000000)) welcome = GuiWelcome(nwGUI) with qtbot.waitExposed(welcome):