diff --git a/apps/app_seeds/lib/i18n/en.i18n.json b/apps/app_seeds/lib/i18n/en.i18n.json index 01920f4..b0d217d 100644 --- a/apps/app_seeds/lib/i18n/en.i18n.json +++ b/apps/app_seeds/lib/i18n/en.i18n.json @@ -39,6 +39,7 @@ "systemLanguage": "System language", "langEs": "Español", "langEn": "English", + "langPt": "Português", "about": "About", "aboutText": "Local-first, encrypted inventory for traditional seeds. AGPL-3.0.", "aboutOpen": "About Tanemaki" diff --git a/apps/app_seeds/lib/i18n/es.i18n.json b/apps/app_seeds/lib/i18n/es.i18n.json index 64c2f7e..15a767c 100644 --- a/apps/app_seeds/lib/i18n/es.i18n.json +++ b/apps/app_seeds/lib/i18n/es.i18n.json @@ -39,6 +39,7 @@ "systemLanguage": "Idioma del sistema", "langEs": "Español", "langEn": "English", + "langPt": "Português", "about": "Acerca de", "aboutText": "Inventario local y cifrado para semillas tradicionales. AGPL-3.0.", "aboutOpen": "Acerca de Tanemaki" diff --git a/apps/app_seeds/lib/i18n/pt.i18n.json b/apps/app_seeds/lib/i18n/pt.i18n.json new file mode 100644 index 0000000..9c7f66f --- /dev/null +++ b/apps/app_seeds/lib/i18n/pt.i18n.json @@ -0,0 +1,327 @@ +{ + "app": { + "title": "Tanemaki" + }, + "common": { + "save": "Guardar", + "cancel": "Cancelar", + "delete": "Eliminar", + "edit": "Editar", + "type": "Tipo", + "comingSoon": "Em breve" + }, + "home": { + "tagline": "Partilha e cultiva sementes locais", + "openMarket": "Mercado aberto", + "openMarketSubtitle": "Descobre e troca", + "yourInventory": "O teu inventário", + "yourInventorySubtitle": "Gere as tuas sementes" + }, + "photo": { + "camera": "Tirar uma foto", + "gallery": "Escolher da galeria", + "setAsCover": "Usar como capa", + "isCover": "Foto de capa", + "deleteConfirm": "Eliminar esta foto?" + }, + "menu": { + "tagline": "o teu banco de sementes", + "inventory": "Inventário", + "market": "Mercado", + "profile": "O teu perfil", + "chat": "Conversas", + "wishlist": "Lista de desejos", + "following": "A seguir", + "settings": "Definições" + }, + "settings": { + "language": "Idioma", + "systemLanguage": "Idioma do sistema", + "langEs": "Español", + "langEn": "English", + "langPt": "Português", + "about": "Acerca de", + "aboutText": "Inventário local e cifrado para sementes tradicionais. AGPL-3.0.", + "aboutOpen": "Acerca do Tanemaki" + }, + "backup": { + "title": "Cópia de segurança", + "exportJson": "Guardar uma cópia de segurança", + "exportJsonSubtitle": "Uma cópia completa para guardar em segurança, restaurar depois ou levar para outro aparelho", + "importJson": "Restaurar uma cópia", + "importJsonSubtitle": "Recupera uma cópia guardada — nada fica duplicado", + "exportCsv": "Exportar para uma folha de cálculo", + "exportCsvSubtitle": "Uma lista simples para Excel ou LibreOffice — sem fotos", + "importCsv": "Importar uma lista", + "importCsvSubtitle": "Acrescenta entradas a partir de uma folha de cálculo", + "importConfirmTitle": "Restaurar uma cópia?", + "importConfirmBody": "As entradas fundem-se com o teu inventário; quando a mesma entrada existe dos dois lados, vence a versão mais recente. Nada fica duplicado.", + "importCsvConfirmTitle": "Importar uma lista?", + "importCsvConfirmBody": "Cada linha é acrescentada como uma entrada nova. Não funde nem substitui, por isso importar o mesmo ficheiro duas vezes acrescenta-o duas vezes.", + "importAction": "Importar", + "exportSaved": "Cópia guardada", + "cancelled": "Cancelado", + "importDone": "Importado: {added} novas, {updated} atualizadas", + "importCsvDone": "{count} entradas acrescentadas", + "importFailed": "Este ficheiro não pôde ser lido como uma cópia do Tanemaki", + "failed": "Algo correu mal", + "recoveryTitle": "O teu código de recuperação", + "recoverySubtitle": "Imprime-o e guarda-o bem: abre as tuas cópias noutro aparelho", + "recoveryIntro": "Este código abre as tuas cópias guardadas e recupera o teu banco em qualquer aparelho. Guarda duas cópias em papel em sítios seguros, como a tua melhor semente. Quem o tiver pode ler as tuas cópias, por isso não o partilhes com ninguém.", + "recoveryCopy": "Copiar", + "recoverySave": "Guardar a folha", + "recoverySheetTitle": "Tanemaki — a tua folha de recuperação", + "recoveryPromptTitle": "Escreve o teu código de recuperação", + "recoveryPromptBody": "Esta cópia foi guardada com outro código. Escreve o código da tua folha de recuperação para a abrir.", + "recoveryWrongCode": "Esse código não abre esta cópia" + }, + "about": { + "title": "Acerca de", + "kanji": "種まき", + "tagline": "Uma aplicação local e descentralizada para gerir e partilhar sementes e plântulas tradicionais.", + "intro": "O Tanemaki (種まき, \"semear / espalhar sementes\" em japonês; nome curto Tane, 種 \"semente\") ajuda pessoas e coletivos a manter um inventário amigável do seu banco de sementes, decidir o que oferecem e partilhá-lo localmente — sem um intermediário central que possa controlar, censurar ou ser multado por isso. O objetivo é prático e político ao mesmo tempo: apoiar as variedades tradicionais e fazer frente ao monopólio das sementes.", + "heritage": "O nome honra as antigas tradições japonesas de ajuda mútua à volta do arroz — yui (trabalho comunitário partilhado) e tanomoshi (fundos de reciprocidade) — que inspiraram o Plantare em papel, a \"moeda comunitária de troca de sementes\" (BAH-Semillero, 2009, CC-BY-SA). O Tanemaki é o Plantare digital.", + "version": "Versão", + "license": "Licença", + "licenseValue": "AGPL-3.0", + "website": "Sítio web", + "openSourceLicenses": "Licenças de código aberto", + "openSourceLicensesSubtitle": "Bibliotecas de terceiros e as suas licenças" + }, + "intro": { + "skip": "Saltar", + "next": "Seguinte", + "start": "Começar", + "menuEntry": "Como funciona o Tanemaki", + "slides": { + "welcome": { + "title": "A semente que te trouxe até aqui", + "body": "Cada semente tradicional é uma carta escrita por milhares de gerações, passada de mão em mão. Somos o que somos graças a essa partilha." + }, + "inventory": { + "title": "O teu banco de sementes, no bolso", + "body": "Anota o que tens, de que ano, quanto e de onde veio — com o nome que tu usas. Uma foto e um nome chegam para começar." + }, + "privacy": { + "title": "Teu, e só teu", + "body": "Sem conta, sem internet, sem rastreadores. Os teus dados vivem cifrados no teu aparelho, e só o que tu escolheres é partilhado." + }, + "share": { + "title": "Partilhar, como sempre se fez", + "body": "Oferece o que te sobra — dar, trocar ou vender — e deixa que alguém perto de ti o encontre. Só se mostra uma distância aproximada, nunca a tua morada; o acordo fecha-se em pessoa." + }, + "plantare": { + "title": "Semear é multiplicar", + "body": "Com um Plantare, quem recebe semente promete devolver uma parte mais tarde. E como devolvê-la implica cultivá-la, cada empréstimo multiplica o comum." + } + } + }, + "inventory": { + "title": "Inventário", + "searchHint": "Procurar sementes", + "empty": "Ainda não há sementes. Toca em + para adicionar a primeira.", + "noMatches": "Nenhuma semente corresponde aos teus filtros.", + "clearFilters": "Limpar filtros", + "uncategorized": "Sem categoria", + "needsReproductionFilter": "Para reproduzir" + }, + "draft": { + "capture": "Capturar fotos", + "captured": "{n} capturadas para catalogar", + "triageTitle": "Para catalogar", + "triageCount": "{n} para catalogar", + "untitled": "Sem nome", + "nameField": "Dá um nome a esta semente", + "nameHint": "O que é?", + "suggestFromPhoto": "Sugerir nome a partir da foto", + "discard": "Descartar" + }, + "quickAdd": { + "title": "Adicionar uma semente", + "labelField": "Nome", + "labelRequired": "Dá-lhe um nome", + "addPhoto": "Adicionar foto", + "quantity": "Quanto?", + "more": "Adicionar mais…", + "save": "Guardar", + "saveAndAddAnother": "Guardar e adicionar outra", + "addedCount": "{n} adicionadas", + "cancel": "Cancelar" + }, + "detail": { + "notFound": "Esta semente já não está aqui.", + "lots": "Lotes", + "noLots": "Ainda não há lotes.", + "names": "Também conhecida como", + "addName": "Adicionar nome", + "links": "Ligações", + "addLink": "Adicionar ligação", + "linkUrl": "URL", + "linkTitle": "Título (opcional)", + "notes": "Notas", + "addLot": "Adicionar lote", + "editLot": "Editar lote", + "deleteConfirm": "Eliminar esta semente?", + "year": "Ano {year}", + "noYear": "Ano desconhecido" + }, + "germination": { + "title": "Germinação", + "add": "Adicionar teste", + "sampleSize": "Tamanho da amostra", + "germinated": "Germinadas", + "none": "Ainda não há testes de germinação.", + "result": "{percent}%" + }, + "viability": { + "expiringSoon": "Usa ou reproduz nesta época", + "expiringSoonYears": "Usa ou reproduz nesta época · dura ~{years} anos", + "expired": "Passou a viabilidade típica — reproduzir", + "expiredYears": "Passou a viabilidade típica (~{years} anos) — reproduzir" + }, + "editVariety": { + "title": "Editar semente", + "name": "Nome", + "category": "Categoria", + "notes": "Notas", + "species": "Espécie (do catálogo)", + "speciesHint": "Procura uma espécie…", + "organic": "Biológica", + "organicHint": "Cultivada em modo biológico" + }, + "addLot": { + "title": "Adicionar lote", + "year": "Data de colheita", + "quantity": "Quanto?", + "amount": "Quantidade" + }, + "harvest": { + "pickTitle": "Escolhe mês / ano", + "anyMonth": "Qualquer mês", + "noDate": "Definir data de colheita", + "monthNames": [ + "janeiro", "fevereiro", "março", "abril", "maio", "junho", + "julho", "agosto", "setembro", "outubro", "novembro", "dezembro" + ] + }, + "lotType": { + "seed": "Sementes", + "plant": "Planta", + "seedling": "Plântula", + "tree": "Árvore / arbusto", + "bulb": "Bolbo / tubérculo", + "cutting": "Estaca" + }, + "presentation": { + "title": "Apresentação", + "none": "Sem indicar", + "pot": "Vaso", + "tray": "Tabuleiro", + "plug": "Alvéolo", + "bareRoot": "Raiz nua", + "rootBall": "Torrão" + }, + "provenance": { + "section": "De onde vem", + "seedsFrom": "Sementes de", + "seedsFromHint": "Quem as cultivou ou ofereceu", + "place": "Lugar", + "placeHint": "De onde vêm (com a região)", + "addSeedsFrom": "Sementes de", + "addPlace": "Lugar" + }, + "abundance": { + "add": "Quanta tenho", + "title": "Quanta tenho", + "none": "Sem indicar", + "plentyToShare": "De sobra para partilhar", + "enoughToShare": "Bastante, para partilhar com moderação", + "enoughForMe": "Suficiente para mim", + "runningLow": "Resta pouca" + }, + "share": { + "add": "Partilhas esta?", + "title": "Partilhas esta?", + "nudge": "Tens de sobra: podias partilhar um pouco.", + "private": "Só para mim", + "gift": "Para dar", + "exchange": "Para trocar", + "sell": "À venda", + "filterChip": "Partilho", + "printCatalog": "Imprimir o que partilho", + "catalogTitle": "O que partilho", + "catalogSaved": "Catálogo guardado", + "cancelled": "Cancelado" + }, + "cropCalendar": { + "add": "Calendário de cultivo", + "title": "Calendário de cultivo", + "sow": "Sementeira", + "transplant": "Transplante", + "flowering": "Floração", + "fruiting": "Frutificação", + "seedHarvest": "Colheita de semente", + "unset": "—" + }, + "needsReproduction": { + "label": "Reproduzir nesta época", + "hint": "Cultiva-a antes que a semente acabe", + "badge": "Por reproduzir" + }, + "preservation": { + "add": "Como está guardada", + "title": "Como está guardada", + "none": "Sem indicar", + "jarWithDesiccant": "Frasco com agente secante", + "glassJar": "Frasco de vidro", + "paperEnvelope": "Envelope de papel", + "paperBag": "Saco de papel", + "plasticBag": "Saco de plástico" + }, + "conditionCheck": { + "advanced": "Armazenamento e detalhes de banco de sementes", + "title": "Verificações de armazenamento", + "add": "Adicionar verificação", + "containers": "Frascos / recipientes", + "desiccant": "Agente secante", + "none": "Ainda não há verificações de armazenamento.", + "summary": "{count} frasco(s) · {state}" + }, + "desiccant": { + "none": "Nenhum", + "add": "Adicionar", + "replace": "Substituir", + "dry": "Azul — seco", + "fresh": "Acabado de renovar" + }, + "unit": { + "aFew": "algumas", + "some": "bastantes", + "plenty": "muitas", + "pinch": "uma pitada", + "handful": { "singular": "mão-cheia", "plural": "mãos-cheias" }, + "teaspoon": { "singular": "colher de chá", "plural": "colheres de chá" }, + "spoon": { "singular": "colher", "plural": "colheres" }, + "cup": { "singular": "chávena", "plural": "chávenas" }, + "jar": { "singular": "frasco", "plural": "frascos" }, + "sack": { "singular": "saco", "plural": "sacos" }, + "packet": { "singular": "pacote", "plural": "pacotes" }, + "cob": { "singular": "maçaroca", "plural": "maçarocas" }, + "pod": { "singular": "vagem", "plural": "vagens" }, + "ear": { "singular": "espiga", "plural": "espigas" }, + "head": { "singular": "cabeça", "plural": "cabeças" }, + "fruit": { "singular": "fruto", "plural": "frutos" }, + "bulb": { "singular": "bolbo", "plural": "bolbos" }, + "tuber": { "singular": "tubérculo", "plural": "tubérculos" }, + "seedHead": { "singular": "capítulo", "plural": "capítulos" }, + "bunch": { "singular": "molho", "plural": "molhos" }, + "plant": { "singular": "planta", "plural": "plantas" }, + "pot": { "singular": "vaso", "plural": "vasos" }, + "tray": { "singular": "tabuleiro", "plural": "tabuleiros" }, + "seedling": { "singular": "plântula", "plural": "plântulas" }, + "tree": { "singular": "árvore", "plural": "árvores" }, + "cutting": { "singular": "estaca", "plural": "estacas" }, + "grams": { "singular": "grama", "plural": "gramas" }, + "count": { "singular": "semente", "plural": "sementes" } + } +} diff --git a/apps/app_seeds/lib/i18n/strings.g.dart b/apps/app_seeds/lib/i18n/strings.g.dart index fc34650..32c5ed5 100644 --- a/apps/app_seeds/lib/i18n/strings.g.dart +++ b/apps/app_seeds/lib/i18n/strings.g.dart @@ -3,10 +3,10 @@ /// Source: lib/i18n /// To regenerate, run: `dart run slang` /// -/// Locales: 2 -/// Strings: 572 (286 per locale) +/// Locales: 3 +/// Strings: 861 (287 per locale) /// -/// Built on 2026-07-09 at 20:28 UTC +/// Built on 2026-07-09 at 20:35 UTC // coverage:ignore-file // ignore_for_file: type=lint, unused_import @@ -19,6 +19,7 @@ import 'package:slang_flutter/slang_flutter.dart'; export 'package:slang_flutter/slang_flutter.dart'; import 'strings_es.g.dart' as l_es; +import 'strings_pt.g.dart' as l_pt; part 'strings_en.g.dart'; /// Supported locales. @@ -29,7 +30,8 @@ part 'strings_en.g.dart'; /// - if (LocaleSettings.currentLocale == AppLocale.en) // locale check enum AppLocale with BaseAppLocale { en(languageCode: 'en'), - es(languageCode: 'es'); + es(languageCode: 'es'), + pt(languageCode: 'pt'); const AppLocale({ required this.languageCode, @@ -73,6 +75,12 @@ enum AppLocale with BaseAppLocale { cardinalResolver: cardinalResolver, ordinalResolver: ordinalResolver, ); + case AppLocale.pt: + return l_pt.TranslationsPt( + overrides: overrides, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ); } } diff --git a/apps/app_seeds/lib/i18n/strings_en.g.dart b/apps/app_seeds/lib/i18n/strings_en.g.dart index 304c8b4..5ad84ad 100644 --- a/apps/app_seeds/lib/i18n/strings_en.g.dart +++ b/apps/app_seeds/lib/i18n/strings_en.g.dart @@ -211,6 +211,9 @@ class Translations$settings$en { /// en: 'English' String get langEn => 'English'; + /// en: 'Português' + String get langPt => 'Português'; + /// en: 'About' String get about => 'About'; @@ -1508,6 +1511,7 @@ extension on Translations { 'settings.systemLanguage' => 'System language', 'settings.langEs' => 'Español', 'settings.langEn' => 'English', + 'settings.langPt' => 'Português', 'settings.about' => 'About', 'settings.aboutText' => 'Local-first, encrypted inventory for traditional seeds. AGPL-3.0.', 'settings.aboutOpen' => 'About Tanemaki', diff --git a/apps/app_seeds/lib/i18n/strings_es.g.dart b/apps/app_seeds/lib/i18n/strings_es.g.dart index 3f11166..622ddc3 100644 --- a/apps/app_seeds/lib/i18n/strings_es.g.dart +++ b/apps/app_seeds/lib/i18n/strings_es.g.dart @@ -151,6 +151,7 @@ class _Translations$settings$es extends Translations$settings$en { @override String get systemLanguage => 'Idioma del sistema'; @override String get langEs => 'Español'; @override String get langEn => 'English'; + @override String get langPt => 'Português'; @override String get about => 'Acerca de'; @override String get aboutText => 'Inventario local y cifrado para semillas tradicionales. AGPL-3.0.'; @override String get aboutOpen => 'Acerca de Tanemaki'; @@ -956,6 +957,7 @@ extension on TranslationsEs { 'settings.systemLanguage' => 'Idioma del sistema', 'settings.langEs' => 'Español', 'settings.langEn' => 'English', + 'settings.langPt' => 'Português', 'settings.about' => 'Acerca de', 'settings.aboutText' => 'Inventario local y cifrado para semillas tradicionales. AGPL-3.0.', 'settings.aboutOpen' => 'Acerca de Tanemaki', diff --git a/apps/app_seeds/lib/i18n/strings_pt.g.dart b/apps/app_seeds/lib/i18n/strings_pt.g.dart new file mode 100644 index 0000000..2998e7d --- /dev/null +++ b/apps/app_seeds/lib/i18n/strings_pt.g.dart @@ -0,0 +1,1221 @@ +/// +/// Generated file. Do not edit. +/// +// coverage:ignore-file +// ignore_for_file: type=lint, unused_import +// dart format off + +import 'package:flutter/widgets.dart'; +import 'package:intl/intl.dart'; +import 'package:slang/generated.dart'; +import 'strings.g.dart'; + +// Path: +class TranslationsPt extends Translations with BaseTranslations { + /// You can call this constructor and build your own translation instance of this locale. + /// Constructing via the enum [AppLocale.build] is preferred. + TranslationsPt({Map? overrides, PluralResolver? cardinalResolver, PluralResolver? ordinalResolver, TranslationMetadata? meta}) + : assert(overrides == null, 'Set "translation_overrides: true" in order to enable this feature.'), + $meta = meta ?? TranslationMetadata( + locale: AppLocale.pt, + overrides: overrides ?? {}, + cardinalResolver: cardinalResolver, + ordinalResolver: ordinalResolver, + ), + super(cardinalResolver: cardinalResolver, ordinalResolver: ordinalResolver) { + super.$meta.setFlatMapFunction($meta.getTranslation); // copy base translations to super.$meta + $meta.setFlatMapFunction(_flatMapFunction); + } + + /// Metadata for the translations of . + @override final TranslationMetadata $meta; + + /// Access flat map + @override dynamic operator[](String key) => $meta.getTranslation(key) ?? super.$meta.getTranslation(key); + + late final TranslationsPt _root = this; // ignore: unused_field + + @override + TranslationsPt $copyWith({TranslationMetadata? meta}) => TranslationsPt(meta: meta ?? this.$meta); + + // Translations + @override late final _Translations$app$pt app = _Translations$app$pt._(_root); + @override late final _Translations$common$pt common = _Translations$common$pt._(_root); + @override late final _Translations$home$pt home = _Translations$home$pt._(_root); + @override late final _Translations$photo$pt photo = _Translations$photo$pt._(_root); + @override late final _Translations$menu$pt menu = _Translations$menu$pt._(_root); + @override late final _Translations$settings$pt settings = _Translations$settings$pt._(_root); + @override late final _Translations$backup$pt backup = _Translations$backup$pt._(_root); + @override late final _Translations$about$pt about = _Translations$about$pt._(_root); + @override late final _Translations$intro$pt intro = _Translations$intro$pt._(_root); + @override late final _Translations$inventory$pt inventory = _Translations$inventory$pt._(_root); + @override late final _Translations$draft$pt draft = _Translations$draft$pt._(_root); + @override late final _Translations$quickAdd$pt quickAdd = _Translations$quickAdd$pt._(_root); + @override late final _Translations$detail$pt detail = _Translations$detail$pt._(_root); + @override late final _Translations$germination$pt germination = _Translations$germination$pt._(_root); + @override late final _Translations$viability$pt viability = _Translations$viability$pt._(_root); + @override late final _Translations$editVariety$pt editVariety = _Translations$editVariety$pt._(_root); + @override late final _Translations$addLot$pt addLot = _Translations$addLot$pt._(_root); + @override late final _Translations$harvest$pt harvest = _Translations$harvest$pt._(_root); + @override late final _Translations$lotType$pt lotType = _Translations$lotType$pt._(_root); + @override late final _Translations$presentation$pt presentation = _Translations$presentation$pt._(_root); + @override late final _Translations$provenance$pt provenance = _Translations$provenance$pt._(_root); + @override late final _Translations$abundance$pt abundance = _Translations$abundance$pt._(_root); + @override late final _Translations$share$pt share = _Translations$share$pt._(_root); + @override late final _Translations$cropCalendar$pt cropCalendar = _Translations$cropCalendar$pt._(_root); + @override late final _Translations$needsReproduction$pt needsReproduction = _Translations$needsReproduction$pt._(_root); + @override late final _Translations$preservation$pt preservation = _Translations$preservation$pt._(_root); + @override late final _Translations$conditionCheck$pt conditionCheck = _Translations$conditionCheck$pt._(_root); + @override late final _Translations$desiccant$pt desiccant = _Translations$desiccant$pt._(_root); + @override late final _Translations$unit$pt unit = _Translations$unit$pt._(_root); +} + +// Path: app +class _Translations$app$pt extends Translations$app$en { + _Translations$app$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Tanemaki'; +} + +// Path: common +class _Translations$common$pt extends Translations$common$en { + _Translations$common$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get save => 'Guardar'; + @override String get cancel => 'Cancelar'; + @override String get delete => 'Eliminar'; + @override String get edit => 'Editar'; + @override String get type => 'Tipo'; + @override String get comingSoon => 'Em breve'; +} + +// Path: home +class _Translations$home$pt extends Translations$home$en { + _Translations$home$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get tagline => 'Partilha e cultiva sementes locais'; + @override String get openMarket => 'Mercado aberto'; + @override String get openMarketSubtitle => 'Descobre e troca'; + @override String get yourInventory => 'O teu inventário'; + @override String get yourInventorySubtitle => 'Gere as tuas sementes'; +} + +// Path: photo +class _Translations$photo$pt extends Translations$photo$en { + _Translations$photo$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get camera => 'Tirar uma foto'; + @override String get gallery => 'Escolher da galeria'; + @override String get setAsCover => 'Usar como capa'; + @override String get isCover => 'Foto de capa'; + @override String get deleteConfirm => 'Eliminar esta foto?'; +} + +// Path: menu +class _Translations$menu$pt extends Translations$menu$en { + _Translations$menu$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get tagline => 'o teu banco de sementes'; + @override String get inventory => 'Inventário'; + @override String get market => 'Mercado'; + @override String get profile => 'O teu perfil'; + @override String get chat => 'Conversas'; + @override String get wishlist => 'Lista de desejos'; + @override String get following => 'A seguir'; + @override String get settings => 'Definições'; +} + +// Path: settings +class _Translations$settings$pt extends Translations$settings$en { + _Translations$settings$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get language => 'Idioma'; + @override String get systemLanguage => 'Idioma do sistema'; + @override String get langEs => 'Español'; + @override String get langEn => 'English'; + @override String get langPt => 'Português'; + @override String get about => 'Acerca de'; + @override String get aboutText => 'Inventário local e cifrado para sementes tradicionais. AGPL-3.0.'; + @override String get aboutOpen => 'Acerca do Tanemaki'; +} + +// Path: backup +class _Translations$backup$pt extends Translations$backup$en { + _Translations$backup$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Cópia de segurança'; + @override String get exportJson => 'Guardar uma cópia de segurança'; + @override String get exportJsonSubtitle => 'Uma cópia completa para guardar em segurança, restaurar depois ou levar para outro aparelho'; + @override String get importJson => 'Restaurar uma cópia'; + @override String get importJsonSubtitle => 'Recupera uma cópia guardada — nada fica duplicado'; + @override String get exportCsv => 'Exportar para uma folha de cálculo'; + @override String get exportCsvSubtitle => 'Uma lista simples para Excel ou LibreOffice — sem fotos'; + @override String get importCsv => 'Importar uma lista'; + @override String get importCsvSubtitle => 'Acrescenta entradas a partir de uma folha de cálculo'; + @override String get importConfirmTitle => 'Restaurar uma cópia?'; + @override String get importConfirmBody => 'As entradas fundem-se com o teu inventário; quando a mesma entrada existe dos dois lados, vence a versão mais recente. Nada fica duplicado.'; + @override String get importCsvConfirmTitle => 'Importar uma lista?'; + @override String get importCsvConfirmBody => 'Cada linha é acrescentada como uma entrada nova. Não funde nem substitui, por isso importar o mesmo ficheiro duas vezes acrescenta-o duas vezes.'; + @override String get importAction => 'Importar'; + @override String get exportSaved => 'Cópia guardada'; + @override String get cancelled => 'Cancelado'; + @override String importDone({required Object added, required Object updated}) => 'Importado: ${added} novas, ${updated} atualizadas'; + @override String importCsvDone({required Object count}) => '${count} entradas acrescentadas'; + @override String get importFailed => 'Este ficheiro não pôde ser lido como uma cópia do Tanemaki'; + @override String get failed => 'Algo correu mal'; + @override String get recoveryTitle => 'O teu código de recuperação'; + @override String get recoverySubtitle => 'Imprime-o e guarda-o bem: abre as tuas cópias noutro aparelho'; + @override String get recoveryIntro => 'Este código abre as tuas cópias guardadas e recupera o teu banco em qualquer aparelho. Guarda duas cópias em papel em sítios seguros, como a tua melhor semente. Quem o tiver pode ler as tuas cópias, por isso não o partilhes com ninguém.'; + @override String get recoveryCopy => 'Copiar'; + @override String get recoverySave => 'Guardar a folha'; + @override String get recoverySheetTitle => 'Tanemaki — a tua folha de recuperação'; + @override String get recoveryPromptTitle => 'Escreve o teu código de recuperação'; + @override String get recoveryPromptBody => 'Esta cópia foi guardada com outro código. Escreve o código da tua folha de recuperação para a abrir.'; + @override String get recoveryWrongCode => 'Esse código não abre esta cópia'; +} + +// Path: about +class _Translations$about$pt extends Translations$about$en { + _Translations$about$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Acerca de'; + @override String get kanji => '種まき'; + @override String get tagline => 'Uma aplicação local e descentralizada para gerir e partilhar sementes e plântulas tradicionais.'; + @override String get intro => 'O Tanemaki (種まき, "semear / espalhar sementes" em japonês; nome curto Tane, 種 "semente") ajuda pessoas e coletivos a manter um inventário amigável do seu banco de sementes, decidir o que oferecem e partilhá-lo localmente — sem um intermediário central que possa controlar, censurar ou ser multado por isso. O objetivo é prático e político ao mesmo tempo: apoiar as variedades tradicionais e fazer frente ao monopólio das sementes.'; + @override String get heritage => 'O nome honra as antigas tradições japonesas de ajuda mútua à volta do arroz — yui (trabalho comunitário partilhado) e tanomoshi (fundos de reciprocidade) — que inspiraram o Plantare em papel, a "moeda comunitária de troca de sementes" (BAH-Semillero, 2009, CC-BY-SA). O Tanemaki é o Plantare digital.'; + @override String get version => 'Versão'; + @override String get license => 'Licença'; + @override String get licenseValue => 'AGPL-3.0'; + @override String get website => 'Sítio web'; + @override String get openSourceLicenses => 'Licenças de código aberto'; + @override String get openSourceLicensesSubtitle => 'Bibliotecas de terceiros e as suas licenças'; +} + +// Path: intro +class _Translations$intro$pt extends Translations$intro$en { + _Translations$intro$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get skip => 'Saltar'; + @override String get next => 'Seguinte'; + @override String get start => 'Começar'; + @override String get menuEntry => 'Como funciona o Tanemaki'; + @override late final _Translations$intro$slides$pt slides = _Translations$intro$slides$pt._(_root); +} + +// Path: inventory +class _Translations$inventory$pt extends Translations$inventory$en { + _Translations$inventory$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Inventário'; + @override String get searchHint => 'Procurar sementes'; + @override String get empty => 'Ainda não há sementes. Toca em + para adicionar a primeira.'; + @override String get noMatches => 'Nenhuma semente corresponde aos teus filtros.'; + @override String get clearFilters => 'Limpar filtros'; + @override String get uncategorized => 'Sem categoria'; + @override String get needsReproductionFilter => 'Para reproduzir'; +} + +// Path: draft +class _Translations$draft$pt extends Translations$draft$en { + _Translations$draft$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get capture => 'Capturar fotos'; + @override String captured({required Object n}) => '${n} capturadas para catalogar'; + @override String get triageTitle => 'Para catalogar'; + @override String triageCount({required Object n}) => '${n} para catalogar'; + @override String get untitled => 'Sem nome'; + @override String get nameField => 'Dá um nome a esta semente'; + @override String get nameHint => 'O que é?'; + @override String get suggestFromPhoto => 'Sugerir nome a partir da foto'; + @override String get discard => 'Descartar'; +} + +// Path: quickAdd +class _Translations$quickAdd$pt extends Translations$quickAdd$en { + _Translations$quickAdd$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Adicionar uma semente'; + @override String get labelField => 'Nome'; + @override String get labelRequired => 'Dá-lhe um nome'; + @override String get addPhoto => 'Adicionar foto'; + @override String get quantity => 'Quanto?'; + @override String get more => 'Adicionar mais…'; + @override String get save => 'Guardar'; + @override String get saveAndAddAnother => 'Guardar e adicionar outra'; + @override String addedCount({required Object n}) => '${n} adicionadas'; + @override String get cancel => 'Cancelar'; +} + +// Path: detail +class _Translations$detail$pt extends Translations$detail$en { + _Translations$detail$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get notFound => 'Esta semente já não está aqui.'; + @override String get lots => 'Lotes'; + @override String get noLots => 'Ainda não há lotes.'; + @override String get names => 'Também conhecida como'; + @override String get addName => 'Adicionar nome'; + @override String get links => 'Ligações'; + @override String get addLink => 'Adicionar ligação'; + @override String get linkUrl => 'URL'; + @override String get linkTitle => 'Título (opcional)'; + @override String get notes => 'Notas'; + @override String get addLot => 'Adicionar lote'; + @override String get editLot => 'Editar lote'; + @override String get deleteConfirm => 'Eliminar esta semente?'; + @override String year({required Object year}) => 'Ano ${year}'; + @override String get noYear => 'Ano desconhecido'; +} + +// Path: germination +class _Translations$germination$pt extends Translations$germination$en { + _Translations$germination$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Germinação'; + @override String get add => 'Adicionar teste'; + @override String get sampleSize => 'Tamanho da amostra'; + @override String get germinated => 'Germinadas'; + @override String get none => 'Ainda não há testes de germinação.'; + @override String result({required Object percent}) => '${percent}%'; +} + +// Path: viability +class _Translations$viability$pt extends Translations$viability$en { + _Translations$viability$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get expiringSoon => 'Usa ou reproduz nesta época'; + @override String expiringSoonYears({required Object years}) => 'Usa ou reproduz nesta época · dura ~${years} anos'; + @override String get expired => 'Passou a viabilidade típica — reproduzir'; + @override String expiredYears({required Object years}) => 'Passou a viabilidade típica (~${years} anos) — reproduzir'; +} + +// Path: editVariety +class _Translations$editVariety$pt extends Translations$editVariety$en { + _Translations$editVariety$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Editar semente'; + @override String get name => 'Nome'; + @override String get category => 'Categoria'; + @override String get notes => 'Notas'; + @override String get species => 'Espécie (do catálogo)'; + @override String get speciesHint => 'Procura uma espécie…'; + @override String get organic => 'Biológica'; + @override String get organicHint => 'Cultivada em modo biológico'; +} + +// Path: addLot +class _Translations$addLot$pt extends Translations$addLot$en { + _Translations$addLot$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Adicionar lote'; + @override String get year => 'Data de colheita'; + @override String get quantity => 'Quanto?'; + @override String get amount => 'Quantidade'; +} + +// Path: harvest +class _Translations$harvest$pt extends Translations$harvest$en { + _Translations$harvest$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get pickTitle => 'Escolhe mês / ano'; + @override String get anyMonth => 'Qualquer mês'; + @override String get noDate => 'Definir data de colheita'; + @override List get monthNames => [ + 'janeiro', + 'fevereiro', + 'março', + 'abril', + 'maio', + 'junho', + 'julho', + 'agosto', + 'setembro', + 'outubro', + 'novembro', + 'dezembro', + ]; +} + +// Path: lotType +class _Translations$lotType$pt extends Translations$lotType$en { + _Translations$lotType$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get seed => 'Sementes'; + @override String get plant => 'Planta'; + @override String get seedling => 'Plântula'; + @override String get tree => 'Árvore / arbusto'; + @override String get bulb => 'Bolbo / tubérculo'; + @override String get cutting => 'Estaca'; +} + +// Path: presentation +class _Translations$presentation$pt extends Translations$presentation$en { + _Translations$presentation$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Apresentação'; + @override String get none => 'Sem indicar'; + @override String get pot => 'Vaso'; + @override String get tray => 'Tabuleiro'; + @override String get plug => 'Alvéolo'; + @override String get bareRoot => 'Raiz nua'; + @override String get rootBall => 'Torrão'; +} + +// Path: provenance +class _Translations$provenance$pt extends Translations$provenance$en { + _Translations$provenance$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get section => 'De onde vem'; + @override String get seedsFrom => 'Sementes de'; + @override String get seedsFromHint => 'Quem as cultivou ou ofereceu'; + @override String get place => 'Lugar'; + @override String get placeHint => 'De onde vêm (com a região)'; + @override String get addSeedsFrom => 'Sementes de'; + @override String get addPlace => 'Lugar'; +} + +// Path: abundance +class _Translations$abundance$pt extends Translations$abundance$en { + _Translations$abundance$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get add => 'Quanta tenho'; + @override String get title => 'Quanta tenho'; + @override String get none => 'Sem indicar'; + @override String get plentyToShare => 'De sobra para partilhar'; + @override String get enoughToShare => 'Bastante, para partilhar com moderação'; + @override String get enoughForMe => 'Suficiente para mim'; + @override String get runningLow => 'Resta pouca'; +} + +// Path: share +class _Translations$share$pt extends Translations$share$en { + _Translations$share$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get add => 'Partilhas esta?'; + @override String get title => 'Partilhas esta?'; + @override String get nudge => 'Tens de sobra: podias partilhar um pouco.'; + @override String get private => 'Só para mim'; + @override String get gift => 'Para dar'; + @override String get exchange => 'Para trocar'; + @override String get sell => 'À venda'; + @override String get filterChip => 'Partilho'; + @override String get printCatalog => 'Imprimir o que partilho'; + @override String get catalogTitle => 'O que partilho'; + @override String get catalogSaved => 'Catálogo guardado'; + @override String get cancelled => 'Cancelado'; +} + +// Path: cropCalendar +class _Translations$cropCalendar$pt extends Translations$cropCalendar$en { + _Translations$cropCalendar$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get add => 'Calendário de cultivo'; + @override String get title => 'Calendário de cultivo'; + @override String get sow => 'Sementeira'; + @override String get transplant => 'Transplante'; + @override String get flowering => 'Floração'; + @override String get fruiting => 'Frutificação'; + @override String get seedHarvest => 'Colheita de semente'; + @override String get unset => '—'; +} + +// Path: needsReproduction +class _Translations$needsReproduction$pt extends Translations$needsReproduction$en { + _Translations$needsReproduction$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get label => 'Reproduzir nesta época'; + @override String get hint => 'Cultiva-a antes que a semente acabe'; + @override String get badge => 'Por reproduzir'; +} + +// Path: preservation +class _Translations$preservation$pt extends Translations$preservation$en { + _Translations$preservation$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get add => 'Como está guardada'; + @override String get title => 'Como está guardada'; + @override String get none => 'Sem indicar'; + @override String get jarWithDesiccant => 'Frasco com agente secante'; + @override String get glassJar => 'Frasco de vidro'; + @override String get paperEnvelope => 'Envelope de papel'; + @override String get paperBag => 'Saco de papel'; + @override String get plasticBag => 'Saco de plástico'; +} + +// Path: conditionCheck +class _Translations$conditionCheck$pt extends Translations$conditionCheck$en { + _Translations$conditionCheck$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get advanced => 'Armazenamento e detalhes de banco de sementes'; + @override String get title => 'Verificações de armazenamento'; + @override String get add => 'Adicionar verificação'; + @override String get containers => 'Frascos / recipientes'; + @override String get desiccant => 'Agente secante'; + @override String get none => 'Ainda não há verificações de armazenamento.'; + @override String summary({required Object count, required Object state}) => '${count} frasco(s) · ${state}'; +} + +// Path: desiccant +class _Translations$desiccant$pt extends Translations$desiccant$en { + _Translations$desiccant$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get none => 'Nenhum'; + @override String get add => 'Adicionar'; + @override String get replace => 'Substituir'; + @override String get dry => 'Azul — seco'; + @override String get fresh => 'Acabado de renovar'; +} + +// Path: unit +class _Translations$unit$pt extends Translations$unit$en { + _Translations$unit$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get aFew => 'algumas'; + @override String get some => 'bastantes'; + @override String get plenty => 'muitas'; + @override String get pinch => 'uma pitada'; + @override late final _Translations$unit$handful$pt handful = _Translations$unit$handful$pt._(_root); + @override late final _Translations$unit$teaspoon$pt teaspoon = _Translations$unit$teaspoon$pt._(_root); + @override late final _Translations$unit$spoon$pt spoon = _Translations$unit$spoon$pt._(_root); + @override late final _Translations$unit$cup$pt cup = _Translations$unit$cup$pt._(_root); + @override late final _Translations$unit$jar$pt jar = _Translations$unit$jar$pt._(_root); + @override late final _Translations$unit$sack$pt sack = _Translations$unit$sack$pt._(_root); + @override late final _Translations$unit$packet$pt packet = _Translations$unit$packet$pt._(_root); + @override late final _Translations$unit$cob$pt cob = _Translations$unit$cob$pt._(_root); + @override late final _Translations$unit$pod$pt pod = _Translations$unit$pod$pt._(_root); + @override late final _Translations$unit$ear$pt ear = _Translations$unit$ear$pt._(_root); + @override late final _Translations$unit$head$pt head = _Translations$unit$head$pt._(_root); + @override late final _Translations$unit$fruit$pt fruit = _Translations$unit$fruit$pt._(_root); + @override late final _Translations$unit$bulb$pt bulb = _Translations$unit$bulb$pt._(_root); + @override late final _Translations$unit$tuber$pt tuber = _Translations$unit$tuber$pt._(_root); + @override late final _Translations$unit$seedHead$pt seedHead = _Translations$unit$seedHead$pt._(_root); + @override late final _Translations$unit$bunch$pt bunch = _Translations$unit$bunch$pt._(_root); + @override late final _Translations$unit$plant$pt plant = _Translations$unit$plant$pt._(_root); + @override late final _Translations$unit$pot$pt pot = _Translations$unit$pot$pt._(_root); + @override late final _Translations$unit$tray$pt tray = _Translations$unit$tray$pt._(_root); + @override late final _Translations$unit$seedling$pt seedling = _Translations$unit$seedling$pt._(_root); + @override late final _Translations$unit$tree$pt tree = _Translations$unit$tree$pt._(_root); + @override late final _Translations$unit$cutting$pt cutting = _Translations$unit$cutting$pt._(_root); + @override late final _Translations$unit$grams$pt grams = _Translations$unit$grams$pt._(_root); + @override late final _Translations$unit$count$pt count = _Translations$unit$count$pt._(_root); +} + +// Path: intro.slides +class _Translations$intro$slides$pt extends Translations$intro$slides$en { + _Translations$intro$slides$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override late final _Translations$intro$slides$welcome$pt welcome = _Translations$intro$slides$welcome$pt._(_root); + @override late final _Translations$intro$slides$inventory$pt inventory = _Translations$intro$slides$inventory$pt._(_root); + @override late final _Translations$intro$slides$privacy$pt privacy = _Translations$intro$slides$privacy$pt._(_root); + @override late final _Translations$intro$slides$share$pt share = _Translations$intro$slides$share$pt._(_root); + @override late final _Translations$intro$slides$plantare$pt plantare = _Translations$intro$slides$plantare$pt._(_root); +} + +// Path: unit.handful +class _Translations$unit$handful$pt extends Translations$unit$handful$en { + _Translations$unit$handful$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'mão-cheia'; + @override String get plural => 'mãos-cheias'; +} + +// Path: unit.teaspoon +class _Translations$unit$teaspoon$pt extends Translations$unit$teaspoon$en { + _Translations$unit$teaspoon$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'colher de chá'; + @override String get plural => 'colheres de chá'; +} + +// Path: unit.spoon +class _Translations$unit$spoon$pt extends Translations$unit$spoon$en { + _Translations$unit$spoon$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'colher'; + @override String get plural => 'colheres'; +} + +// Path: unit.cup +class _Translations$unit$cup$pt extends Translations$unit$cup$en { + _Translations$unit$cup$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'chávena'; + @override String get plural => 'chávenas'; +} + +// Path: unit.jar +class _Translations$unit$jar$pt extends Translations$unit$jar$en { + _Translations$unit$jar$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'frasco'; + @override String get plural => 'frascos'; +} + +// Path: unit.sack +class _Translations$unit$sack$pt extends Translations$unit$sack$en { + _Translations$unit$sack$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'saco'; + @override String get plural => 'sacos'; +} + +// Path: unit.packet +class _Translations$unit$packet$pt extends Translations$unit$packet$en { + _Translations$unit$packet$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'pacote'; + @override String get plural => 'pacotes'; +} + +// Path: unit.cob +class _Translations$unit$cob$pt extends Translations$unit$cob$en { + _Translations$unit$cob$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'maçaroca'; + @override String get plural => 'maçarocas'; +} + +// Path: unit.pod +class _Translations$unit$pod$pt extends Translations$unit$pod$en { + _Translations$unit$pod$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'vagem'; + @override String get plural => 'vagens'; +} + +// Path: unit.ear +class _Translations$unit$ear$pt extends Translations$unit$ear$en { + _Translations$unit$ear$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'espiga'; + @override String get plural => 'espigas'; +} + +// Path: unit.head +class _Translations$unit$head$pt extends Translations$unit$head$en { + _Translations$unit$head$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'cabeça'; + @override String get plural => 'cabeças'; +} + +// Path: unit.fruit +class _Translations$unit$fruit$pt extends Translations$unit$fruit$en { + _Translations$unit$fruit$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'fruto'; + @override String get plural => 'frutos'; +} + +// Path: unit.bulb +class _Translations$unit$bulb$pt extends Translations$unit$bulb$en { + _Translations$unit$bulb$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'bolbo'; + @override String get plural => 'bolbos'; +} + +// Path: unit.tuber +class _Translations$unit$tuber$pt extends Translations$unit$tuber$en { + _Translations$unit$tuber$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'tubérculo'; + @override String get plural => 'tubérculos'; +} + +// Path: unit.seedHead +class _Translations$unit$seedHead$pt extends Translations$unit$seedHead$en { + _Translations$unit$seedHead$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'capítulo'; + @override String get plural => 'capítulos'; +} + +// Path: unit.bunch +class _Translations$unit$bunch$pt extends Translations$unit$bunch$en { + _Translations$unit$bunch$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'molho'; + @override String get plural => 'molhos'; +} + +// Path: unit.plant +class _Translations$unit$plant$pt extends Translations$unit$plant$en { + _Translations$unit$plant$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'planta'; + @override String get plural => 'plantas'; +} + +// Path: unit.pot +class _Translations$unit$pot$pt extends Translations$unit$pot$en { + _Translations$unit$pot$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'vaso'; + @override String get plural => 'vasos'; +} + +// Path: unit.tray +class _Translations$unit$tray$pt extends Translations$unit$tray$en { + _Translations$unit$tray$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'tabuleiro'; + @override String get plural => 'tabuleiros'; +} + +// Path: unit.seedling +class _Translations$unit$seedling$pt extends Translations$unit$seedling$en { + _Translations$unit$seedling$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'plântula'; + @override String get plural => 'plântulas'; +} + +// Path: unit.tree +class _Translations$unit$tree$pt extends Translations$unit$tree$en { + _Translations$unit$tree$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'árvore'; + @override String get plural => 'árvores'; +} + +// Path: unit.cutting +class _Translations$unit$cutting$pt extends Translations$unit$cutting$en { + _Translations$unit$cutting$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'estaca'; + @override String get plural => 'estacas'; +} + +// Path: unit.grams +class _Translations$unit$grams$pt extends Translations$unit$grams$en { + _Translations$unit$grams$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'grama'; + @override String get plural => 'gramas'; +} + +// Path: unit.count +class _Translations$unit$count$pt extends Translations$unit$count$en { + _Translations$unit$count$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get singular => 'semente'; + @override String get plural => 'sementes'; +} + +// Path: intro.slides.welcome +class _Translations$intro$slides$welcome$pt extends Translations$intro$slides$welcome$en { + _Translations$intro$slides$welcome$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'A semente que te trouxe até aqui'; + @override String get body => 'Cada semente tradicional é uma carta escrita por milhares de gerações, passada de mão em mão. Somos o que somos graças a essa partilha.'; +} + +// Path: intro.slides.inventory +class _Translations$intro$slides$inventory$pt extends Translations$intro$slides$inventory$en { + _Translations$intro$slides$inventory$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'O teu banco de sementes, no bolso'; + @override String get body => 'Anota o que tens, de que ano, quanto e de onde veio — com o nome que tu usas. Uma foto e um nome chegam para começar.'; +} + +// Path: intro.slides.privacy +class _Translations$intro$slides$privacy$pt extends Translations$intro$slides$privacy$en { + _Translations$intro$slides$privacy$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Teu, e só teu'; + @override String get body => 'Sem conta, sem internet, sem rastreadores. Os teus dados vivem cifrados no teu aparelho, e só o que tu escolheres é partilhado.'; +} + +// Path: intro.slides.share +class _Translations$intro$slides$share$pt extends Translations$intro$slides$share$en { + _Translations$intro$slides$share$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Partilhar, como sempre se fez'; + @override String get body => 'Oferece o que te sobra — dar, trocar ou vender — e deixa que alguém perto de ti o encontre. Só se mostra uma distância aproximada, nunca a tua morada; o acordo fecha-se em pessoa.'; +} + +// Path: intro.slides.plantare +class _Translations$intro$slides$plantare$pt extends Translations$intro$slides$plantare$en { + _Translations$intro$slides$plantare$pt._(TranslationsPt root) : this._root = root, super.internal(root); + + final TranslationsPt _root; // ignore: unused_field + + // Translations + @override String get title => 'Semear é multiplicar'; + @override String get body => 'Com um Plantare, quem recebe semente promete devolver uma parte mais tarde. E como devolvê-la implica cultivá-la, cada empréstimo multiplica o comum.'; +} + +/// The flat map containing all translations for locale . +/// Only for edge cases! For simple maps, use the map function of this library. +/// +/// The Dart AOT compiler has issues with very large switch statements, +/// so the map is split into smaller functions (512 entries each). +extension on TranslationsPt { + dynamic _flatMapFunction(String path) { + return switch (path) { + 'app.title' => 'Tanemaki', + 'common.save' => 'Guardar', + 'common.cancel' => 'Cancelar', + 'common.delete' => 'Eliminar', + 'common.edit' => 'Editar', + 'common.type' => 'Tipo', + 'common.comingSoon' => 'Em breve', + 'home.tagline' => 'Partilha e cultiva sementes locais', + 'home.openMarket' => 'Mercado aberto', + 'home.openMarketSubtitle' => 'Descobre e troca', + 'home.yourInventory' => 'O teu inventário', + 'home.yourInventorySubtitle' => 'Gere as tuas sementes', + 'photo.camera' => 'Tirar uma foto', + 'photo.gallery' => 'Escolher da galeria', + 'photo.setAsCover' => 'Usar como capa', + 'photo.isCover' => 'Foto de capa', + 'photo.deleteConfirm' => 'Eliminar esta foto?', + 'menu.tagline' => 'o teu banco de sementes', + 'menu.inventory' => 'Inventário', + 'menu.market' => 'Mercado', + 'menu.profile' => 'O teu perfil', + 'menu.chat' => 'Conversas', + 'menu.wishlist' => 'Lista de desejos', + 'menu.following' => 'A seguir', + 'menu.settings' => 'Definições', + 'settings.language' => 'Idioma', + 'settings.systemLanguage' => 'Idioma do sistema', + 'settings.langEs' => 'Español', + 'settings.langEn' => 'English', + 'settings.langPt' => 'Português', + 'settings.about' => 'Acerca de', + 'settings.aboutText' => 'Inventário local e cifrado para sementes tradicionais. AGPL-3.0.', + 'settings.aboutOpen' => 'Acerca do Tanemaki', + 'backup.title' => 'Cópia de segurança', + 'backup.exportJson' => 'Guardar uma cópia de segurança', + 'backup.exportJsonSubtitle' => 'Uma cópia completa para guardar em segurança, restaurar depois ou levar para outro aparelho', + 'backup.importJson' => 'Restaurar uma cópia', + 'backup.importJsonSubtitle' => 'Recupera uma cópia guardada — nada fica duplicado', + 'backup.exportCsv' => 'Exportar para uma folha de cálculo', + 'backup.exportCsvSubtitle' => 'Uma lista simples para Excel ou LibreOffice — sem fotos', + 'backup.importCsv' => 'Importar uma lista', + 'backup.importCsvSubtitle' => 'Acrescenta entradas a partir de uma folha de cálculo', + 'backup.importConfirmTitle' => 'Restaurar uma cópia?', + 'backup.importConfirmBody' => 'As entradas fundem-se com o teu inventário; quando a mesma entrada existe dos dois lados, vence a versão mais recente. Nada fica duplicado.', + 'backup.importCsvConfirmTitle' => 'Importar uma lista?', + 'backup.importCsvConfirmBody' => 'Cada linha é acrescentada como uma entrada nova. Não funde nem substitui, por isso importar o mesmo ficheiro duas vezes acrescenta-o duas vezes.', + 'backup.importAction' => 'Importar', + 'backup.exportSaved' => 'Cópia guardada', + 'backup.cancelled' => 'Cancelado', + 'backup.importDone' => ({required Object added, required Object updated}) => 'Importado: ${added} novas, ${updated} atualizadas', + 'backup.importCsvDone' => ({required Object count}) => '${count} entradas acrescentadas', + 'backup.importFailed' => 'Este ficheiro não pôde ser lido como uma cópia do Tanemaki', + 'backup.failed' => 'Algo correu mal', + 'backup.recoveryTitle' => 'O teu código de recuperação', + 'backup.recoverySubtitle' => 'Imprime-o e guarda-o bem: abre as tuas cópias noutro aparelho', + 'backup.recoveryIntro' => 'Este código abre as tuas cópias guardadas e recupera o teu banco em qualquer aparelho. Guarda duas cópias em papel em sítios seguros, como a tua melhor semente. Quem o tiver pode ler as tuas cópias, por isso não o partilhes com ninguém.', + 'backup.recoveryCopy' => 'Copiar', + 'backup.recoverySave' => 'Guardar a folha', + 'backup.recoverySheetTitle' => 'Tanemaki — a tua folha de recuperação', + 'backup.recoveryPromptTitle' => 'Escreve o teu código de recuperação', + 'backup.recoveryPromptBody' => 'Esta cópia foi guardada com outro código. Escreve o código da tua folha de recuperação para a abrir.', + 'backup.recoveryWrongCode' => 'Esse código não abre esta cópia', + 'about.title' => 'Acerca de', + 'about.kanji' => '種まき', + 'about.tagline' => 'Uma aplicação local e descentralizada para gerir e partilhar sementes e plântulas tradicionais.', + 'about.intro' => 'O Tanemaki (種まき, "semear / espalhar sementes" em japonês; nome curto Tane, 種 "semente") ajuda pessoas e coletivos a manter um inventário amigável do seu banco de sementes, decidir o que oferecem e partilhá-lo localmente — sem um intermediário central que possa controlar, censurar ou ser multado por isso. O objetivo é prático e político ao mesmo tempo: apoiar as variedades tradicionais e fazer frente ao monopólio das sementes.', + 'about.heritage' => 'O nome honra as antigas tradições japonesas de ajuda mútua à volta do arroz — yui (trabalho comunitário partilhado) e tanomoshi (fundos de reciprocidade) — que inspiraram o Plantare em papel, a "moeda comunitária de troca de sementes" (BAH-Semillero, 2009, CC-BY-SA). O Tanemaki é o Plantare digital.', + 'about.version' => 'Versão', + 'about.license' => 'Licença', + 'about.licenseValue' => 'AGPL-3.0', + 'about.website' => 'Sítio web', + 'about.openSourceLicenses' => 'Licenças de código aberto', + 'about.openSourceLicensesSubtitle' => 'Bibliotecas de terceiros e as suas licenças', + 'intro.skip' => 'Saltar', + 'intro.next' => 'Seguinte', + 'intro.start' => 'Começar', + 'intro.menuEntry' => 'Como funciona o Tanemaki', + 'intro.slides.welcome.title' => 'A semente que te trouxe até aqui', + 'intro.slides.welcome.body' => 'Cada semente tradicional é uma carta escrita por milhares de gerações, passada de mão em mão. Somos o que somos graças a essa partilha.', + 'intro.slides.inventory.title' => 'O teu banco de sementes, no bolso', + 'intro.slides.inventory.body' => 'Anota o que tens, de que ano, quanto e de onde veio — com o nome que tu usas. Uma foto e um nome chegam para começar.', + 'intro.slides.privacy.title' => 'Teu, e só teu', + 'intro.slides.privacy.body' => 'Sem conta, sem internet, sem rastreadores. Os teus dados vivem cifrados no teu aparelho, e só o que tu escolheres é partilhado.', + 'intro.slides.share.title' => 'Partilhar, como sempre se fez', + 'intro.slides.share.body' => 'Oferece o que te sobra — dar, trocar ou vender — e deixa que alguém perto de ti o encontre. Só se mostra uma distância aproximada, nunca a tua morada; o acordo fecha-se em pessoa.', + 'intro.slides.plantare.title' => 'Semear é multiplicar', + 'intro.slides.plantare.body' => 'Com um Plantare, quem recebe semente promete devolver uma parte mais tarde. E como devolvê-la implica cultivá-la, cada empréstimo multiplica o comum.', + 'inventory.title' => 'Inventário', + 'inventory.searchHint' => 'Procurar sementes', + 'inventory.empty' => 'Ainda não há sementes. Toca em + para adicionar a primeira.', + 'inventory.noMatches' => 'Nenhuma semente corresponde aos teus filtros.', + 'inventory.clearFilters' => 'Limpar filtros', + 'inventory.uncategorized' => 'Sem categoria', + 'inventory.needsReproductionFilter' => 'Para reproduzir', + 'draft.capture' => 'Capturar fotos', + 'draft.captured' => ({required Object n}) => '${n} capturadas para catalogar', + 'draft.triageTitle' => 'Para catalogar', + 'draft.triageCount' => ({required Object n}) => '${n} para catalogar', + 'draft.untitled' => 'Sem nome', + 'draft.nameField' => 'Dá um nome a esta semente', + 'draft.nameHint' => 'O que é?', + 'draft.suggestFromPhoto' => 'Sugerir nome a partir da foto', + 'draft.discard' => 'Descartar', + 'quickAdd.title' => 'Adicionar uma semente', + 'quickAdd.labelField' => 'Nome', + 'quickAdd.labelRequired' => 'Dá-lhe um nome', + 'quickAdd.addPhoto' => 'Adicionar foto', + 'quickAdd.quantity' => 'Quanto?', + 'quickAdd.more' => 'Adicionar mais…', + 'quickAdd.save' => 'Guardar', + 'quickAdd.saveAndAddAnother' => 'Guardar e adicionar outra', + 'quickAdd.addedCount' => ({required Object n}) => '${n} adicionadas', + 'quickAdd.cancel' => 'Cancelar', + 'detail.notFound' => 'Esta semente já não está aqui.', + 'detail.lots' => 'Lotes', + 'detail.noLots' => 'Ainda não há lotes.', + 'detail.names' => 'Também conhecida como', + 'detail.addName' => 'Adicionar nome', + 'detail.links' => 'Ligações', + 'detail.addLink' => 'Adicionar ligação', + 'detail.linkUrl' => 'URL', + 'detail.linkTitle' => 'Título (opcional)', + 'detail.notes' => 'Notas', + 'detail.addLot' => 'Adicionar lote', + 'detail.editLot' => 'Editar lote', + 'detail.deleteConfirm' => 'Eliminar esta semente?', + 'detail.year' => ({required Object year}) => 'Ano ${year}', + 'detail.noYear' => 'Ano desconhecido', + 'germination.title' => 'Germinação', + 'germination.add' => 'Adicionar teste', + 'germination.sampleSize' => 'Tamanho da amostra', + 'germination.germinated' => 'Germinadas', + 'germination.none' => 'Ainda não há testes de germinação.', + 'germination.result' => ({required Object percent}) => '${percent}%', + 'viability.expiringSoon' => 'Usa ou reproduz nesta época', + 'viability.expiringSoonYears' => ({required Object years}) => 'Usa ou reproduz nesta época · dura ~${years} anos', + 'viability.expired' => 'Passou a viabilidade típica — reproduzir', + 'viability.expiredYears' => ({required Object years}) => 'Passou a viabilidade típica (~${years} anos) — reproduzir', + 'editVariety.title' => 'Editar semente', + 'editVariety.name' => 'Nome', + 'editVariety.category' => 'Categoria', + 'editVariety.notes' => 'Notas', + 'editVariety.species' => 'Espécie (do catálogo)', + 'editVariety.speciesHint' => 'Procura uma espécie…', + 'editVariety.organic' => 'Biológica', + 'editVariety.organicHint' => 'Cultivada em modo biológico', + 'addLot.title' => 'Adicionar lote', + 'addLot.year' => 'Data de colheita', + 'addLot.quantity' => 'Quanto?', + 'addLot.amount' => 'Quantidade', + 'harvest.pickTitle' => 'Escolhe mês / ano', + 'harvest.anyMonth' => 'Qualquer mês', + 'harvest.noDate' => 'Definir data de colheita', + 'harvest.monthNames.0' => 'janeiro', + 'harvest.monthNames.1' => 'fevereiro', + 'harvest.monthNames.2' => 'março', + 'harvest.monthNames.3' => 'abril', + 'harvest.monthNames.4' => 'maio', + 'harvest.monthNames.5' => 'junho', + 'harvest.monthNames.6' => 'julho', + 'harvest.monthNames.7' => 'agosto', + 'harvest.monthNames.8' => 'setembro', + 'harvest.monthNames.9' => 'outubro', + 'harvest.monthNames.10' => 'novembro', + 'harvest.monthNames.11' => 'dezembro', + 'lotType.seed' => 'Sementes', + 'lotType.plant' => 'Planta', + 'lotType.seedling' => 'Plântula', + 'lotType.tree' => 'Árvore / arbusto', + 'lotType.bulb' => 'Bolbo / tubérculo', + 'lotType.cutting' => 'Estaca', + 'presentation.title' => 'Apresentação', + 'presentation.none' => 'Sem indicar', + 'presentation.pot' => 'Vaso', + 'presentation.tray' => 'Tabuleiro', + 'presentation.plug' => 'Alvéolo', + 'presentation.bareRoot' => 'Raiz nua', + 'presentation.rootBall' => 'Torrão', + 'provenance.section' => 'De onde vem', + 'provenance.seedsFrom' => 'Sementes de', + 'provenance.seedsFromHint' => 'Quem as cultivou ou ofereceu', + 'provenance.place' => 'Lugar', + 'provenance.placeHint' => 'De onde vêm (com a região)', + 'provenance.addSeedsFrom' => 'Sementes de', + 'provenance.addPlace' => 'Lugar', + 'abundance.add' => 'Quanta tenho', + 'abundance.title' => 'Quanta tenho', + 'abundance.none' => 'Sem indicar', + 'abundance.plentyToShare' => 'De sobra para partilhar', + 'abundance.enoughToShare' => 'Bastante, para partilhar com moderação', + 'abundance.enoughForMe' => 'Suficiente para mim', + 'abundance.runningLow' => 'Resta pouca', + 'share.add' => 'Partilhas esta?', + 'share.title' => 'Partilhas esta?', + 'share.nudge' => 'Tens de sobra: podias partilhar um pouco.', + 'share.private' => 'Só para mim', + 'share.gift' => 'Para dar', + 'share.exchange' => 'Para trocar', + 'share.sell' => 'À venda', + 'share.filterChip' => 'Partilho', + 'share.printCatalog' => 'Imprimir o que partilho', + 'share.catalogTitle' => 'O que partilho', + 'share.catalogSaved' => 'Catálogo guardado', + 'share.cancelled' => 'Cancelado', + 'cropCalendar.add' => 'Calendário de cultivo', + 'cropCalendar.title' => 'Calendário de cultivo', + 'cropCalendar.sow' => 'Sementeira', + 'cropCalendar.transplant' => 'Transplante', + 'cropCalendar.flowering' => 'Floração', + 'cropCalendar.fruiting' => 'Frutificação', + 'cropCalendar.seedHarvest' => 'Colheita de semente', + 'cropCalendar.unset' => '—', + 'needsReproduction.label' => 'Reproduzir nesta época', + 'needsReproduction.hint' => 'Cultiva-a antes que a semente acabe', + 'needsReproduction.badge' => 'Por reproduzir', + 'preservation.add' => 'Como está guardada', + 'preservation.title' => 'Como está guardada', + 'preservation.none' => 'Sem indicar', + 'preservation.jarWithDesiccant' => 'Frasco com agente secante', + 'preservation.glassJar' => 'Frasco de vidro', + 'preservation.paperEnvelope' => 'Envelope de papel', + 'preservation.paperBag' => 'Saco de papel', + 'preservation.plasticBag' => 'Saco de plástico', + 'conditionCheck.advanced' => 'Armazenamento e detalhes de banco de sementes', + 'conditionCheck.title' => 'Verificações de armazenamento', + 'conditionCheck.add' => 'Adicionar verificação', + 'conditionCheck.containers' => 'Frascos / recipientes', + 'conditionCheck.desiccant' => 'Agente secante', + 'conditionCheck.none' => 'Ainda não há verificações de armazenamento.', + 'conditionCheck.summary' => ({required Object count, required Object state}) => '${count} frasco(s) · ${state}', + 'desiccant.none' => 'Nenhum', + 'desiccant.add' => 'Adicionar', + 'desiccant.replace' => 'Substituir', + 'desiccant.dry' => 'Azul — seco', + 'desiccant.fresh' => 'Acabado de renovar', + 'unit.aFew' => 'algumas', + 'unit.some' => 'bastantes', + 'unit.plenty' => 'muitas', + 'unit.pinch' => 'uma pitada', + 'unit.handful.singular' => 'mão-cheia', + 'unit.handful.plural' => 'mãos-cheias', + 'unit.teaspoon.singular' => 'colher de chá', + 'unit.teaspoon.plural' => 'colheres de chá', + 'unit.spoon.singular' => 'colher', + 'unit.spoon.plural' => 'colheres', + 'unit.cup.singular' => 'chávena', + 'unit.cup.plural' => 'chávenas', + 'unit.jar.singular' => 'frasco', + 'unit.jar.plural' => 'frascos', + 'unit.sack.singular' => 'saco', + 'unit.sack.plural' => 'sacos', + 'unit.packet.singular' => 'pacote', + 'unit.packet.plural' => 'pacotes', + 'unit.cob.singular' => 'maçaroca', + 'unit.cob.plural' => 'maçarocas', + 'unit.pod.singular' => 'vagem', + 'unit.pod.plural' => 'vagens', + 'unit.ear.singular' => 'espiga', + 'unit.ear.plural' => 'espigas', + 'unit.head.singular' => 'cabeça', + 'unit.head.plural' => 'cabeças', + 'unit.fruit.singular' => 'fruto', + 'unit.fruit.plural' => 'frutos', + 'unit.bulb.singular' => 'bolbo', + 'unit.bulb.plural' => 'bolbos', + 'unit.tuber.singular' => 'tubérculo', + 'unit.tuber.plural' => 'tubérculos', + 'unit.seedHead.singular' => 'capítulo', + 'unit.seedHead.plural' => 'capítulos', + 'unit.bunch.singular' => 'molho', + 'unit.bunch.plural' => 'molhos', + 'unit.plant.singular' => 'planta', + 'unit.plant.plural' => 'plantas', + 'unit.pot.singular' => 'vaso', + 'unit.pot.plural' => 'vasos', + 'unit.tray.singular' => 'tabuleiro', + 'unit.tray.plural' => 'tabuleiros', + 'unit.seedling.singular' => 'plântula', + 'unit.seedling.plural' => 'plântulas', + 'unit.tree.singular' => 'árvore', + 'unit.tree.plural' => 'árvores', + 'unit.cutting.singular' => 'estaca', + 'unit.cutting.plural' => 'estacas', + 'unit.grams.singular' => 'grama', + 'unit.grams.plural' => 'gramas', + 'unit.count.singular' => 'semente', + 'unit.count.plural' => 'sementes', + _ => null, + }; + } +} diff --git a/apps/app_seeds/lib/ui/settings_screen.dart b/apps/app_seeds/lib/ui/settings_screen.dart index d044eb6..cdd8f7c 100644 --- a/apps/app_seeds/lib/ui/settings_screen.dart +++ b/apps/app_seeds/lib/ui/settings_screen.dart @@ -33,6 +33,11 @@ class SettingsScreen extends StatelessWidget { selected: current == 'en', onTap: () => LocaleSettings.setLocale(AppLocale.en), ), + _LanguageTile( + label: t.settings.langPt, + selected: current == 'pt', + onTap: () => LocaleSettings.setLocale(AppLocale.pt), + ), ListTile( leading: const Icon(Icons.smartphone_outlined), title: Text(t.settings.systemLanguage), diff --git a/apps/app_seeds/test/support/test_support.dart b/apps/app_seeds/test/support/test_support.dart index 55af651..c1e9685 100644 --- a/apps/app_seeds/test/support/test_support.dart +++ b/apps/app_seeds/test/support/test_support.dart @@ -60,6 +60,7 @@ Widget wrapScreen({ required VarietyRepository repository, required Widget child, AppLocale locale = AppLocale.en, + TextDirection? textDirection, }) { LocaleSettings.setLocaleSync(locale); return TranslationProvider( @@ -75,7 +76,9 @@ Widget wrapScreen({ GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - home: child, + home: textDirection == null + ? child + : Directionality(textDirection: textDirection, child: child), ), ), ), @@ -88,6 +91,7 @@ Widget wrapDetail({ required String varietyId, SpeciesRepository? species, AppLocale locale = AppLocale.en, + TextDirection? textDirection, }) { LocaleSettings.setLocaleSync(locale); return TranslationProvider( @@ -106,7 +110,12 @@ Widget wrapDetail({ GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], - home: const VarietyDetailScreen(), + home: textDirection == null + ? const VarietyDetailScreen() + : Directionality( + textDirection: textDirection, + child: const VarietyDetailScreen(), + ), ), ), ), diff --git a/apps/app_seeds/test/ui/rtl_smoke_test.dart b/apps/app_seeds/test/ui/rtl_smoke_test.dart new file mode 100644 index 0000000..06d636e --- /dev/null +++ b/apps/app_seeds/test/ui/rtl_smoke_test.dart @@ -0,0 +1,99 @@ +import 'package:commons_core/commons_core.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:tane/db/database.dart'; +import 'package:tane/db/enums.dart'; +import 'package:tane/ui/inventory_list_screen.dart'; +import 'package:tane/ui/settings_screen.dart'; + +import '../support/test_support.dart'; + +/// RTL is a first-class requirement (CLAUDE.md): the main screens must build +/// and lay out under right-to-left without overflowing or misplacing +/// directional affordances. Overflow errors fail these tests automatically. +void main() { + late AppDatabase db; + + setUp(() => db = newTestDatabase()); + tearDown(() => db.close()); + + testWidgets('the inventory list renders under RTL', (tester) async { + final repo = newTestRepository(db); + final id = await repo.addQuickVariety( + label: 'طماطم بلدية', // an Arabic label, as a keeper would write it + category: 'Solanaceae', + ); + await repo.addLot( + varietyId: id, + harvestYear: 2024, + quantity: const Quantity(kind: QuantityKind.handful), + offerStatus: OfferStatus.shared, + ); + await repo.addQuickVariety(label: 'Maize', category: 'Poaceae'); + + await tester.pumpWidget( + wrapScreen( + repository: repo, + textDirection: TextDirection.rtl, + child: const InventoryListScreen(), + ), + ); + await tester.pumpAndSettle(); + + expect(find.text('طماطم بلدية'), findsOneWidget); + expect(find.byKey(const Key('inventory.filter.sharing')), findsOneWidget); + await disposeTree(tester); + }); + + testWidgets('the variety detail (lots, calendar, names) renders under RTL', ( + tester, + ) async { + final repo = newTestRepository(db); + final id = await repo.addQuickVariety( + label: 'Grandma tomato', + category: 'Solanaceae', + ); + await repo.addVernacularName(id, 'طماطم'); + await repo.addLot( + varietyId: id, + harvestYear: 2023, + quantity: const Quantity(kind: QuantityKind.packet, count: 3), + abundance: Abundance.plentyToShare, + offerStatus: OfferStatus.exchange, + ); + + await tester.pumpWidget( + wrapDetail( + repository: repo, + varietyId: id, + species: newTestSpeciesRepository(db), + textDirection: TextDirection.rtl, + ), + ); + await tester.pumpAndSettle(); + + expect(find.text('Grandma tomato'), findsOneWidget); + expect(find.text('طماطم'), findsOneWidget); + + // The lot sheet (the busiest form) must also lay out under RTL. + await tester.tap(find.byKey(const Key('detail.addLot'))); + await tester.pumpAndSettle(); + expect(find.byKey(const Key('addLot.save')), findsOneWidget); + await disposeTree(tester); + }); + + testWidgets('settings renders under RTL', (tester) async { + final repo = newTestRepository(db); + await tester.pumpWidget( + wrapScreen( + repository: repo, + textDirection: TextDirection.rtl, + child: const SettingsScreen(), + ), + ); + await tester.pumpAndSettle(); + + expect(find.text('Português'), findsOneWidget); + await disposeTree(tester); + }); +} diff --git a/docs/i18n.md b/docs/i18n.md new file mode 100644 index 0000000..dd21deb --- /dev/null +++ b/docs/i18n.md @@ -0,0 +1,53 @@ +# Translating Tanemaki + +Tanemaki is multilingual **by design** — international, not any-country-first +(see the golden rules in [`../CLAUDE.md`](../CLAUDE.md)). Translations live as +one JSON file per locale, a format Weblate (and any translation platform that +speaks nested JSON) handles natively. + +## Where strings live + +``` +apps/app_seeds/lib/i18n/ + en.i18n.json ← base locale (source of truth for keys) + es.i18n.json + pt.i18n.json + strings*.g.dart ← generated, do not edit +``` + +- Placeholders use braces: `"{count} entries added"`. Keep them verbatim. +- Keys are code and never change per locale; only values are translated. +- Missing keys fall back to English at runtime (`fallback_strategy: + base_locale` in [`slang.yaml`](../apps/app_seeds/slang.yaml)), so a partial + translation is shippable from day one. + +## Adding a locale + +1. Copy `en.i18n.json` to `.i18n.json` (e.g. `fr.i18n.json`) and + translate what you can. +2. Regenerate the Dart bindings: + ```bash + cd apps/app_seeds && dart run slang + ``` +3. Add a language tile in + [`settings_screen.dart`](../apps/app_seeds/lib/ui/settings_screen.dart) + (label = the language's own name, e.g. "Français") plus the `langXx` key in + every locale file. +4. Run the tests: `flutter test` (an i18n test guards against hardcoded + strings; the RTL smoke test guards right-to-left layouts). + +## RTL and scripts + +Right-to-left locales (Arabic, Hebrew, Persian) are first-class: layouts use +directional insets and are exercised by +[`rtl_smoke_test.dart`](../apps/app_seeds/test/ui/rtl_smoke_test.dart). +Locale-specific resources ship with their locale, never hardcoded: OCR +language packs (`assets/tessdata/`), PDF fonts (`assets/fonts/`), and species +common names (`assets/catalog/species.json`, a locale-keyed map). + +## Weblate + +The JSON-per-locale layout is Weblate-ready (component per file, base +`en.i18n.json`). Hosting is not set up yet; when it is, this page will link +to the project. Until then, translation PRs/patches are welcome directly on +the files above.