From 7cef6954ebf7121f8b281f3efe32f1d874930c00 Mon Sep 17 00:00:00 2001 From: Carlo Baratto Date: Thu, 8 Oct 2026 22:10:51 +0200 Subject: [PATCH] scheletro porting nativo Sailfish OS di Henflow: packaging, settings, pagine, icone, i18n --- README.md | 76 +++++++++++++++++++++++++++ harbour-henflow.pro | 45 ++++++++++++++++ icons/108x108/harbour-henflow.png | Bin 0 -> 1938 bytes icons/128x128/harbour-henflow.png | Bin 0 -> 2286 bytes icons/172x172/harbour-henflow.png | Bin 0 -> 2938 bytes icons/86x86/harbour-henflow.png | Bin 0 -> 1476 bytes icons/make_icons.py | 69 ++++++++++++++++++++++++ qml/cover/CoverPage.qml | 25 +++++++++ qml/harbour-henflow.qml | 12 +++++ qml/pages/MainPage.qml | 68 ++++++++++++++++++++++++ rpm/harbour-henflow.desktop | 20 +++++++ rpm/harbour-henflow.spec | 81 +++++++++++++++++++++++++++++ src/main.cpp | 61 ++++++++++++++++++++++ src/settings.cpp | 37 +++++++++++++ src/settings.h | 32 ++++++++++++ translations/harbour-henflow.ts | 74 ++++++++++++++++++++++++++ translations/harbour-henflow_it.ts | 74 ++++++++++++++++++++++++++ 17 files changed, 674 insertions(+) create mode 100644 README.md create mode 100644 harbour-henflow.pro create mode 100644 icons/108x108/harbour-henflow.png create mode 100644 icons/128x128/harbour-henflow.png create mode 100644 icons/172x172/harbour-henflow.png create mode 100644 icons/86x86/harbour-henflow.png create mode 100644 icons/make_icons.py create mode 100644 qml/cover/CoverPage.qml create mode 100644 qml/harbour-henflow.qml create mode 100644 qml/pages/MainPage.qml create mode 100644 rpm/harbour-henflow.desktop create mode 100644 rpm/harbour-henflow.spec create mode 100644 src/main.cpp create mode 100644 src/settings.cpp create mode 100644 src/settings.h create mode 100644 translations/harbour-henflow.ts create mode 100644 translations/harbour-henflow_it.ts diff --git a/README.md b/README.md new file mode 100644 index 0000000..513f572 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# harbour-henflow + +Porting **nativo Sailfish OS** dell'app Android *Henflow* (`it.carlobaratto.henflow`, +Gestione ordini uova, galline e consegne). UI in QML/Silica, logica e dati in C++, +pubblicazione prevista sullo **store Jolla Harbour**. + +Il porting **non** usa il runtime Flutter community (`flutter-sailfishos`): quello +resta una via OpenRepos, non Harbour-safe, e non supporta i plugin nativi Android +(AdMob/Firebase/Billing). Dati locali sul telefono: nessun account, nessun cloud. + +## Stato + +Guscio completo e pronto alla prima build (finestra, pagina principale, cover, +impostazioni con lingua, icone, catalogo traduzioni, spec RPM). Le schermate sono +segnaposto: vanno mappate 1:1 dai sorgenti Flutter. + +## Struttura + +``` +harbour-henflow.pro # QT += quick qml, INSTALLS icone +rpm/harbour-henflow.spec # lrelease + desktop cercati con find (layout sorgente variabile) +rpm/harbour-henflow.desktop # profilo [X-Sailjail] esplicito (dati persistenti) +src/main.cpp # SailfishApp, context property appSettings, lingua +src/settings.h/.cpp # QSettings su path esplicito AppConfigLocation + sync() +qml/harbour-henflow.qml # ApplicationWindow: initialPage + cover +qml/pages/MainPage.qml # segnaposto con i moduli previsti +qml/cover/CoverPage.qml +icons/make_icons.py # icone 86/108/128/172 (PIL) +translations/*.ts # stringhe sorgente INGLESI + catalogo italiano +``` + +## Build e deploy + +Sul PC con l'SDK Sailfish (qui non c'e' sfdk): + +```sh +sfdk target use SailfishOS-5.0.0.62-aarch64 # o il target del tuo device +sfdk build # RPM in build-*/RPMS/ +sfdk deploy # oppure Qt Creator +``` + +Tarball per lo store (con `--prefix`, esclude .git e i file non tracciati): + +```sh +git archive --format=tar.gz --prefix=harbour-henflow-0.1.0/ -o harbour-henflow-0.1.0.tar.gz HEAD +``` + +## Modello dati proposto (da confermare sui sorgenti Flutter) + +Un file JSON in `AppConfigLocation` (`~/.config/harbour/henflow/henflow.json`) +e' sufficiente: nessuna dipendenza extra e nessun driver SQL da verificare sul +device. SQLite resta l'alternativa se servono query piu' ricche. + +| entita' | campi | +|---|---| +| `hens` | id, nome, razza, data_nascita, uova_settimana (stima), attiva, note | +| `egg_log` | data, uova_raccolte (+ eventuale id gallina) | +| `customers` | id, nome, telefono, quantita_abituale, giorno_consegna, note | +| `orders` | id, id_cliente, quantita, data_ordine, data_consegna, stato, note | + +Derivati: **uova disponibili oggi** = produzione stimata/registrata meno gli ordini +con data di consegna odierna; **data consegna automatica** = primo giorno di +consegna del cliente successivo all'ordine. + +## Prossimi passi + +1. Copiare i sorgenti Flutter sul server (vedi sotto). +2. Mappare schermate e campi reali (non la descrizione dello store). +3. Implementare storage + schermate, verifica su device (192.168.2.15). +4. Asset store (icona, cover 1080x540), descrizioni EN, upload Harbour. + +```sh +# dal PC con i sorgenti Flutter (LAN o VPN) +rsync -av --exclude build --exclude .dart_tool --exclude .git \ + ~/percorso/henflow/ kaneda@192.168.3.21:/home/kaneda/workspace/henflow-flutter/ +``` diff --git a/harbour-henflow.pro b/harbour-henflow.pro new file mode 100644 index 0000000..3f94eb2 --- /dev/null +++ b/harbour-henflow.pro @@ -0,0 +1,45 @@ +TEMPLATE = app +TARGET = harbour-henflow + +CONFIG += sailfishapp +CONFIG += c++11 + +# Il sailfishapp.prf del kit 5.1 NON aggiunge da solo gli include QtQuick/QtQml +# (sintomo: "QQuickView: No such file or directory"). +QT += quick qml + +SOURCES += \ + src/main.cpp \ + src/settings.cpp + +HEADERS += \ + src/settings.h + +OTHER_FILES += \ + qml/harbour-henflow.qml \ + qml/pages/*.qml \ + qml/cover/*.qml \ + rpm/harbour-henflow.spec \ + rpm/harbour-henflow.desktop \ + translations/harbour-henflow.ts \ + translations/harbour-henflow_it.ts + +DISTFILES += $$OTHER_FILES + +# Le traduzioni NON passano dal template sailfishapp_i18n (sul kit 5.1 il .qm +# non viene generato/installato in modo affidabile): lo spec compila il catalogo +# con lrelease e lo installa nel datadir dell'app, main.cpp lo carica da li'. +# Le stringhe sorgente sono INGLESI (lingua di default di Sailfish). + +# Icone: struttura standard hicolor, path assoluti (gli install manuali con +# path relativi falliscono se il tar sorgente e' incompleto). +icons86.path = /usr/share/icons/hicolor/86x86/apps +icons86.files = $$PWD/icons/86x86/harbour-henflow.png +icons108.path = /usr/share/icons/hicolor/108x108/apps +icons108.files = $$PWD/icons/108x108/harbour-henflow.png +icons128.path = /usr/share/icons/hicolor/128x128/apps +icons128.files = $$PWD/icons/128x128/harbour-henflow.png +icons172.path = /usr/share/icons/hicolor/172x172/apps +icons172.files = $$PWD/icons/172x172/harbour-henflow.png + +INSTALLS += icons86 icons108 icons128 icons172 diff --git a/icons/108x108/harbour-henflow.png b/icons/108x108/harbour-henflow.png new file mode 100644 index 0000000000000000000000000000000000000000..dabae7ceb0885e53e2b39ae92104177fd28b5f73 GIT binary patch literal 1938 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 IM6N<$g0Ra%7XSbN literal 0 HcmV?d00001 diff --git a/icons/172x172/harbour-henflow.png b/icons/172x172/harbour-henflow.png new file mode 100644 index 0000000000000000000000000000000000000000..e74e1a8df7a4fc6c7efac56900717c19430c93bb GIT binary patch literal 2938 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 eIuQs2p5}k#3-piYTpAt#0000arancio bruciato con angoli molto arrotondati, + un uovo bianco con ombra morbida e una pagliuzza di grano. + Dimensioni: 86, 108, 128, 172 (struttura standard hicolor).""" +import os +from PIL import Image, ImageDraw + +C_TOP = (250, 214, 137) # #FAD689 ambrato chiaro +C_BOT = (196, 122, 41) # #C47A29 arancio bruciato +EGG = (255, 253, 246) +STRAW = (255, 236, 179) + + +def gradient(size, c1, c2): + img = Image.new("RGB", (size, size)) + d = ImageDraw.Draw(img) + for y in range(size): + t = y / (size - 1) + d.line([(0, y), (size, y)], + fill=(int(c1[0] + (c2[0] - c1[0]) * t), + int(c1[1] + (c2[1] - c1[1]) * t), + int(c1[2] + (c2[2] - c1[2]) * t))) + return img + + +def draw_icon(size): + m = size * 0.05 + r = size * 0.22 + out = Image.new("RGBA", (size, size), (0, 0, 0, 0)) + + grad = gradient(size, C_TOP, C_BOT).convert("RGBA") + mask = Image.new("L", (size, size), 0) + ImageDraw.Draw(mask).rounded_rectangle([m, m, size - m, size - m], + radius=r, fill=255) + out.paste(grad, (0, 0), mask) + + d = ImageDraw.Draw(out, "RGBA") + + # pagliuzza: due archi chiari in basso, suggeriscono il nido + lw = max(2, int(size * 0.03)) + for k, off in ((0.0, 0.0), (0.06, 0.03)): + d.arc([size * (0.16 + k), size * (0.62 + off), + size * (0.84 - k), size * (1.02 + off)], + start=200, end=340, fill=STRAW + (110,), width=lw) + + # uovo bianco, leggermente spostato in alto, con ombra morbida + ex0, ey0 = size * 0.30, size * 0.22 + ex1, ey1 = size * 0.70, size * 0.70 + d.ellipse([ex0 + size * 0.015, ey0 + size * 0.02, + ex1 + size * 0.015, ey1 + size * 0.02], + fill=(90, 50, 10, 70)) + d.ellipse([ex0, ey0, ex1, ey1], fill=EGG + (255,)) + + # riflesso + d.ellipse([size * 0.35, size * 0.30, size * 0.45, size * 0.40], + fill=(255, 255, 255, 120)) + return out + + +def main(): + for s in (86, 108, 128, 172): + os.makedirs(f"icons/{s}x{s}", exist_ok=True) + draw_icon(s).save(f"icons/{s}x{s}/harbour-henflow.png") + print("icone scritte: 86, 108, 128, 172") + + +if __name__ == "__main__": + main() diff --git a/qml/cover/CoverPage.qml b/qml/cover/CoverPage.qml new file mode 100644 index 0000000..01f3f14 --- /dev/null +++ b/qml/cover/CoverPage.qml @@ -0,0 +1,25 @@ +import QtQuick 2.2 +import Sailfish.Silica 1.0 + +CoverBackground { + Label { + id: title + anchors { + top: parent.top + topMargin: Theme.paddingLarge + horizontalCenter: parent.horizontalCenter + } + text: qsTr("Henflow") + color: Theme.primaryColor + } + + Label { + anchors.centerIn: parent + width: parent.width - 2 * Theme.paddingLarge + text: qsTr("Eggs, hens and orders") + font.pixelSize: Theme.fontSizeSmall + color: Theme.secondaryColor + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } +} diff --git a/qml/harbour-henflow.qml b/qml/harbour-henflow.qml new file mode 100644 index 0000000..81a8bb8 --- /dev/null +++ b/qml/harbour-henflow.qml @@ -0,0 +1,12 @@ +import QtQuick 2.2 +import Sailfish.Silica 1.0 +import "pages" +import "cover" + +ApplicationWindow +{ + id: app + + initialPage: Component { MainPage { } } + cover: Component { CoverPage { } } +} diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml new file mode 100644 index 0000000..c0bcd73 --- /dev/null +++ b/qml/pages/MainPage.qml @@ -0,0 +1,68 @@ +import QtQuick 2.2 +import Sailfish.Silica 1.0 + +Page { + id: page + allowedOrientations: Orientation.All + + SilicaListView { + id: listView + anchors.fill: parent + + header: PageHeader { + title: qsTr("Henflow") + } + + model: ListModel { + id: sections + // Moduli previsti dall'app Android, da mappare sulle schermate + // Flutter quando i sorgenti arrivano sul server. + Component.onCompleted: { + append({ "name": qsTr("Hens"), "note": qsTr("name, breed, hatch date, estimated production") }) + append({ "name": qsTr("Available eggs"), "note": qsTr("eggs ready today") }) + append({ "name": qsTr("Orders"), "note": qsTr("customer, quantity, automatic delivery date") }) + append({ "name": qsTr("Calendar"), "note": qsTr("orders and pickups") }) + append({ "name": qsTr("Customers"), "note": qsTr("regular buyers") }) + append({ "name": qsTr("Dashboard"), "note": qsTr("summary of the day") }) + } + } + + delegate: ListItem { + id: item + contentHeight: Theme.itemSizeMedium + + Column { + anchors.verticalCenter: parent.verticalCenter + x: Theme.horizontalPageMargin + width: parent.width - 2 * Theme.horizontalPageMargin + + Label { + text: model.name + color: item.highlighted ? Theme.highlightColor : Theme.primaryColor + truncationMode: TruncationMode.Fade + width: parent.width + } + + Label { + text: model.note + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.secondaryColor + truncationMode: TruncationMode.Fade + width: parent.width + } + } + } + + footer: Label { + x: Theme.horizontalPageMargin + width: parent.width - 2 * Theme.horizontalPageMargin + text: qsTr("Native port in progress") + font.pixelSize: Theme.fontSizeExtraSmall + color: Theme.secondaryHighlightColor + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + } + + VerticalScrollDecorator {} + } +} diff --git a/rpm/harbour-henflow.desktop b/rpm/harbour-henflow.desktop new file mode 100644 index 0000000..76f7d71 --- /dev/null +++ b/rpm/harbour-henflow.desktop @@ -0,0 +1,20 @@ +[Desktop Entry] +Name=Henflow +Name[it_IT]=Henflow +Comment=Manage hens, eggs and orders +Comment[it_IT]=Gestisci galline, uova e ordini +Exec=harbour-henflow +Icon=harbour-henflow +Type=Application +X-Nemo-Application-Type=silica-qt5 +Categories=Utility; + +# Profilo SailJail esplicito: senza X-Sailjail la sandbox di Sailfish 5.x usa il +# profilo default, che NASCONDE ~/.config/harbour -> impostazioni e dati non +# persistenti (sintomo: "salva via SSH ma non dal launcher"). +# Org/App dichiarati QUI (li legge la sandbox) e nel main.cpp (li legge +# QStandardPaths): AppConfigLocation = ~/.config/harbour/henflow. +# Nessuna permission: l'app e' completamente locale (nessuna rete). +[X-Sailjail] +OrganizationName=harbour +ApplicationName=henflow diff --git a/rpm/harbour-henflow.spec b/rpm/harbour-henflow.spec new file mode 100644 index 0000000..0050666 --- /dev/null +++ b/rpm/harbour-henflow.spec @@ -0,0 +1,81 @@ +Name: harbour-henflow +Summary: Manage hens, eggs and orders +Version: 0.1.0 +Release: 1 +Group: Qt/Qt +License: MIT +URL: https://git.hackatoniclife.com/kaneda/harbour-henflow +Source0: %{name}-%{version}.tar.gz +Source1: %{name}.desktop + +Requires: sailfishsilica-qt5 >= 0.10.9 +BuildRequires: pkgconfig(sailfishapp) >= 1.0.2 +BuildRequires: pkgconfig(Qt5Core) +BuildRequires: pkgconfig(Qt5Qml) +BuildRequires: pkgconfig(Qt5Quick) +BuildRequires: qt5-qttools-linguist +BuildRequires: desktop-file-utils + +%global debug_package %{nil} + +%description +Manage hens, egg production and customer orders locally on the phone. +Chicken registry (name, breed, hatch date), daily egg estimates, +available eggs today, quick order entry with automatic delivery date, +pickup calendar, regular customers and a simple dashboard. +No account, no cloud: all data stays on the device. + +%changelog +* Thu Oct 08 2026 Carlo Baratto - 0.1.0-1 +- Shell del porting nativo Sailfish OS: finestra, pagina principale, + cover, impostazioni (lingua) e pipeline RPM complete + +%prep +%setup -q -n %{name}-%{version} + +%build +%qmake5 +make %{?_smp_mflags} + +# Catalogo di traduzione generato esplicitamente con lrelease (il template +# sailfishapp_i18n non produce il .qm in modo affidabile sul kit 5.1). +# Il .ts viene cercato in modo robusto: sfdk usa i sorgenti live (shadow build) +# e la cartella sorgente puo' chiamarsi henflow-0.1.0 (tarball), harbour-henflow +# (clone) o harbour-henflow-main (zip di Gitea). +TS=$(find %{_builddir}/.. -maxdepth 4 -name '%{name}_it.ts' 2>/dev/null | head -1) +if [ -z "$TS" ]; then + 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 + +# Cartella sorgente con nome variabile: cerca il desktop invece di assumere +# un path fisso; la sorgente dichiarata nello spec resta il fallback. +DESKTOP=$(find %{_builddir}/.. -maxdepth 4 -name '%{name}.desktop' 2>/dev/null | head -1) +if [ -z "$DESKTOP" ] && [ -f %{SOURCE1} ]; then DESKTOP=%{SOURCE1}; fi +if [ -z "$DESKTOP" ]; then + echo "ERROR: %{name}.desktop not found" >&2 + exit 1 +fi +install -m 0644 "$DESKTOP" %{buildroot}%{_datadir}/applications/%{name}.desktop +desktop-file-validate %{buildroot}%{_datadir}/applications/%{name}.desktop || true + +# Traduzione italiana nel datadir dell'app (il validatore RPM per Harbour +# rifiuta la cartella di sistema delle traduzioni); main.cpp la carica da qui. +mkdir -p %{buildroot}%{_datadir}/%{name}/translations +install -m 0644 %{_builddir}/%{name}_it.qm %{buildroot}%{_datadir}/%{name}/translations/ + +%files +%defattr(-,root,root,-) +%{_bindir}/%{name} +%{_datadir}/applications/%{name}.desktop +%{_datadir}/icons/hicolor/86x86/apps/%{name}.png +%{_datadir}/icons/hicolor/108x108/apps/%{name}.png +%{_datadir}/icons/hicolor/128x128/apps/%{name}.png +%{_datadir}/icons/hicolor/172x172/apps/%{name}.png +%{_datadir}/%{name}/qml +%{_datadir}/%{name}/translations/%{name}*.qm diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..2511e04 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "settings.h" + +Q_DECL_EXPORT int main(int argc, char *argv[]) +{ + QGuiApplication *app = SailfishApp::application(argc, argv); + + // Identita' allineata al profilo X-Sailjail del desktop file: + // AppConfigLocation = ~/.config/harbour/henflow (zona persistente). + app->setOrganizationName(QStringLiteral("harbour")); + app->setApplicationName(QStringLiteral("henflow")); + app->setApplicationVersion(QStringLiteral("0.1.0")); + + Settings settings; + + // Lingua scelta dall'utente: "system" segue Sailfish, "en" e' la lingua + // delle stringhe sorgente, "it" carica il catalogo dal datadir dell'app. + QString lang = settings.language(); + if (lang == QLatin1String("system")) { + const QString sys = QLocale::system().name(); + lang = sys.startsWith(QLatin1String("it")) ? QStringLiteral("it") + : QStringLiteral("en"); + } + if (lang == QLatin1String("it")) { + const QList trs = app->findChildren(); + foreach (QTranslator *t, trs) { + app->removeTranslator(t); + t->deleteLater(); + } + QTranslator *translator = new QTranslator(app); + if (translator->load(QStringLiteral("harbour-henflow_it"), + QStringLiteral("/usr/share/harbour-henflow/translations"))) { + app->installTranslator(translator); + } else { + qWarning("harbour-henflow: cannot load harbour-henflow_it.qm"); + } + } + + QQuickView *view = SailfishApp::createView(); + + qDebug() << "harbour-henflow v0.1.0 build" << __DATE__ << __TIME__; + + view->rootContext()->setContextProperty(QStringLiteral("appSettings"), &settings); + view->rootContext()->setContextProperty(QStringLiteral("appVersion"), + QCoreApplication::applicationVersion()); + + // pathTo: un QUrl relativo si risolve contro la CWD, che dal launcher non e' + // la cartella dell'app -> QML non caricato e prima schermata BIANCA. + view->setSource(SailfishApp::pathTo(QStringLiteral("qml/harbour-henflow.qml"))); + view->show(); + + return app->exec(); +} diff --git a/src/settings.cpp b/src/settings.cpp new file mode 100644 index 0000000..44cb017 --- /dev/null +++ b/src/settings.cpp @@ -0,0 +1,37 @@ +#include "settings.h" + +#include +#include + +Settings::Settings(QObject *parent) + : QObject(parent) + , m_settings(configPath(), QSettings::IniFormat) +{ +} + +QString Settings::configPath() +{ + // AppConfigLocation dipende da organizationName/applicationName impostati + // nel main.cpp: ~/.config/harbour/henflow (zona persistente della sandbox). + const QString dir = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation); + QDir().mkpath(dir); + return dir + QStringLiteral("/henflow.conf"); +} + +QString Settings::language() const +{ + return m_settings.value(QStringLiteral("ui/language"), + QStringLiteral("system")).toString(); +} + +void Settings::setLanguage(const QString &language) +{ + if (language == this->language()) + return; + + m_settings.setValue(QStringLiteral("ui/language"), language); + // sync() esplicito: su Sailfish l'app puo' chiudersi bruscamente e il flush + // del distruttore non gira -> le scritture non sincronizzate vanno perse. + m_settings.sync(); + emit languageChanged(); +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 0000000..4c20c74 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,32 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + +#include +#include +#include + +// Wrapper QSettings esposto a QML come context property "appSettings". +// NB: si usa un PATH ESPLICITO su AppConfigLocation, non il costruttore +// QSettings(org, app): con la sandbox SailJail il costruttore da solo non +// persiste le modifiche fatte dal launcher. +class Settings : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged) + +public: + explicit Settings(QObject *parent = nullptr); + + QString language() const; + void setLanguage(const QString &language); + +signals: + void languageChanged(); + +private: + static QString configPath(); + + QSettings m_settings; +}; + +#endif // SETTINGS_H diff --git a/translations/harbour-henflow.ts b/translations/harbour-henflow.ts new file mode 100644 index 0000000..8c38603 --- /dev/null +++ b/translations/harbour-henflow.ts @@ -0,0 +1,74 @@ + + + + + CoverPage + + Henflow + + + + Eggs, hens and orders + + + + + MainPage + + Henflow + + + + Hens + + + + name, breed, hatch date, estimated production + + + + Available eggs + + + + eggs ready today + + + + Orders + + + + customer, quantity, automatic delivery date + + + + Calendar + + + + orders and pickups + + + + Customers + + + + regular buyers + + + + Dashboard + + + + summary of the day + + + + Native port in progress + + + + diff --git a/translations/harbour-henflow_it.ts b/translations/harbour-henflow_it.ts new file mode 100644 index 0000000..a120e09 --- /dev/null +++ b/translations/harbour-henflow_it.ts @@ -0,0 +1,74 @@ + + + + + CoverPage + + Henflow + Henflow + + + Eggs, hens and orders + Uova, galline e ordini + + + + MainPage + + Henflow + Henflow + + + Hens + Galline + + + name, breed, hatch date, estimated production + nome, razza, data di nascita, produzione stimata + + + Available eggs + Uova disponibili + + + eggs ready today + uova pronte oggi + + + Orders + Ordini + + + customer, quantity, automatic delivery date + cliente, quantità, data di consegna automatica + + + Calendar + Calendario + + + orders and pickups + ordini e ritiri + + + Customers + Clienti + + + regular buyers + acquirenti abituali + + + Dashboard + Dashboard + + + summary of the day + riepilogo della giornata + + + Native port in progress + Porting nativo in corso + + +