From f844d7c4f6043b788249329ab46d68f2ddf8b2a3 Mon Sep 17 00:00:00 2001 From: vjrj Date: Wed, 15 Jul 2026 19:12:16 +0200 Subject: [PATCH] feat(links): surface source repo + Weblate links on site and in app MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - site: set sourceURL (git.comunes.org/comunes/tane) and weblateURL (translate.comunes.org/projects/tane) — activates footer + collaborate links - app About screen: add 'Source code' and 'Help translate' link tiles - i18n: add about.sourceCode / about.translate / about.translateSubtitle (en base + es/pt/fr/de/ast; ja falls back to base), regenerate slang - docs: add TRANSLATIONS.md runbook for the Weblate app component + git token + slang-regeneration workflow --- TRANSLATIONS.md | 87 ++++++++++++++++++++++ apps/app_seeds/lib/i18n/ast.i18n.json | 3 + apps/app_seeds/lib/i18n/de.i18n.json | 3 + apps/app_seeds/lib/i18n/en.i18n.json | 3 + apps/app_seeds/lib/i18n/es.i18n.json | 3 + apps/app_seeds/lib/i18n/fr.i18n.json | 3 + apps/app_seeds/lib/i18n/pt.i18n.json | 3 + apps/app_seeds/lib/i18n/strings.g.dart | 4 +- apps/app_seeds/lib/i18n/strings_ast.g.dart | 10 ++- apps/app_seeds/lib/i18n/strings_de.g.dart | 10 ++- apps/app_seeds/lib/i18n/strings_en.g.dart | 16 +++- apps/app_seeds/lib/i18n/strings_es.g.dart | 10 ++- apps/app_seeds/lib/i18n/strings_fr.g.dart | 10 ++- apps/app_seeds/lib/i18n/strings_pt.g.dart | 10 ++- apps/app_seeds/lib/ui/about_screen.dart | 24 ++++++ site/config.toml | 4 +- 16 files changed, 187 insertions(+), 16 deletions(-) create mode 100644 TRANSLATIONS.md diff --git a/TRANSLATIONS.md b/TRANSLATIONS.md new file mode 100644 index 0000000..ca888f9 --- /dev/null +++ b/TRANSLATIONS.md @@ -0,0 +1,87 @@ +# Translating Tane (Weblate) + +Runbook for the translation setup. Written so another agent (or a human) can +reproduce it without prior context. + +Tane is translated on **[translate.comunes.org/projects/tane](https://translate.comunes.org/projects/tane/)** +(a self-hosted **Weblate 5.x**, docker-compose at `/data/weblate` on host **tesla**). +The links to the repo and to Weblate are shown both on the landing site +(`site/config.toml` → `sourceURL`, `weblateURL`) and inside the app (About screen). + +## What is translatable + +| Surface | Files | Format | Base locale | Locales today | +|---|---|---|---|---| +| **App** (`app` component) | `apps/app_seeds/lib/i18n/*.i18n.json` | JSON **nested** (slang, `{param}` placeholders) | `en` | en, es, pt, fr, de, ast, ja | +| **Site** (deferred) | `site/i18n/*.toml` | Hugo TOML | `en` | en, es | + +Only source strings live in git; app strings use `slang`, so `strings.g.dart` / +`strings_*.g.dart` are **generated** (see the slang caveat below). + +## Git connection + +- Repo: `https://git.comunes.org/comunes/tane.git`, branch **`main`** (private + Gitea/Forgejo behind Cloudflare). +- Weblate must use **HTTPS + an access token** — SSH port 22 is not reachable + through Cloudflare, so the stored `Comunes Translations` SSH key is unusable here. +- Repository URL in Weblate: + `https://:@git.comunes.org/comunes/tane.git` + where `` is a git.comunes.org access token with **read + write** on + `comunes/tane` (Weblate pushes translations back). Generate it in Gitea/Forgejo + → Settings → Applications. + +## The `app` component (create once) + +The `tane` project already exists on Weblate. Add a component (admin UI +*Add new translation component*, or `docker exec weblate-weblate-1 weblate shell`): + +| Field | Value | +|---|---| +| Project | `tane` | +| Name / slug | `app` | +| Source code repository | `https://:@git.comunes.org/comunes/tane.git` | +| Repository branch | `main` | +| File mask | `apps/app_seeds/lib/i18n/*.i18n.json` | +| Monolingual base language file | `apps/app_seeds/lib/i18n/en.i18n.json` | +| Template for new translations | `apps/app_seeds/lib/i18n/en.i18n.json` | +| File format | **JSON nested structure** (`json-nested`) — not flat `json` | +| Source language | English (`en`) | + +Weblate auto-discovers the existing locales from the mask. Leave push-on-commit on +so translations flow back to `main`. + +Sanity check after creating it: +```sh +docker exec weblate-weblate-1 weblate shell -c \ + 'from weblate.trans.models import Project; \ + print(Project.objects.get(slug="tane").component_set.count())' # expect 1 +``` +Then edit a test string in the UI and confirm a commit lands on +`git.comunes.org/comunes/tane` (`main`) — that validates the token has write. + +## slang regeneration caveat (important) + +Weblate only edits the `*.i18n.json` sources. The committed `strings.g.dart` / +`strings_*.g.dart` are generated and go **stale** on every Weblate commit, and +there is no CI to regenerate them. Before a release, a maintainer must: + +```sh +git pull +cd apps/app_seeds && dart run slang # regenerates strings*.g.dart +cd ../.. && dart analyze # workspace gate +git add -A && git commit -m "chore(i18n): regenerate slang after Weblate sync" +``` + +(Adding a new source string manually? Same steps — edit `en.i18n.json` first, then +regenerate. `fallback_strategy: base_locale` means locales missing a key show the +English text until translators fill it in.) + +## Site component — deferred + +Weblate 5.x has no native Hugo-TOML format, and the site has only EN/ES (~3 KB). +Two options, decide later: +- (a) Switch Hugo i18n to a Weblate-supported format (Hugo also reads + `i18n/*.json` / `*.yaml`), then add a matching `site` component. +- (b) Keep translating the two `site/i18n/*.toml` files by hand. + +For now the site is translated manually; only the `app` component is on Weblate. diff --git a/apps/app_seeds/lib/i18n/ast.i18n.json b/apps/app_seeds/lib/i18n/ast.i18n.json index 0b81ab7..80d39a1 100644 --- a/apps/app_seeds/lib/i18n/ast.i18n.json +++ b/apps/app_seeds/lib/i18n/ast.i18n.json @@ -146,6 +146,9 @@ "license": "Llicencia", "licenseValue": "AGPL-3.0", "website": "Sitiu web", + "sourceCode": "Códigu fonte", + "translate": "Ayuda a traducir", + "translateSubtitle": "Ayuda a traer Tane a la to llingua", "openSourceLicenses": "Llicencies de códigu abiertu", "openSourceLicensesSubtitle": "Biblioteques de terceros y les sos llicencies", "copyright": "© {years} Asociación Comunes, baxo AGPLv3" diff --git a/apps/app_seeds/lib/i18n/de.i18n.json b/apps/app_seeds/lib/i18n/de.i18n.json index 2a8ac83..444b08b 100644 --- a/apps/app_seeds/lib/i18n/de.i18n.json +++ b/apps/app_seeds/lib/i18n/de.i18n.json @@ -147,6 +147,9 @@ "license": "Lizenz", "licenseValue": "AGPL-3.0", "website": "Webseite", + "sourceCode": "Quellcode", + "translate": "Beim Übersetzen helfen", + "translateSubtitle": "Hilf, Tane in deine Sprache zu bringen", "openSourceLicenses": "Open-Source-Lizenzen", "openSourceLicensesSubtitle": "Bibliotheken von Drittanbietern und ihre Lizenzen", "copyright": "© {years} Comunes Association, unter AGPLv3" diff --git a/apps/app_seeds/lib/i18n/en.i18n.json b/apps/app_seeds/lib/i18n/en.i18n.json index 6c25692..97d0ccc 100644 --- a/apps/app_seeds/lib/i18n/en.i18n.json +++ b/apps/app_seeds/lib/i18n/en.i18n.json @@ -147,6 +147,9 @@ "license": "License", "licenseValue": "AGPL-3.0", "website": "Website", + "sourceCode": "Source code", + "translate": "Help translate", + "translateSubtitle": "Help bring Tane to your language", "openSourceLicenses": "Open-source licenses", "openSourceLicensesSubtitle": "Third-party libraries and their licenses", "copyright": "© {years} Comunes Association, under AGPLv3" diff --git a/apps/app_seeds/lib/i18n/es.i18n.json b/apps/app_seeds/lib/i18n/es.i18n.json index 53260c5..de9f4ff 100644 --- a/apps/app_seeds/lib/i18n/es.i18n.json +++ b/apps/app_seeds/lib/i18n/es.i18n.json @@ -146,6 +146,9 @@ "license": "Licencia", "licenseValue": "AGPL-3.0", "website": "Sitio web", + "sourceCode": "Código fuente", + "translate": "Ayuda a traducir", + "translateSubtitle": "Ayuda a traer Tane a tu idioma", "openSourceLicenses": "Licencias de código abierto", "openSourceLicensesSubtitle": "Bibliotecas de terceros y sus licencias", "copyright": "© {years} Asociación Comunes, bajo AGPLv3" diff --git a/apps/app_seeds/lib/i18n/fr.i18n.json b/apps/app_seeds/lib/i18n/fr.i18n.json index ca21157..a90758a 100644 --- a/apps/app_seeds/lib/i18n/fr.i18n.json +++ b/apps/app_seeds/lib/i18n/fr.i18n.json @@ -147,6 +147,9 @@ "license": "Licence", "licenseValue": "AGPL-3.0", "website": "Site web", + "sourceCode": "Code source", + "translate": "Aider à traduire", + "translateSubtitle": "Aidez à traduire Tane dans votre langue", "openSourceLicenses": "Licences open source", "openSourceLicensesSubtitle": "Bibliothèques tiers et leurs licences", "copyright": "© {years} Association Comunes, sous AGPLv3" diff --git a/apps/app_seeds/lib/i18n/pt.i18n.json b/apps/app_seeds/lib/i18n/pt.i18n.json index 4d9146f..5d248ee 100644 --- a/apps/app_seeds/lib/i18n/pt.i18n.json +++ b/apps/app_seeds/lib/i18n/pt.i18n.json @@ -147,6 +147,9 @@ "license": "Licença", "licenseValue": "AGPL-3.0", "website": "Sítio web", + "sourceCode": "Código-fonte", + "translate": "Ajuda a traduzir", + "translateSubtitle": "Ajuda a trazer o Tane para o teu idioma", "openSourceLicenses": "Licenças de código aberto", "openSourceLicensesSubtitle": "Bibliotecas de terceiros e as suas licenças", "copyright": "© {years} Associação Comunes, sob AGPLv3" diff --git a/apps/app_seeds/lib/i18n/strings.g.dart b/apps/app_seeds/lib/i18n/strings.g.dart index 77bc0c6..a0f7c8e 100644 --- a/apps/app_seeds/lib/i18n/strings.g.dart +++ b/apps/app_seeds/lib/i18n/strings.g.dart @@ -4,9 +4,9 @@ /// To regenerate, run: `dart run slang` /// /// Locales: 7 -/// Strings: 3454 (493 per locale) +/// Strings: 3472 (496 per locale) /// -/// Built on 2026-07-15 at 13:17 UTC +/// Built on 2026-07-15 at 17:09 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import diff --git a/apps/app_seeds/lib/i18n/strings_ast.g.dart b/apps/app_seeds/lib/i18n/strings_ast.g.dart index 1017383..e53dba8 100644 --- a/apps/app_seeds/lib/i18n/strings_ast.g.dart +++ b/apps/app_seeds/lib/i18n/strings_ast.g.dart @@ -328,6 +328,9 @@ class _Translations$about$ast extends Translations$about$en { @override String get license => 'Llicencia'; @override String get licenseValue => 'AGPL-3.0'; @override String get website => 'Sitiu web'; + @override String get sourceCode => 'Códigu fonte'; + @override String get translate => 'Ayuda a traducir'; + @override String get translateSubtitle => 'Ayuda a traer Tane a la to llingua'; @override String get openSourceLicenses => 'Llicencies de códigu abiertu'; @override String get openSourceLicensesSubtitle => 'Biblioteques de terceros y les sos llicencies'; @override String copyright({required Object years}) => '© ${years} Asociación Comunes, baxo AGPLv3'; @@ -1536,6 +1539,9 @@ extension on TranslationsAst { 'about.license' => 'Llicencia', 'about.licenseValue' => 'AGPL-3.0', 'about.website' => 'Sitiu web', + 'about.sourceCode' => 'Códigu fonte', + 'about.translate' => 'Ayuda a traducir', + 'about.translateSubtitle' => 'Ayuda a traer Tane a la to llingua', 'about.openSourceLicenses' => 'Llicencies de códigu abiertu', 'about.openSourceLicensesSubtitle' => 'Biblioteques de terceros y les sos llicencies', 'about.copyright' => ({required Object years}) => '© ${years} Asociación Comunes, baxo AGPLv3', @@ -1923,11 +1929,11 @@ extension on TranslationsAst { 'handover.promiseReceived' => 'Voi devolver semiente', 'sale.title' => 'Ventes', 'sale.help' => 'Rexistra semilla vendida o mercada — dineru, Ğ1 o cualquier moneda. Un modelu aparte del regalu y del Plantare. Enxamás se cobra comisión poles semilles.', + _ => null, + } ?? switch (path) { 'sale.add' => 'Rexistrar venta', 'sale.empty' => 'Entá nun hai ventes. Anota equí lo que vendes o merques.', 'sale.iSold' => 'Vendí', - _ => null, - } ?? switch (path) { 'sale.iBought' => 'Mercué', 'sale.direction' => '¿Vendes o merques?', 'sale.counterparty' => '¿Con quién?', diff --git a/apps/app_seeds/lib/i18n/strings_de.g.dart b/apps/app_seeds/lib/i18n/strings_de.g.dart index 829b964..460891b 100644 --- a/apps/app_seeds/lib/i18n/strings_de.g.dart +++ b/apps/app_seeds/lib/i18n/strings_de.g.dart @@ -329,6 +329,9 @@ class _Translations$about$de extends Translations$about$en { @override String get license => 'Lizenz'; @override String get licenseValue => 'AGPL-3.0'; @override String get website => 'Webseite'; + @override String get sourceCode => 'Quellcode'; + @override String get translate => 'Beim Übersetzen helfen'; + @override String get translateSubtitle => 'Hilf, Tane in deine Sprache zu bringen'; @override String get openSourceLicenses => 'Open-Source-Lizenzen'; @override String get openSourceLicensesSubtitle => 'Bibliotheken von Drittanbietern und ihre Lizenzen'; @override String copyright({required Object years}) => '© ${years} Comunes Association, unter AGPLv3'; @@ -1533,6 +1536,9 @@ extension on TranslationsDe { 'about.license' => 'Lizenz', 'about.licenseValue' => 'AGPL-3.0', 'about.website' => 'Webseite', + 'about.sourceCode' => 'Quellcode', + 'about.translate' => 'Beim Übersetzen helfen', + 'about.translateSubtitle' => 'Hilf, Tane in deine Sprache zu bringen', 'about.openSourceLicenses' => 'Open-Source-Lizenzen', 'about.openSourceLicensesSubtitle' => 'Bibliotheken von Drittanbietern und ihre Lizenzen', 'about.copyright' => ({required Object years}) => '© ${years} Comunes Association, unter AGPLv3', @@ -1919,11 +1925,11 @@ extension on TranslationsDe { 'sale.empty' => 'Noch keine Verkäufe. Notiere hier, was du verkaufst oder kaufst.', 'sale.iSold' => 'Ich verkaufte', 'sale.iBought' => 'Ich kaufte', + _ => null, + } ?? switch (path) { 'sale.direction' => 'Verkauft oder gekauft?', 'sale.counterparty' => 'Mit wem?', 'sale.counterpartyHint' => 'Eine Person oder ein Kollektiv (optional)', - _ => null, - } ?? switch (path) { 'sale.amount' => 'Betrag', 'sale.currency' => 'Währung', 'sale.currencyHint' => '€, Ğ1, Stunden… (optional)', diff --git a/apps/app_seeds/lib/i18n/strings_en.g.dart b/apps/app_seeds/lib/i18n/strings_en.g.dart index ed46930..725c1a4 100644 --- a/apps/app_seeds/lib/i18n/strings_en.g.dart +++ b/apps/app_seeds/lib/i18n/strings_en.g.dart @@ -577,6 +577,15 @@ class Translations$about$en { /// en: 'Website' String get website => 'Website'; + /// en: 'Source code' + String get sourceCode => 'Source code'; + + /// en: 'Help translate' + String get translate => 'Help translate'; + + /// en: 'Help bring Tane to your language' + String get translateSubtitle => 'Help bring Tane to your language'; + /// en: 'Open-source licenses' String get openSourceLicenses => 'Open-source licenses'; @@ -2721,6 +2730,9 @@ extension on Translations { 'about.license' => 'License', 'about.licenseValue' => 'AGPL-3.0', 'about.website' => 'Website', + 'about.sourceCode' => 'Source code', + 'about.translate' => 'Help translate', + 'about.translateSubtitle' => 'Help bring Tane to your language', 'about.openSourceLicenses' => 'Open-source licenses', 'about.openSourceLicensesSubtitle' => 'Third-party libraries and their licenses', 'about.copyright' => ({required Object years}) => '© ${years} Comunes Association, under AGPLv3', @@ -3107,11 +3119,11 @@ extension on Translations { 'plantare.returnSimilar' => 'A similar amount of seed', 'plantare.returnSimilarNote' => 'open-pollinated · non-GMO · organically grown', 'plantare.returnWork' => 'Some hours of work', + _ => null, + } ?? switch (path) { 'plantare.returnOther' => 'Something else', 'plantare.workHoursLabel' => 'How many hours?', 'plantare.proposalsSection' => 'Waiting for your reply', - _ => null, - } ?? switch (path) { 'plantare.incomingFrom' => ({required Object name}) => '${name} proposes a Plantaré', 'plantare.accept' => 'Accept & sign', 'plantare.declineAction' => 'Decline', diff --git a/apps/app_seeds/lib/i18n/strings_es.g.dart b/apps/app_seeds/lib/i18n/strings_es.g.dart index 1c3dfcf..f3a5c8a 100644 --- a/apps/app_seeds/lib/i18n/strings_es.g.dart +++ b/apps/app_seeds/lib/i18n/strings_es.g.dart @@ -328,6 +328,9 @@ class _Translations$about$es extends Translations$about$en { @override String get license => 'Licencia'; @override String get licenseValue => 'AGPL-3.0'; @override String get website => 'Sitio web'; + @override String get sourceCode => 'Código fuente'; + @override String get translate => 'Ayuda a traducir'; + @override String get translateSubtitle => 'Ayuda a traer Tane a tu idioma'; @override String get openSourceLicenses => 'Licencias de código abierto'; @override String get openSourceLicensesSubtitle => 'Bibliotecas de terceros y sus licencias'; @override String copyright({required Object years}) => '© ${years} Asociación Comunes, bajo AGPLv3'; @@ -1561,6 +1564,9 @@ extension on TranslationsEs { 'about.license' => 'Licencia', 'about.licenseValue' => 'AGPL-3.0', 'about.website' => 'Sitio web', + 'about.sourceCode' => 'Código fuente', + 'about.translate' => 'Ayuda a traducir', + 'about.translateSubtitle' => 'Ayuda a traer Tane a tu idioma', 'about.openSourceLicenses' => 'Licencias de código abierto', 'about.openSourceLicensesSubtitle' => 'Bibliotecas de terceros y sus licencias', 'about.copyright' => ({required Object years}) => '© ${years} Asociación Comunes, bajo AGPLv3', @@ -1948,11 +1954,11 @@ extension on TranslationsEs { 'plantare.returnSimilarNote' => 'polinización abierta · no transgénica · cultivada en ecológico', 'plantare.returnWork' => 'Unas horas de trabajo', 'plantare.returnOther' => 'Otra cosa', + _ => null, + } ?? switch (path) { 'plantare.workHoursLabel' => '¿Cuántas horas?', 'plantare.proposalsSection' => 'Esperando tu respuesta', 'plantare.incomingFrom' => ({required Object name}) => '${name} te propone un Plantaré', - _ => null, - } ?? switch (path) { 'plantare.accept' => 'Aceptar y firmar', 'plantare.declineAction' => 'Rechazar', 'plantare.declineReasonHint' => 'Motivo (opcional)', diff --git a/apps/app_seeds/lib/i18n/strings_fr.g.dart b/apps/app_seeds/lib/i18n/strings_fr.g.dart index a48c861..f28d9cc 100644 --- a/apps/app_seeds/lib/i18n/strings_fr.g.dart +++ b/apps/app_seeds/lib/i18n/strings_fr.g.dart @@ -329,6 +329,9 @@ class _Translations$about$fr extends Translations$about$en { @override String get license => 'Licence'; @override String get licenseValue => 'AGPL-3.0'; @override String get website => 'Site web'; + @override String get sourceCode => 'Code source'; + @override String get translate => 'Aider à traduire'; + @override String get translateSubtitle => 'Aidez à traduire Tane dans votre langue'; @override String get openSourceLicenses => 'Licences open source'; @override String get openSourceLicensesSubtitle => 'Bibliothèques tiers et leurs licences'; @override String copyright({required Object years}) => '© ${years} Association Comunes, sous AGPLv3'; @@ -1533,6 +1536,9 @@ extension on TranslationsFr { 'about.license' => 'Licence', 'about.licenseValue' => 'AGPL-3.0', 'about.website' => 'Site web', + 'about.sourceCode' => 'Code source', + 'about.translate' => 'Aider à traduire', + 'about.translateSubtitle' => 'Aidez à traduire Tane dans votre langue', 'about.openSourceLicenses' => 'Licences open source', 'about.openSourceLicensesSubtitle' => 'Bibliothèques tiers et leurs licences', 'about.copyright' => ({required Object years}) => '© ${years} Association Comunes, sous AGPLv3', @@ -1919,11 +1925,11 @@ extension on TranslationsFr { 'sale.empty' => 'Pas encore de ventes. Notez ici ce que vous vendez ou achetez.', 'sale.iSold' => 'J\'ai vendu', 'sale.iBought' => 'J\'ai acheté', + _ => null, + } ?? switch (path) { 'sale.direction' => 'Vendu ou acheté ?', 'sale.counterparty' => 'Avec qui ?', 'sale.counterpartyHint' => 'Une personne ou un collectif (optionnel)', - _ => null, - } ?? switch (path) { 'sale.amount' => 'Montant', 'sale.currency' => 'Monnaie', 'sale.currencyHint' => '€, Ğ1, heures… (optionnel)', diff --git a/apps/app_seeds/lib/i18n/strings_pt.g.dart b/apps/app_seeds/lib/i18n/strings_pt.g.dart index a242b50..dad41df 100644 --- a/apps/app_seeds/lib/i18n/strings_pt.g.dart +++ b/apps/app_seeds/lib/i18n/strings_pt.g.dart @@ -329,6 +329,9 @@ class _Translations$about$pt extends Translations$about$en { @override String get license => 'Licença'; @override String get licenseValue => 'AGPL-3.0'; @override String get website => 'Sítio web'; + @override String get sourceCode => 'Código-fonte'; + @override String get translate => 'Ajuda a traduzir'; + @override String get translateSubtitle => 'Ajuda a trazer o Tane para o teu idioma'; @override String get openSourceLicenses => 'Licenças de código aberto'; @override String get openSourceLicensesSubtitle => 'Bibliotecas de terceiros e as suas licenças'; @override String copyright({required Object years}) => '© ${years} Associação Comunes, sob AGPLv3'; @@ -1536,6 +1539,9 @@ extension on TranslationsPt { 'about.license' => 'Licença', 'about.licenseValue' => 'AGPL-3.0', 'about.website' => 'Sítio web', + 'about.sourceCode' => 'Código-fonte', + 'about.translate' => 'Ajuda a traduzir', + 'about.translateSubtitle' => 'Ajuda a trazer o Tane para o teu idioma', 'about.openSourceLicenses' => 'Licenças de código aberto', 'about.openSourceLicensesSubtitle' => 'Bibliotecas de terceiros e as suas licenças', 'about.copyright' => ({required Object years}) => '© ${years} Associação Comunes, sob AGPLv3', @@ -1922,11 +1928,11 @@ extension on TranslationsPt { 'sale.title' => 'Vendas', 'sale.help' => 'Regista semente vendida ou comprada — dinheiro, Ğ1 ou qualquer moeda. Um modelo separado do presente e do Plantare. Nunca se cobra comissão pelas sementes.', 'sale.add' => 'Registar venda', + _ => null, + } ?? switch (path) { 'sale.empty' => 'Ainda não há vendas. Anota aqui o que vendes ou compras.', 'sale.iSold' => 'Vendi', 'sale.iBought' => 'Comprei', - _ => null, - } ?? switch (path) { 'sale.direction' => 'Vendes ou compras?', 'sale.counterparty' => 'Com quem?', 'sale.counterpartyHint' => 'Uma pessoa ou um coletivo (opcional)', diff --git a/apps/app_seeds/lib/ui/about_screen.dart b/apps/app_seeds/lib/ui/about_screen.dart index 0f1b8ba..d111c8b 100644 --- a/apps/app_seeds/lib/ui/about_screen.dart +++ b/apps/app_seeds/lib/ui/about_screen.dart @@ -9,6 +9,12 @@ import 'theme.dart'; /// The app's public website. Shown as a tappable row in [AboutScreen]. const String _websiteUrl = 'https://tane.comunes.org'; +/// The public source repository (AGPL). Shown as a tappable row in [AboutScreen]. +const String _sourceUrl = 'https://git.comunes.org/comunes/tane'; + +/// The translation platform where anyone can help translate Tane. +const String _translateUrl = 'https://translate.comunes.org/projects/tane/'; + /// The year Tane's copyright starts. Ğ1nkgo uses its own first year (2023); /// Tane's is 2026. const int _copyrightStartYear = 2026; @@ -69,6 +75,24 @@ class AboutScreen extends StatelessWidget { mode: LaunchMode.externalApplication, ), ), + ListTile( + leading: const Icon(Icons.code, color: seedGreen), + title: Text(t.about.sourceCode), + subtitle: const Text(_sourceUrl), + onTap: () => launchUrl( + Uri.parse(_sourceUrl), + mode: LaunchMode.externalApplication, + ), + ), + ListTile( + leading: const Icon(Icons.translate, color: seedGreen), + title: Text(t.about.translate), + subtitle: Text(t.about.translateSubtitle), + onTap: () => launchUrl( + Uri.parse(_translateUrl), + mode: LaunchMode.externalApplication, + ), + ), ListTile( leading: const Icon(Icons.privacy_tip_outlined, color: seedGreen), title: Text(t.legal.title), diff --git a/site/config.toml b/site/config.toml index 99a9450..6ea0539 100644 --- a/site/config.toml +++ b/site/config.toml @@ -17,8 +17,8 @@ enableGitInfo = false # Links rendered only when set, so nothing broken shows before they exist: playStoreURL = "" # Google Play, once published fdroidURL = "" # F-Droid, once published - sourceURL = "" # public source repository (AGPL) — set when available - weblateURL = "" # translation platform — set when hosting is ready + sourceURL = "https://git.comunes.org/comunes/tane" # public source repository (AGPL) + weblateURL = "https://translate.comunes.org/projects/tane/" # translation platform [languages] [languages.en]