From e3ba9b5e87fd774f5e96a22de9f36c2c4b07ca5a Mon Sep 17 00:00:00 2001 From: Carlo Baratto Date: Wed, 19 Aug 2026 16:17:30 +0200 Subject: [PATCH] Localizzazione EN di default: qsTr() su tutte le stringhe QML, catalogo italiano translations/harbour-calibreweb_it.ts, lrelease+install .qm nello spec (pattern quill), .pro aggiornato --- harbour-calibreweb.pro | 10 +- qml/cover/CoverPage.qml | 2 +- qml/pages/BookDetailPage.qml | 10 +- qml/pages/ChapterListDialog.qml | 4 +- qml/pages/FeedPage.qml | 8 +- qml/pages/MainPage.qml | 14 +- qml/pages/MarginDialog.qml | 10 +- qml/pages/ReaderPage.qml | 14 +- qml/pages/SearchPage.qml | 10 +- qml/pages/SettingsPage.qml | 30 +-- rpm/harbour-calibreweb.spec | 23 +++ translations/harbour-calibreweb_it.ts | 277 ++++++++++++++++++++++++++ 12 files changed, 360 insertions(+), 52 deletions(-) create mode 100644 translations/harbour-calibreweb_it.ts diff --git a/harbour-calibreweb.pro b/harbour-calibreweb.pro index 005c8f3..7a5b444 100644 --- a/harbour-calibreweb.pro +++ b/harbour-calibreweb.pro @@ -27,10 +27,18 @@ OTHER_FILES += \ qml/cover/*.qml \ rpm/harbour-calibreweb.spec \ rpm/harbour-calibreweb.desktop \ - rpm/harbour-calibreweb.yaml + rpm/harbour-calibreweb.yaml \ + translations/harbour-calibreweb_it.ts DISTFILES += $$OTHER_FILES +# Translations are NOT handled by the sailfishapp_i18n template on the 5.1 kit +# (the .qm is never generated/installed reliably). The spec builds the .qm +# with lrelease and installs it into /usr/share/translations directly; +# libsailfishapp loads harbour-calibreweb_.qm automatically. +# Source strings are ENGLISH (default language); harbour-calibreweb_it.ts +# provides the Italian catalogue. + # Icone installate via make install (struttura standard Sailfish: icons//.png) icons86.path = /usr/share/icons/hicolor/86x86/apps icons86.files = $$PWD/icons/86x86/harbour-calibreweb.png diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml index 557d648..7fb6f0f 100644 --- a/qml/cover/CoverPage.qml +++ b/qml/cover/CoverPage.qml @@ -15,7 +15,7 @@ CoverBackground { Label { anchors.horizontalCenter: parent.horizontalCenter - text: "Calibre Web" + text: qsTr("Calibre Web") color: Theme.primaryColor font.pixelSize: Theme.fontSizeSmall } diff --git a/qml/pages/BookDetailPage.qml b/qml/pages/BookDetailPage.qml index 5748655..6f253af 100644 --- a/qml/pages/BookDetailPage.qml +++ b/qml/pages/BookDetailPage.qml @@ -33,7 +33,7 @@ Page { Button { anchors.horizontalCenter: parent.horizontalCenter - text: "Leggi (EPUB)" + text: qsTr("Read (EPUB)") visible: page.hasEpubFormat() enabled: !page.downloading onClicked: startReading() @@ -57,7 +57,7 @@ Page { visible: text.length > 0 } - SectionHeader { text: "Formati" } + SectionHeader { text: qsTr("Formats") } Repeater { model: bookData.formats @@ -109,7 +109,7 @@ Page { } Label { anchors.horizontalCenter: parent.horizontalCenter - text: "Download in corso…" + text: qsTr("Downloading…") color: Theme.secondaryColor font.pixelSize: Theme.fontSizeSmall } @@ -258,12 +258,12 @@ Page { return } page.downloadError = "" - page.downloadNotice = "Salvato in " + path + page.downloadNotice = qsTr("Saved to ") + path hideNoticeTimer.restart() } else { page.downloadNotice = "" page.readingNow = false - page.downloadError = "Errore: " + error + page.downloadError = qsTr("Error: ") + error } } } diff --git a/qml/pages/ChapterListDialog.qml b/qml/pages/ChapterListDialog.qml index 8c2f77f..438520c 100644 --- a/qml/pages/ChapterListDialog.qml +++ b/qml/pages/ChapterListDialog.qml @@ -9,7 +9,7 @@ Dialog { SilicaListView { anchors.fill: parent - header: DialogHeader { title: "Indice" } + header: DialogHeader { title: qsTr("Table of contents") } model: dialog.model delegate: ListItem { @@ -35,7 +35,7 @@ Dialog { ViewPlaceholder { enabled: dialog.model.length === 0 - text: "Nessun capitolo" + text: qsTr("No chapters") } } } diff --git a/qml/pages/FeedPage.qml b/qml/pages/FeedPage.qml index c5c7861..af008d3 100644 --- a/qml/pages/FeedPage.qml +++ b/qml/pages/FeedPage.qml @@ -88,18 +88,18 @@ Page { PullDownMenu { MenuItem { - text: "Aggiorna" + text: qsTr("Refresh") onClicked: reload() } MenuItem { - text: "Impostazioni" + text: qsTr("Settings") onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml")) } } ViewPlaceholder { enabled: feedModel.count === 0 && !page.loading - text: page.errorMessage.length > 0 ? page.errorMessage : "Nessun risultato" + text: page.errorMessage.length > 0 ? page.errorMessage : qsTr("No results") } BusyIndicator { @@ -168,7 +168,7 @@ Page { } page.nextUrl = nextUrl if (feedModel.count === 0 && page.errorMessage.length === 0) - page.errorMessage = "Nessun risultato" + page.errorMessage = qsTr("No results") } onFeedError: { page.loading = false diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml index 5d2fa94..d138a41 100644 --- a/qml/pages/MainPage.qml +++ b/qml/pages/MainPage.qml @@ -10,7 +10,7 @@ Page { SilicaListView { id: listView anchors.fill: parent - header: PageHeader { title: "Calibre Web" } + header: PageHeader { title: qsTr("Calibre Web") } model: sectionModel delegate: ListItem { @@ -40,15 +40,15 @@ Page { PullDownMenu { MenuItem { - text: "Cerca" + text: qsTr("Search") onClicked: pageStack.push(Qt.resolvedUrl("SearchPage.qml")) } MenuItem { - text: "Impostazioni" + text: qsTr("Settings") onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml")) } MenuItem { - text: "Aggiorna" + text: qsTr("Refresh") onClicked: loadIndex() } } @@ -57,7 +57,7 @@ Page { enabled: sectionModel.count === 0 && !page.loading text: page.errorMessage.length > 0 ? page.errorMessage - : "Apri le impostazioni e inserisci l'indirizzo del tuo Calibre Web" + : qsTr("Open the settings and enter your Calibre Web address") } BusyIndicator { @@ -74,7 +74,7 @@ Page { function loadIndex() { var base = appSettings.baseUrl if (base.length === 0) { - page.errorMessage = "Server non configurato" + page.errorMessage = qsTr("Server not configured") return } page.loading = true @@ -97,7 +97,7 @@ Page { sectionModel.append({ title: e.title, linkUrl: e.linkUrl }) } if (sectionModel.count === 0) - page.errorMessage = "Nessuna sezione trovata nel feed OPDS" + page.errorMessage = qsTr("No sections found in the OPDS feed") } onFeedError: { page.loading = false diff --git a/qml/pages/MarginDialog.qml b/qml/pages/MarginDialog.qml index 09b1e7e..a7bcdbe 100644 --- a/qml/pages/MarginDialog.qml +++ b/qml/pages/MarginDialog.qml @@ -22,14 +22,14 @@ Dialog { width: parent.width DialogHeader { - title: "Margini del testo" - acceptText: "Applica" + title: qsTr("Text margins") + acceptText: qsTr("Apply") } Slider { id: lrSlider width: parent.width - label: "Margini laterali" + label: qsTr("Side margins") minimumValue: 0 maximumValue: 80 stepSize: 4 @@ -44,7 +44,7 @@ Dialog { Slider { id: tbSlider width: parent.width - label: "Alto e basso" + label: qsTr("Top and bottom") minimumValue: 0 maximumValue: 80 stepSize: 4 @@ -59,7 +59,7 @@ Dialog { Label { x: Theme.horizontalPageMargin width: parent.width - 2 * Theme.horizontalPageMargin - text: "Le modifiche si applicano subito al testo. Conferma per salvarle per tutti i libri." + text: qsTr("Changes apply immediately. Confirm to save them for all books.") color: Theme.secondaryColor wrapMode: Text.Wrap font.pixelSize: Theme.fontSizeSmall diff --git a/qml/pages/ReaderPage.qml b/qml/pages/ReaderPage.qml index 0057b65..742dfa8 100644 --- a/qml/pages/ReaderPage.qml +++ b/qml/pages/ReaderPage.qml @@ -32,11 +32,11 @@ Page { // il PullDownMenu va DENTRO una vista Silica, non a livello di Page PullDownMenu { MenuItem { - text: "Indice capitoli" + text: qsTr("Table of contents") onClicked: showChapterList() } MenuItem { - text: "Margini del testo" + text: qsTr("Text margins") onClicked: { var dlg = pageStack.push(Qt.resolvedUrl("MarginDialog.qml"), { marginLr: appSettings.readerMargin, @@ -50,11 +50,11 @@ Page { } } MenuItem { - text: "Impostazioni" + text: qsTr("Settings") onClicked: pageStack.push(Qt.resolvedUrl("SettingsPage.qml")) } MenuItem { - text: "Chiudi libro" + text: qsTr("Close book") onClicked: { page.maybeSave(true) pageStack.popTo(null) @@ -164,7 +164,7 @@ Page { interval: 15000 onTriggered: { if (!web.loaded && !page.ready) { - page.errorMessage = "Il lettore non risponde (WebView). Il file EPUB potrebbe essere danneggiato." + page.errorMessage = qsTr("The reader is not responding (WebView). The EPUB file may be damaged.") page.ready = true } } @@ -287,7 +287,7 @@ Page { var html = book.chapterHtml(page.currentChapter, page.fontPx(), appSettings.readerMargin, appSettings.readerMarginV) if (html.length === 0) { - page.errorMessage = "Capitolo non leggibile" + page.errorMessage = qsTr("Chapter unreadable") page.ready = true return } @@ -336,7 +336,7 @@ Page { Component.onCompleted: { page.ready = false if (!book.open(page.epubPath)) { - page.errorMessage = "Impossibile aprire il libro EPUB" + page.errorMessage = qsTr("Unable to open the EPUB file") page.ready = true return } diff --git a/qml/pages/SearchPage.qml b/qml/pages/SearchPage.qml index b3470b0..f36ab50 100644 --- a/qml/pages/SearchPage.qml +++ b/qml/pages/SearchPage.qml @@ -12,19 +12,19 @@ Page { id: column width: parent.width - PageHeader { title: "Cerca" } + PageHeader { title: qsTr("Search") } SearchField { id: searchField width: parent.width - placeholderText: "Titolo o autore…" + placeholderText: qsTr("Title or author…") EnterKey.enabled: text.length > 0 EnterKey.onClicked: search() } Button { anchors.horizontalCenter: parent.horizontalCenter - text: "Cerca" + text: qsTr("Search") enabled: searchField.text.length > 0 onClicked: search() } @@ -32,7 +32,7 @@ Page { Label { x: Theme.horizontalPageMargin width: parent.width - 2 * Theme.horizontalPageMargin - text: "La ricerca usa il motore del server (OPDS search)." + text: qsTr("Search uses the server engine (OPDS search).") color: Theme.secondaryColor font.pixelSize: Theme.fontSizeSmall wrapMode: Text.Wrap @@ -47,6 +47,6 @@ Page { return var url = base + "/opds/search?query=" + encodeURIComponent(query) pageStack.push(Qt.resolvedUrl("FeedPage.qml"), - { feedUrl: url, pageTitle: "Risultati: " + query }) + { feedUrl: url, pageTitle: qsTr("Results: ") + query }) } } diff --git a/qml/pages/SettingsPage.qml b/qml/pages/SettingsPage.qml index 8a5b648..19326bd 100644 --- a/qml/pages/SettingsPage.qml +++ b/qml/pages/SettingsPage.qml @@ -16,15 +16,15 @@ Page { id: column width: parent.width - PageHeader { title: "Impostazioni" } + PageHeader { title: qsTr("Settings") } - SectionHeader { text: "Server" } + SectionHeader { text: qsTr("Server") } TextField { id: serverField anchors.left: parent.left anchors.right: parent.right - label: "Indirizzo Calibre Web" + label: qsTr("Calibre Web address") placeholderText: "https://calibre.example.com" text: appSettings.serverUrl inputMethodHints: Qt.ImhUrlCharactersOnly @@ -35,7 +35,7 @@ Page { id: userField anchors.left: parent.left anchors.right: parent.right - label: "Utente (vuoto = accesso anonimo)" + label: qsTr("User (empty = anonymous access)") text: appSettings.username onTextChanged: appSettings.username = text } @@ -44,25 +44,25 @@ Page { id: passField anchors.left: parent.left anchors.right: parent.right - label: "Password" + label: qsTr("Password") text: appSettings.password echoMode: TextInput.Password onTextChanged: appSettings.password = text } TextSwitch { - text: "Ignora errori certificato SSL" - description: "Da attivare se il server usa un certificato autofirmato" + text: qsTr("Ignore SSL certificate errors") + description: qsTr("Enable if the server uses a self-signed certificate") checked: appSettings.ignoreSslErrors onCheckedChanged: appSettings.ignoreSslErrors = checked } - SectionHeader { text: "Lettore" } + SectionHeader { text: qsTr("Reader") } Slider { id: marginSlider width: parent.width - label: "Margini laterali" + label: qsTr("Side margins") minimumValue: 0 maximumValue: 80 stepSize: 4 @@ -74,7 +74,7 @@ Page { Slider { id: marginVSlider width: parent.width - label: "Margine alto e basso" + label: qsTr("Top and bottom margin") minimumValue: 0 maximumValue: 80 stepSize: 4 @@ -83,11 +83,11 @@ Page { onValueChanged: appSettings.readerMarginV = value } - SectionHeader { text: "Connessione" } + SectionHeader { text: qsTr("Connection") } Button { anchors.horizontalCenter: parent.horizontalCenter - text: "Prova connessione" + text: qsTr("Test connection") enabled: !page.testing onClicked: testConnection() } @@ -118,7 +118,7 @@ Page { function testConnection() { var base = appSettings.serverUrl.trim() if (base.length === 0) { - page.testResult = "Inserisci l'indirizzo del server" + page.testResult = qsTr("Enter the server address") page.testOk = false return } @@ -127,7 +127,7 @@ Page { base = "https://" + base appSettings.serverUrl = base page.testing = true - page.testResult = "Verifica in corso…" + page.testResult = qsTr("Testing…") apiClient.getFeed(base + "/opds") } @@ -138,7 +138,7 @@ Page { return page.testing = false page.testOk = true - page.testResult = "Connessione OK: " + entries.length + " sezioni trovate" + page.testResult = qsTr("Connection OK: %1 sections found").arg(entries.length) } onFeedError: { if (pageStack.currentPage !== page) diff --git a/rpm/harbour-calibreweb.spec b/rpm/harbour-calibreweb.spec index 3f816ac..c19c3c0 100644 --- a/rpm/harbour-calibreweb.spec +++ b/rpm/harbour-calibreweb.spec @@ -25,6 +25,8 @@ in locale. %changelog * Wed Aug 19 2026 Carlo Baratto - 0.2.0-1 +- Localizzazione: lingua di default inglese (qsTr ovunque), catalogo + italiano harbour-calibreweb_it.ts/.qm installato in /usr/share/translations - Fix configurazione persa: file di configurazione unico e fisso (/home/nemo/.config/harbour/calibreweb.conf) indipendente dall'utente che avvia l'app (launcher nemo / debug SSH defaultuser), con migrazione @@ -46,12 +48,32 @@ in locale. %qmake5 make %{?_smp_mflags} +# Translation catalogue: generated explicitly with lrelease (the sailfishapp_i18n +# template does not produce the .qm reliably on the 5.1 kit). The .ts lives in +# the source tree; sfdk uses the sources live (shadow build), so locate it +# across the possible layouts. +if [ -f %{_builddir}/../%{name}-%{version}/translations/%{name}_it.ts ]; then + TS=%{_builddir}/../%{name}-%{version}/translations/%{name}_it.ts +elif [ -f %{_builddir}/%{name}-%{version}/translations/%{name}_it.ts ]; then + TS=%{_builddir}/%{name}-%{version}/translations/%{name}_it.ts +elif [ -f %{_builddir}/translations/%{name}_it.ts ]; then + TS=%{_builddir}/translations/%{name}_it.ts +else + echo "ERROR: %{name}_it.ts not found" >&2 + exit 1 +fi +lrelease "$TS" -qm %{_builddir}/%{name}_it.qm + %install make install INSTALL_ROOT=%{buildroot} mkdir -p %{buildroot}%{_datadir}/applications install -m 0644 %{SOURCE1} %{buildroot}%{_datadir}/applications/%{name}.desktop desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop || true +# Italian translation: installed from the spec, like the desktop file. +mkdir -p %{buildroot}/usr/share/translations +install -m 0644 %{_builddir}/%{name}_it.qm %{buildroot}/usr/share/translations/ + %files %defattr(-,root,root,-) %{_bindir}/%{name} @@ -59,3 +81,4 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop || tr %{_datadir}/icons/hicolor/86x86/apps/%{name}.png %{_datadir}/icons/hicolor/108x108/apps/%{name}.png %{_datadir}/%{name}/qml +/usr/share/translations/%{name}*.qm diff --git a/translations/harbour-calibreweb_it.ts b/translations/harbour-calibreweb_it.ts new file mode 100644 index 0000000..ad6e8d5 --- /dev/null +++ b/translations/harbour-calibreweb_it.ts @@ -0,0 +1,277 @@ + + + + BookDetailPage + + + Read (EPUB) + Leggi (EPUB) + + + + Formats + Formati + + + + Downloading… + Download in corso… + + + + Saved to + Salvato in + + + + Error: + Errore: + + + + ChapterListDialog + + + Table of contents + Indice capitoli + + + + No chapters + Nessun capitolo + + + + CoverPage + + + Calibre Web + Calibre Web + + + + FeedPage + + + Refresh + Aggiorna + + + + Settings + Impostazioni + + + + + No results + Nessun risultato + + + + MainPage + + + Calibre Web + Calibre Web + + + + Search + Cerca + + + + Settings + Impostazioni + + + + Refresh + Aggiorna + + + + Open the settings and enter your Calibre Web address + Apri le impostazioni e inserisci l'indirizzo del tuo Calibre Web + + + + Server not configured + Server non configurato + + + + No sections found in the OPDS feed + Nessuna sezione trovata nel feed OPDS + + + + MarginDialog + + + Text margins + Margini del testo + + + + Apply + Applica + + + + Side margins + Margini laterali + + + + Top and bottom + Alto e basso + + + + Changes apply immediately. Confirm to save them for all books. + Le modifiche si applicano subito al testo. Conferma per salvarle per tutti i libri. + + + + ReaderPage + + + Table of contents + Indice capitoli + + + + Text margins + Margini del testo + + + + Settings + Impostazioni + + + + Close book + Chiudi libro + + + + The reader is not responding (WebView). The EPUB file may be damaged. + Il lettore non risponde (WebView). Il file EPUB potrebbe essere danneggiato. + + + + Chapter unreadable + Capitolo non leggibile + + + + Unable to open the EPUB file + Impossibile aprire il libro EPUB + + + + SearchPage + + + + Search + Cerca + + + + Title or author… + Titolo o autore… + + + + Search uses the server engine (OPDS search). + La ricerca usa il motore del server (OPDS search). + + + + Results: + Risultati: + + + + SettingsPage + + + Settings + Impostazioni + + + + Server + Server + + + + Calibre Web address + Indirizzo Calibre Web + + + + User (empty = anonymous access) + Utente (vuoto = accesso anonimo) + + + + Password + Password + + + + Ignore SSL certificate errors + Ignora errori certificato SSL + + + + Enable if the server uses a self-signed certificate + Da attivare se il server usa un certificato autofirmato + + + + Reader + Lettore + + + + Side margins + Margini laterali + + + + Top and bottom margin + Margine alto e basso + + + + Connection + Connessione + + + + Test connection + Prova connessione + + + + Enter the server address + Inserisci l'indirizzo del server + + + + Testing… + Verifica in corso… + + + + Connection OK: %1 sections found + Connessione OK: %1 sezioni trovate + + + \ No newline at end of file