feat(inventory): photo-first drafts + on-device OCR (digitization R2+R4)
Lower the bulk-digitization cliff with two more routes on top of the already-landed CSV import and "save and add another": - Photo-first drafts (capture now, catalogue later): burst-capture photos (camera or multi-gallery) into unnamed draft varieties, shown in a "to catalogue" tray, hidden from the main list until named. Adds Variety.isDraft (schema), addDraftVariety/watchDrafts/nameDraft, the triage sheet and the inventory banner. - On-device OCR label suggestion (Tesseract, offline, no Google): a "Suggest name from photo" button in the naming dialog behind a LabelTextExtractor interface (Tesseract on Android/iOS, no-op elsewhere). Reads the largest print via hOCR bounding boxes, drops boilerplate/low-confidence noise, preprocesses (grayscale, contrast, upscale) and sweeps rotations (0-315 deg) so tilted packets still read. Bundles tessdata_fast eng+spa; validated on-device against real packets. The photo is written to a temp file deleted immediately in a finally block (the plugin needs a path) - a bounded, documented exception to no-plaintext-at-rest. This commit also carries the co-developed schema evolution v5 to v8 that shares these files (organic flag, species viability years, crop calendar, lot provenance/abundance/preservation format, condition checks) plus their exports/migrations and i18n. Tests: CSV/draft/OCR unit + widget + migration green in isolation. Note: the full widget suite currently hangs (>10 min) - under investigation.
This commit is contained in:
parent
12a2ee2d64
commit
6809dc6143
89 changed files with 17141 additions and 228 deletions
|
|
@ -44,24 +44,24 @@
|
|||
"aboutOpen": "About Tanemaki"
|
||||
},
|
||||
"backup": {
|
||||
"title": "Backup",
|
||||
"exportCsv": "Export as CSV",
|
||||
"exportCsvSubtitle": "For spreadsheets — no photos",
|
||||
"exportJson": "Export as JSON",
|
||||
"exportJsonSubtitle": "Complete copy, can be imported back",
|
||||
"importJson": "Import from JSON",
|
||||
"importJsonSubtitle": "Merge a saved copy into this inventory",
|
||||
"importCsv": "Import from CSV",
|
||||
"importCsvSubtitle": "Add a list from a spreadsheet",
|
||||
"importConfirmTitle": "Import a saved copy?",
|
||||
"title": "Backup & restore",
|
||||
"exportJson": "Save a backup",
|
||||
"exportJsonSubtitle": "A complete copy to keep safe, restore later or move to another device",
|
||||
"importJson": "Restore a backup",
|
||||
"importJsonSubtitle": "Bring a saved copy back — nothing gets duplicated",
|
||||
"exportCsv": "Export to a spreadsheet",
|
||||
"exportCsvSubtitle": "A simple list for Excel or LibreOffice — no photos",
|
||||
"importCsv": "Import a list",
|
||||
"importCsvSubtitle": "Add entries from a spreadsheet",
|
||||
"importConfirmTitle": "Restore a backup?",
|
||||
"importConfirmBody": "Entries merge with your inventory; when the same entry exists on both sides, the newest version wins. Nothing gets duplicated.",
|
||||
"importCsvConfirmTitle": "Import a CSV list?",
|
||||
"importCsvConfirmTitle": "Import a list?",
|
||||
"importCsvConfirmBody": "Every row is added as a new entry. This does not merge or replace, so importing the same file twice adds it twice.",
|
||||
"importAction": "Import",
|
||||
"exportSaved": "Copy saved",
|
||||
"cancelled": "Cancelled",
|
||||
"importDone": "Imported: {added} new, {updated} updated",
|
||||
"importCsvDone": "Imported {count} from CSV",
|
||||
"importCsvDone": "Added {count} entries",
|
||||
"importFailed": "This file could not be read as a Tanemaki copy",
|
||||
"failed": "Something went wrong"
|
||||
},
|
||||
|
|
@ -112,7 +112,19 @@
|
|||
"empty": "No seeds yet. Tap + to add your first.",
|
||||
"noMatches": "No seeds match your filters.",
|
||||
"clearFilters": "Clear filters",
|
||||
"uncategorized": "Uncategorized"
|
||||
"uncategorized": "Uncategorized",
|
||||
"needsReproductionFilter": "To regrow"
|
||||
},
|
||||
"draft": {
|
||||
"capture": "Capture photos",
|
||||
"captured": "{n} captured to catalogue",
|
||||
"triageTitle": "To catalogue",
|
||||
"triageCount": "{n} to catalogue",
|
||||
"untitled": "Unnamed",
|
||||
"nameField": "Name this seed",
|
||||
"nameHint": "What is it?",
|
||||
"suggestFromPhoto": "Suggest name from photo",
|
||||
"discard": "Discard"
|
||||
},
|
||||
"quickAdd": {
|
||||
"title": "Add a seed",
|
||||
|
|
@ -151,13 +163,21 @@
|
|||
"none": "No germination tests yet.",
|
||||
"result": "{percent}%"
|
||||
},
|
||||
"viability": {
|
||||
"expiringSoon": "Use or reproduce this season",
|
||||
"expiringSoonYears": "Use or reproduce this season · keeps ~{years} yr",
|
||||
"expired": "Past typical viability — reproduce",
|
||||
"expiredYears": "Past typical viability (~{years} yr) — reproduce"
|
||||
},
|
||||
"editVariety": {
|
||||
"title": "Edit seed",
|
||||
"name": "Name",
|
||||
"category": "Category",
|
||||
"notes": "Notes",
|
||||
"species": "Species (from catalog)",
|
||||
"speciesHint": "Search a species…"
|
||||
"speciesHint": "Search a species…",
|
||||
"organic": "Organic",
|
||||
"organicHint": "Grown organically (eco)"
|
||||
},
|
||||
"addLot": {
|
||||
"title": "Add lot",
|
||||
|
|
@ -191,6 +211,65 @@
|
|||
"bareRoot": "Bare-root",
|
||||
"rootBall": "Root-ball"
|
||||
},
|
||||
"provenance": {
|
||||
"section": "Where it's from",
|
||||
"seedsFrom": "Seeds from",
|
||||
"seedsFromHint": "Who grew or gave them",
|
||||
"place": "Place",
|
||||
"placeHint": "Where they come from (with region)",
|
||||
"addSeedsFrom": "Seeds from",
|
||||
"addPlace": "Place"
|
||||
},
|
||||
"abundance": {
|
||||
"add": "How much I have",
|
||||
"title": "How much I have",
|
||||
"none": "Not set",
|
||||
"plentyToShare": "Plenty to share",
|
||||
"enoughToShare": "Enough to share a little",
|
||||
"enoughForMe": "Enough for me",
|
||||
"runningLow": "Running low"
|
||||
},
|
||||
"cropCalendar": {
|
||||
"add": "Crop calendar",
|
||||
"title": "Crop calendar",
|
||||
"sow": "Sow",
|
||||
"transplant": "Transplant",
|
||||
"flowering": "Flowering",
|
||||
"fruiting": "Fruiting",
|
||||
"seedHarvest": "Seed harvest",
|
||||
"unset": "—"
|
||||
},
|
||||
"needsReproduction": {
|
||||
"label": "To regrow this season",
|
||||
"hint": "Grow it out before the seed runs out",
|
||||
"badge": "To regrow"
|
||||
},
|
||||
"preservation": {
|
||||
"add": "How it's kept",
|
||||
"title": "How it's kept",
|
||||
"none": "Unspecified",
|
||||
"jarWithDesiccant": "Jar with drying agent",
|
||||
"glassJar": "Glass jar",
|
||||
"paperEnvelope": "Paper envelope",
|
||||
"paperBag": "Paper bag",
|
||||
"plasticBag": "Plastic bag"
|
||||
},
|
||||
"conditionCheck": {
|
||||
"advanced": "Storage & seed-bank details",
|
||||
"title": "Storage checks",
|
||||
"add": "Add check",
|
||||
"containers": "Jars / containers",
|
||||
"desiccant": "Drying agent",
|
||||
"none": "No storage checks yet.",
|
||||
"summary": "{count} jar(s) · {state}"
|
||||
},
|
||||
"desiccant": {
|
||||
"none": "None",
|
||||
"add": "Add some",
|
||||
"replace": "Replace it",
|
||||
"dry": "Blue — dry",
|
||||
"fresh": "Just renewed"
|
||||
},
|
||||
"unit": {
|
||||
"aFew": "a few",
|
||||
"some": "some",
|
||||
|
|
|
|||
|
|
@ -45,23 +45,23 @@
|
|||
},
|
||||
"backup": {
|
||||
"title": "Copia de seguridad",
|
||||
"exportCsv": "Exportar a CSV",
|
||||
"exportCsvSubtitle": "Para hojas de cálculo — sin fotos",
|
||||
"exportJson": "Exportar a JSON",
|
||||
"exportJsonSubtitle": "Copia completa, se puede volver a importar",
|
||||
"importJson": "Importar desde JSON",
|
||||
"importJsonSubtitle": "Fusiona una copia guardada con este inventario",
|
||||
"importCsv": "Importar desde CSV",
|
||||
"importCsvSubtitle": "Añade una lista desde una hoja de cálculo",
|
||||
"importConfirmTitle": "¿Importar una copia guardada?",
|
||||
"exportJson": "Guardar una copia de seguridad",
|
||||
"exportJsonSubtitle": "Una copia completa para guardar a salvo, restaurar luego o pasar a otro dispositivo",
|
||||
"importJson": "Restaurar una copia",
|
||||
"importJsonSubtitle": "Recupera una copia guardada — no se duplica nada",
|
||||
"exportCsv": "Exportar a una hoja de cálculo",
|
||||
"exportCsvSubtitle": "Una lista sencilla para Excel o LibreOffice — sin fotos",
|
||||
"importCsv": "Importar una lista",
|
||||
"importCsvSubtitle": "Añade entradas desde una hoja de cálculo",
|
||||
"importConfirmTitle": "¿Restaurar una copia?",
|
||||
"importConfirmBody": "Las entradas se fusionan con tu inventario; si una entrada existe en ambos lados, gana la versión más reciente. No se duplica nada.",
|
||||
"importCsvConfirmTitle": "¿Importar una lista CSV?",
|
||||
"importCsvConfirmTitle": "¿Importar una lista?",
|
||||
"importCsvConfirmBody": "Cada fila se añade como una entrada nueva. No fusiona ni reemplaza, así que importar el mismo fichero dos veces lo añade dos veces.",
|
||||
"importAction": "Importar",
|
||||
"exportSaved": "Copia guardada",
|
||||
"cancelled": "Cancelado",
|
||||
"importDone": "Importado: {added} nuevas, {updated} actualizadas",
|
||||
"importCsvDone": "Importadas {count} desde CSV",
|
||||
"importCsvDone": "Añadidas {count} entradas",
|
||||
"importFailed": "Este fichero no se pudo leer como una copia de Tanemaki",
|
||||
"failed": "Algo ha salido mal"
|
||||
},
|
||||
|
|
@ -112,7 +112,19 @@
|
|||
"empty": "Aún no hay semillas. Toca + para añadir la primera.",
|
||||
"noMatches": "Ninguna semilla coincide con los filtros.",
|
||||
"clearFilters": "Quitar filtros",
|
||||
"uncategorized": "Sin categoría"
|
||||
"uncategorized": "Sin categoría",
|
||||
"needsReproductionFilter": "Por reproducir"
|
||||
},
|
||||
"draft": {
|
||||
"capture": "Capturar fotos",
|
||||
"captured": "{n} capturadas por catalogar",
|
||||
"triageTitle": "Por catalogar",
|
||||
"triageCount": "{n} por catalogar",
|
||||
"untitled": "Sin nombre",
|
||||
"nameField": "Nombra esta semilla",
|
||||
"nameHint": "¿Qué es?",
|
||||
"suggestFromPhoto": "Sugerir nombre de la foto",
|
||||
"discard": "Descartar"
|
||||
},
|
||||
"quickAdd": {
|
||||
"title": "Añadir una semilla",
|
||||
|
|
@ -151,13 +163,21 @@
|
|||
"none": "Aún no hay pruebas de germinación.",
|
||||
"result": "{percent}%"
|
||||
},
|
||||
"viability": {
|
||||
"expiringSoon": "Úsala o multiplícala esta temporada",
|
||||
"expiringSoonYears": "Úsala o multiplícala esta temporada · dura ~{years} años",
|
||||
"expired": "Supera su viabilidad típica — a multiplicar",
|
||||
"expiredYears": "Supera su viabilidad típica (~{years} años) — a multiplicar"
|
||||
},
|
||||
"editVariety": {
|
||||
"title": "Editar semilla",
|
||||
"name": "Nombre",
|
||||
"category": "Categoría",
|
||||
"notes": "Notas",
|
||||
"species": "Especie (del catálogo)",
|
||||
"speciesHint": "Buscar una especie…"
|
||||
"speciesHint": "Buscar una especie…",
|
||||
"organic": "Ecológica",
|
||||
"organicHint": "Cultivada de forma ecológica (eco)"
|
||||
},
|
||||
"addLot": {
|
||||
"title": "Añadir lote",
|
||||
|
|
@ -191,6 +211,65 @@
|
|||
"bareRoot": "Raíz desnuda",
|
||||
"rootBall": "Cepellón"
|
||||
},
|
||||
"provenance": {
|
||||
"section": "De dónde viene",
|
||||
"seedsFrom": "Semillas de",
|
||||
"seedsFromHint": "Quién las cultivó o las dio",
|
||||
"place": "Lugar",
|
||||
"placeHint": "De dónde vienen (con provincia)",
|
||||
"addSeedsFrom": "Semillas de",
|
||||
"addPlace": "Lugar"
|
||||
},
|
||||
"abundance": {
|
||||
"add": "Cuánta tengo",
|
||||
"title": "Cuánta tengo",
|
||||
"none": "Sin indicar",
|
||||
"plentyToShare": "De sobra para compartir",
|
||||
"enoughToShare": "Bastante, para compartir con moderación",
|
||||
"enoughForMe": "Suficiente para mí",
|
||||
"runningLow": "Queda poca"
|
||||
},
|
||||
"cropCalendar": {
|
||||
"add": "Calendario de cultivo",
|
||||
"title": "Calendario de cultivo",
|
||||
"sow": "Siembra",
|
||||
"transplant": "Trasplante",
|
||||
"flowering": "Floración",
|
||||
"fruiting": "Fructificación",
|
||||
"seedHarvest": "Cosecha de semilla",
|
||||
"unset": "—"
|
||||
},
|
||||
"needsReproduction": {
|
||||
"label": "Reproducir esta temporada",
|
||||
"hint": "Cultívala antes de que se acabe la semilla",
|
||||
"badge": "Por reproducir"
|
||||
},
|
||||
"preservation": {
|
||||
"add": "Cómo se conserva",
|
||||
"title": "Cómo se conserva",
|
||||
"none": "Sin especificar",
|
||||
"jarWithDesiccant": "Bote con desecante",
|
||||
"glassJar": "Bote de cristal",
|
||||
"paperEnvelope": "Sobre de papel",
|
||||
"paperBag": "Bolsa de papel",
|
||||
"plasticBag": "Bolsa de plástico"
|
||||
},
|
||||
"conditionCheck": {
|
||||
"advanced": "Conservación y detalles del banco",
|
||||
"title": "Revisiones de conservación",
|
||||
"add": "Añadir revisión",
|
||||
"containers": "Botes / recipientes",
|
||||
"desiccant": "Desecante",
|
||||
"none": "Aún no hay revisiones.",
|
||||
"summary": "{count} bote(s) · {state}"
|
||||
},
|
||||
"desiccant": {
|
||||
"none": "No tiene",
|
||||
"add": "Se pone",
|
||||
"replace": "Se cambia",
|
||||
"dry": "Azul — seco",
|
||||
"fresh": "Recién puesto"
|
||||
},
|
||||
"unit": {
|
||||
"aFew": "unas pocas",
|
||||
"some": "algunas",
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
/// To regenerate, run: `dart run slang`
|
||||
///
|
||||
/// Locales: 2
|
||||
/// Strings: 408 (204 per locale)
|
||||
/// Strings: 530 (265 per locale)
|
||||
///
|
||||
/// Built on 2026-07-09 at 12:44 UTC
|
||||
/// Built on 2026-07-09 at 17:18 UTC
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: type=lint, unused_import
|
||||
|
|
|
|||
|
|
@ -50,14 +50,23 @@ class Translations with BaseTranslations<AppLocale, Translations> {
|
|||
late final Translations$about$en about = Translations$about$en.internal(_root);
|
||||
late final Translations$intro$en intro = Translations$intro$en.internal(_root);
|
||||
late final Translations$inventory$en inventory = Translations$inventory$en.internal(_root);
|
||||
late final Translations$draft$en draft = Translations$draft$en.internal(_root);
|
||||
late final Translations$quickAdd$en quickAdd = Translations$quickAdd$en.internal(_root);
|
||||
late final Translations$detail$en detail = Translations$detail$en.internal(_root);
|
||||
late final Translations$germination$en germination = Translations$germination$en.internal(_root);
|
||||
late final Translations$viability$en viability = Translations$viability$en.internal(_root);
|
||||
late final Translations$editVariety$en editVariety = Translations$editVariety$en.internal(_root);
|
||||
late final Translations$addLot$en addLot = Translations$addLot$en.internal(_root);
|
||||
late final Translations$harvest$en harvest = Translations$harvest$en.internal(_root);
|
||||
late final Translations$lotType$en lotType = Translations$lotType$en.internal(_root);
|
||||
late final Translations$presentation$en presentation = Translations$presentation$en.internal(_root);
|
||||
late final Translations$provenance$en provenance = Translations$provenance$en.internal(_root);
|
||||
late final Translations$abundance$en abundance = Translations$abundance$en.internal(_root);
|
||||
late final Translations$cropCalendar$en cropCalendar = Translations$cropCalendar$en.internal(_root);
|
||||
late final Translations$needsReproduction$en needsReproduction = Translations$needsReproduction$en.internal(_root);
|
||||
late final Translations$preservation$en preservation = Translations$preservation$en.internal(_root);
|
||||
late final Translations$conditionCheck$en conditionCheck = Translations$conditionCheck$en.internal(_root);
|
||||
late final Translations$desiccant$en desiccant = Translations$desiccant$en.internal(_root);
|
||||
late final Translations$unit$en unit = Translations$unit$en.internal(_root);
|
||||
}
|
||||
|
||||
|
|
@ -219,41 +228,41 @@ class Translations$backup$en {
|
|||
|
||||
// Translations
|
||||
|
||||
/// en: 'Backup'
|
||||
String get title => 'Backup';
|
||||
/// en: 'Backup & restore'
|
||||
String get title => 'Backup & restore';
|
||||
|
||||
/// en: 'Export as CSV'
|
||||
String get exportCsv => 'Export as CSV';
|
||||
/// en: 'Save a backup'
|
||||
String get exportJson => 'Save a backup';
|
||||
|
||||
/// en: 'For spreadsheets — no photos'
|
||||
String get exportCsvSubtitle => 'For spreadsheets — no photos';
|
||||
/// en: 'A complete copy to keep safe, restore later or move to another device'
|
||||
String get exportJsonSubtitle => 'A complete copy to keep safe, restore later or move to another device';
|
||||
|
||||
/// en: 'Export as JSON'
|
||||
String get exportJson => 'Export as JSON';
|
||||
/// en: 'Restore a backup'
|
||||
String get importJson => 'Restore a backup';
|
||||
|
||||
/// en: 'Complete copy, can be imported back'
|
||||
String get exportJsonSubtitle => 'Complete copy, can be imported back';
|
||||
/// en: 'Bring a saved copy back — nothing gets duplicated'
|
||||
String get importJsonSubtitle => 'Bring a saved copy back — nothing gets duplicated';
|
||||
|
||||
/// en: 'Import from JSON'
|
||||
String get importJson => 'Import from JSON';
|
||||
/// en: 'Export to a spreadsheet'
|
||||
String get exportCsv => 'Export to a spreadsheet';
|
||||
|
||||
/// en: 'Merge a saved copy into this inventory'
|
||||
String get importJsonSubtitle => 'Merge a saved copy into this inventory';
|
||||
/// en: 'A simple list for Excel or LibreOffice — no photos'
|
||||
String get exportCsvSubtitle => 'A simple list for Excel or LibreOffice — no photos';
|
||||
|
||||
/// en: 'Import from CSV'
|
||||
String get importCsv => 'Import from CSV';
|
||||
/// en: 'Import a list'
|
||||
String get importCsv => 'Import a list';
|
||||
|
||||
/// en: 'Add a list from a spreadsheet'
|
||||
String get importCsvSubtitle => 'Add a list from a spreadsheet';
|
||||
/// en: 'Add entries from a spreadsheet'
|
||||
String get importCsvSubtitle => 'Add entries from a spreadsheet';
|
||||
|
||||
/// en: 'Import a saved copy?'
|
||||
String get importConfirmTitle => 'Import a saved copy?';
|
||||
/// en: 'Restore a backup?'
|
||||
String get importConfirmTitle => 'Restore a backup?';
|
||||
|
||||
/// en: 'Entries merge with your inventory; when the same entry exists on both sides, the newest version wins. Nothing gets duplicated.'
|
||||
String get importConfirmBody => 'Entries merge with your inventory; when the same entry exists on both sides, the newest version wins. Nothing gets duplicated.';
|
||||
|
||||
/// en: 'Import a CSV list?'
|
||||
String get importCsvConfirmTitle => 'Import a CSV list?';
|
||||
/// en: 'Import a list?'
|
||||
String get importCsvConfirmTitle => 'Import a list?';
|
||||
|
||||
/// en: 'Every row is added as a new entry. This does not merge or replace, so importing the same file twice adds it twice.'
|
||||
String get importCsvConfirmBody => 'Every row is added as a new entry. This does not merge or replace, so importing the same file twice adds it twice.';
|
||||
|
|
@ -270,8 +279,8 @@ class Translations$backup$en {
|
|||
/// en: 'Imported: {added} new, {updated} updated'
|
||||
String importDone({required Object added, required Object updated}) => 'Imported: ${added} new, ${updated} updated';
|
||||
|
||||
/// en: 'Imported {count} from CSV'
|
||||
String importCsvDone({required Object count}) => 'Imported ${count} from CSV';
|
||||
/// en: 'Added {count} entries'
|
||||
String importCsvDone({required Object count}) => 'Added ${count} entries';
|
||||
|
||||
/// en: 'This file could not be read as a Tanemaki copy'
|
||||
String get importFailed => 'This file could not be read as a Tanemaki copy';
|
||||
|
|
@ -370,6 +379,45 @@ class Translations$inventory$en {
|
|||
|
||||
/// en: 'Uncategorized'
|
||||
String get uncategorized => 'Uncategorized';
|
||||
|
||||
/// en: 'To regrow'
|
||||
String get needsReproductionFilter => 'To regrow';
|
||||
}
|
||||
|
||||
// Path: draft
|
||||
class Translations$draft$en {
|
||||
Translations$draft$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Capture photos'
|
||||
String get capture => 'Capture photos';
|
||||
|
||||
/// en: '{n} captured to catalogue'
|
||||
String captured({required Object n}) => '${n} captured to catalogue';
|
||||
|
||||
/// en: 'To catalogue'
|
||||
String get triageTitle => 'To catalogue';
|
||||
|
||||
/// en: '{n} to catalogue'
|
||||
String triageCount({required Object n}) => '${n} to catalogue';
|
||||
|
||||
/// en: 'Unnamed'
|
||||
String get untitled => 'Unnamed';
|
||||
|
||||
/// en: 'Name this seed'
|
||||
String get nameField => 'Name this seed';
|
||||
|
||||
/// en: 'What is it?'
|
||||
String get nameHint => 'What is it?';
|
||||
|
||||
/// en: 'Suggest name from photo'
|
||||
String get suggestFromPhoto => 'Suggest name from photo';
|
||||
|
||||
/// en: 'Discard'
|
||||
String get discard => 'Discard';
|
||||
}
|
||||
|
||||
// Path: quickAdd
|
||||
|
|
@ -492,6 +540,27 @@ class Translations$germination$en {
|
|||
String result({required Object percent}) => '${percent}%';
|
||||
}
|
||||
|
||||
// Path: viability
|
||||
class Translations$viability$en {
|
||||
Translations$viability$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Use or reproduce this season'
|
||||
String get expiringSoon => 'Use or reproduce this season';
|
||||
|
||||
/// en: 'Use or reproduce this season · keeps ~{years} yr'
|
||||
String expiringSoonYears({required Object years}) => 'Use or reproduce this season · keeps ~${years} yr';
|
||||
|
||||
/// en: 'Past typical viability — reproduce'
|
||||
String get expired => 'Past typical viability — reproduce';
|
||||
|
||||
/// en: 'Past typical viability (~{years} yr) — reproduce'
|
||||
String expiredYears({required Object years}) => 'Past typical viability (~${years} yr) — reproduce';
|
||||
}
|
||||
|
||||
// Path: editVariety
|
||||
class Translations$editVariety$en {
|
||||
Translations$editVariety$en.internal(this._root);
|
||||
|
|
@ -517,6 +586,12 @@ class Translations$editVariety$en {
|
|||
|
||||
/// en: 'Search a species…'
|
||||
String get speciesHint => 'Search a species…';
|
||||
|
||||
/// en: 'Organic'
|
||||
String get organic => 'Organic';
|
||||
|
||||
/// en: 'Grown organically (eco)'
|
||||
String get organicHint => 'Grown organically (eco)';
|
||||
}
|
||||
|
||||
// Path: addLot
|
||||
|
|
@ -630,6 +705,204 @@ class Translations$presentation$en {
|
|||
String get rootBall => 'Root-ball';
|
||||
}
|
||||
|
||||
// Path: provenance
|
||||
class Translations$provenance$en {
|
||||
Translations$provenance$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Where it's from'
|
||||
String get section => 'Where it\'s from';
|
||||
|
||||
/// en: 'Seeds from'
|
||||
String get seedsFrom => 'Seeds from';
|
||||
|
||||
/// en: 'Who grew or gave them'
|
||||
String get seedsFromHint => 'Who grew or gave them';
|
||||
|
||||
/// en: 'Place'
|
||||
String get place => 'Place';
|
||||
|
||||
/// en: 'Where they come from (with region)'
|
||||
String get placeHint => 'Where they come from (with region)';
|
||||
|
||||
/// en: 'Seeds from'
|
||||
String get addSeedsFrom => 'Seeds from';
|
||||
|
||||
/// en: 'Place'
|
||||
String get addPlace => 'Place';
|
||||
}
|
||||
|
||||
// Path: abundance
|
||||
class Translations$abundance$en {
|
||||
Translations$abundance$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'How much I have'
|
||||
String get add => 'How much I have';
|
||||
|
||||
/// en: 'How much I have'
|
||||
String get title => 'How much I have';
|
||||
|
||||
/// en: 'Not set'
|
||||
String get none => 'Not set';
|
||||
|
||||
/// en: 'Plenty to share'
|
||||
String get plentyToShare => 'Plenty to share';
|
||||
|
||||
/// en: 'Enough to share a little'
|
||||
String get enoughToShare => 'Enough to share a little';
|
||||
|
||||
/// en: 'Enough for me'
|
||||
String get enoughForMe => 'Enough for me';
|
||||
|
||||
/// en: 'Running low'
|
||||
String get runningLow => 'Running low';
|
||||
}
|
||||
|
||||
// Path: cropCalendar
|
||||
class Translations$cropCalendar$en {
|
||||
Translations$cropCalendar$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Crop calendar'
|
||||
String get add => 'Crop calendar';
|
||||
|
||||
/// en: 'Crop calendar'
|
||||
String get title => 'Crop calendar';
|
||||
|
||||
/// en: 'Sow'
|
||||
String get sow => 'Sow';
|
||||
|
||||
/// en: 'Transplant'
|
||||
String get transplant => 'Transplant';
|
||||
|
||||
/// en: 'Flowering'
|
||||
String get flowering => 'Flowering';
|
||||
|
||||
/// en: 'Fruiting'
|
||||
String get fruiting => 'Fruiting';
|
||||
|
||||
/// en: 'Seed harvest'
|
||||
String get seedHarvest => 'Seed harvest';
|
||||
|
||||
/// en: '—'
|
||||
String get unset => '—';
|
||||
}
|
||||
|
||||
// Path: needsReproduction
|
||||
class Translations$needsReproduction$en {
|
||||
Translations$needsReproduction$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'To regrow this season'
|
||||
String get label => 'To regrow this season';
|
||||
|
||||
/// en: 'Grow it out before the seed runs out'
|
||||
String get hint => 'Grow it out before the seed runs out';
|
||||
|
||||
/// en: 'To regrow'
|
||||
String get badge => 'To regrow';
|
||||
}
|
||||
|
||||
// Path: preservation
|
||||
class Translations$preservation$en {
|
||||
Translations$preservation$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'How it's kept'
|
||||
String get add => 'How it\'s kept';
|
||||
|
||||
/// en: 'How it's kept'
|
||||
String get title => 'How it\'s kept';
|
||||
|
||||
/// en: 'Unspecified'
|
||||
String get none => 'Unspecified';
|
||||
|
||||
/// en: 'Jar with drying agent'
|
||||
String get jarWithDesiccant => 'Jar with drying agent';
|
||||
|
||||
/// en: 'Glass jar'
|
||||
String get glassJar => 'Glass jar';
|
||||
|
||||
/// en: 'Paper envelope'
|
||||
String get paperEnvelope => 'Paper envelope';
|
||||
|
||||
/// en: 'Paper bag'
|
||||
String get paperBag => 'Paper bag';
|
||||
|
||||
/// en: 'Plastic bag'
|
||||
String get plasticBag => 'Plastic bag';
|
||||
}
|
||||
|
||||
// Path: conditionCheck
|
||||
class Translations$conditionCheck$en {
|
||||
Translations$conditionCheck$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'Storage & seed-bank details'
|
||||
String get advanced => 'Storage & seed-bank details';
|
||||
|
||||
/// en: 'Storage checks'
|
||||
String get title => 'Storage checks';
|
||||
|
||||
/// en: 'Add check'
|
||||
String get add => 'Add check';
|
||||
|
||||
/// en: 'Jars / containers'
|
||||
String get containers => 'Jars / containers';
|
||||
|
||||
/// en: 'Drying agent'
|
||||
String get desiccant => 'Drying agent';
|
||||
|
||||
/// en: 'No storage checks yet.'
|
||||
String get none => 'No storage checks yet.';
|
||||
|
||||
/// en: '{count} jar(s) · {state}'
|
||||
String summary({required Object count, required Object state}) => '${count} jar(s) · ${state}';
|
||||
}
|
||||
|
||||
// Path: desiccant
|
||||
class Translations$desiccant$en {
|
||||
Translations$desiccant$en.internal(this._root);
|
||||
|
||||
final Translations _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
|
||||
/// en: 'None'
|
||||
String get none => 'None';
|
||||
|
||||
/// en: 'Add some'
|
||||
String get add => 'Add some';
|
||||
|
||||
/// en: 'Replace it'
|
||||
String get replace => 'Replace it';
|
||||
|
||||
/// en: 'Blue — dry'
|
||||
String get dry => 'Blue — dry';
|
||||
|
||||
/// en: 'Just renewed'
|
||||
String get fresh => 'Just renewed';
|
||||
}
|
||||
|
||||
// Path: unit
|
||||
class Translations$unit$en {
|
||||
Translations$unit$en.internal(this._root);
|
||||
|
|
@ -1165,24 +1438,24 @@ extension on Translations {
|
|||
'settings.about' => 'About',
|
||||
'settings.aboutText' => 'Local-first, encrypted inventory for traditional seeds. AGPL-3.0.',
|
||||
'settings.aboutOpen' => 'About Tanemaki',
|
||||
'backup.title' => 'Backup',
|
||||
'backup.exportCsv' => 'Export as CSV',
|
||||
'backup.exportCsvSubtitle' => 'For spreadsheets — no photos',
|
||||
'backup.exportJson' => 'Export as JSON',
|
||||
'backup.exportJsonSubtitle' => 'Complete copy, can be imported back',
|
||||
'backup.importJson' => 'Import from JSON',
|
||||
'backup.importJsonSubtitle' => 'Merge a saved copy into this inventory',
|
||||
'backup.importCsv' => 'Import from CSV',
|
||||
'backup.importCsvSubtitle' => 'Add a list from a spreadsheet',
|
||||
'backup.importConfirmTitle' => 'Import a saved copy?',
|
||||
'backup.title' => 'Backup & restore',
|
||||
'backup.exportJson' => 'Save a backup',
|
||||
'backup.exportJsonSubtitle' => 'A complete copy to keep safe, restore later or move to another device',
|
||||
'backup.importJson' => 'Restore a backup',
|
||||
'backup.importJsonSubtitle' => 'Bring a saved copy back — nothing gets duplicated',
|
||||
'backup.exportCsv' => 'Export to a spreadsheet',
|
||||
'backup.exportCsvSubtitle' => 'A simple list for Excel or LibreOffice — no photos',
|
||||
'backup.importCsv' => 'Import a list',
|
||||
'backup.importCsvSubtitle' => 'Add entries from a spreadsheet',
|
||||
'backup.importConfirmTitle' => 'Restore a backup?',
|
||||
'backup.importConfirmBody' => 'Entries merge with your inventory; when the same entry exists on both sides, the newest version wins. Nothing gets duplicated.',
|
||||
'backup.importCsvConfirmTitle' => 'Import a CSV list?',
|
||||
'backup.importCsvConfirmTitle' => 'Import a list?',
|
||||
'backup.importCsvConfirmBody' => 'Every row is added as a new entry. This does not merge or replace, so importing the same file twice adds it twice.',
|
||||
'backup.importAction' => 'Import',
|
||||
'backup.exportSaved' => 'Copy saved',
|
||||
'backup.cancelled' => 'Cancelled',
|
||||
'backup.importDone' => ({required Object added, required Object updated}) => 'Imported: ${added} new, ${updated} updated',
|
||||
'backup.importCsvDone' => ({required Object count}) => 'Imported ${count} from CSV',
|
||||
'backup.importCsvDone' => ({required Object count}) => 'Added ${count} entries',
|
||||
'backup.importFailed' => 'This file could not be read as a Tanemaki copy',
|
||||
'backup.failed' => 'Something went wrong',
|
||||
'about.title' => 'About',
|
||||
|
|
@ -1216,6 +1489,16 @@ extension on Translations {
|
|||
'inventory.noMatches' => 'No seeds match your filters.',
|
||||
'inventory.clearFilters' => 'Clear filters',
|
||||
'inventory.uncategorized' => 'Uncategorized',
|
||||
'inventory.needsReproductionFilter' => 'To regrow',
|
||||
'draft.capture' => 'Capture photos',
|
||||
'draft.captured' => ({required Object n}) => '${n} captured to catalogue',
|
||||
'draft.triageTitle' => 'To catalogue',
|
||||
'draft.triageCount' => ({required Object n}) => '${n} to catalogue',
|
||||
'draft.untitled' => 'Unnamed',
|
||||
'draft.nameField' => 'Name this seed',
|
||||
'draft.nameHint' => 'What is it?',
|
||||
'draft.suggestFromPhoto' => 'Suggest name from photo',
|
||||
'draft.discard' => 'Discard',
|
||||
'quickAdd.title' => 'Add a seed',
|
||||
'quickAdd.labelField' => 'Name',
|
||||
'quickAdd.labelRequired' => 'Give it a name',
|
||||
|
|
@ -1247,12 +1530,18 @@ extension on Translations {
|
|||
'germination.germinated' => 'Germinated',
|
||||
'germination.none' => 'No germination tests yet.',
|
||||
'germination.result' => ({required Object percent}) => '${percent}%',
|
||||
'viability.expiringSoon' => 'Use or reproduce this season',
|
||||
'viability.expiringSoonYears' => ({required Object years}) => 'Use or reproduce this season · keeps ~${years} yr',
|
||||
'viability.expired' => 'Past typical viability — reproduce',
|
||||
'viability.expiredYears' => ({required Object years}) => 'Past typical viability (~${years} yr) — reproduce',
|
||||
'editVariety.title' => 'Edit seed',
|
||||
'editVariety.name' => 'Name',
|
||||
'editVariety.category' => 'Category',
|
||||
'editVariety.notes' => 'Notes',
|
||||
'editVariety.species' => 'Species (from catalog)',
|
||||
'editVariety.speciesHint' => 'Search a species…',
|
||||
'editVariety.organic' => 'Organic',
|
||||
'editVariety.organicHint' => 'Grown organically (eco)',
|
||||
'addLot.title' => 'Add lot',
|
||||
'addLot.year' => 'Harvest date',
|
||||
'addLot.quantity' => 'How much?',
|
||||
|
|
@ -1285,6 +1574,51 @@ extension on Translations {
|
|||
'presentation.plug' => 'Plug',
|
||||
'presentation.bareRoot' => 'Bare-root',
|
||||
'presentation.rootBall' => 'Root-ball',
|
||||
'provenance.section' => 'Where it\'s from',
|
||||
'provenance.seedsFrom' => 'Seeds from',
|
||||
'provenance.seedsFromHint' => 'Who grew or gave them',
|
||||
'provenance.place' => 'Place',
|
||||
'provenance.placeHint' => 'Where they come from (with region)',
|
||||
'provenance.addSeedsFrom' => 'Seeds from',
|
||||
'provenance.addPlace' => 'Place',
|
||||
'abundance.add' => 'How much I have',
|
||||
'abundance.title' => 'How much I have',
|
||||
'abundance.none' => 'Not set',
|
||||
'abundance.plentyToShare' => 'Plenty to share',
|
||||
'abundance.enoughToShare' => 'Enough to share a little',
|
||||
'abundance.enoughForMe' => 'Enough for me',
|
||||
'abundance.runningLow' => 'Running low',
|
||||
'cropCalendar.add' => 'Crop calendar',
|
||||
'cropCalendar.title' => 'Crop calendar',
|
||||
'cropCalendar.sow' => 'Sow',
|
||||
'cropCalendar.transplant' => 'Transplant',
|
||||
'cropCalendar.flowering' => 'Flowering',
|
||||
'cropCalendar.fruiting' => 'Fruiting',
|
||||
'cropCalendar.seedHarvest' => 'Seed harvest',
|
||||
'cropCalendar.unset' => '—',
|
||||
'needsReproduction.label' => 'To regrow this season',
|
||||
'needsReproduction.hint' => 'Grow it out before the seed runs out',
|
||||
'needsReproduction.badge' => 'To regrow',
|
||||
'preservation.add' => 'How it\'s kept',
|
||||
'preservation.title' => 'How it\'s kept',
|
||||
'preservation.none' => 'Unspecified',
|
||||
'preservation.jarWithDesiccant' => 'Jar with drying agent',
|
||||
'preservation.glassJar' => 'Glass jar',
|
||||
'preservation.paperEnvelope' => 'Paper envelope',
|
||||
'preservation.paperBag' => 'Paper bag',
|
||||
'preservation.plasticBag' => 'Plastic bag',
|
||||
'conditionCheck.advanced' => 'Storage & seed-bank details',
|
||||
'conditionCheck.title' => 'Storage checks',
|
||||
'conditionCheck.add' => 'Add check',
|
||||
'conditionCheck.containers' => 'Jars / containers',
|
||||
'conditionCheck.desiccant' => 'Drying agent',
|
||||
'conditionCheck.none' => 'No storage checks yet.',
|
||||
'conditionCheck.summary' => ({required Object count, required Object state}) => '${count} jar(s) · ${state}',
|
||||
'desiccant.none' => 'None',
|
||||
'desiccant.add' => 'Add some',
|
||||
'desiccant.replace' => 'Replace it',
|
||||
'desiccant.dry' => 'Blue — dry',
|
||||
'desiccant.fresh' => 'Just renewed',
|
||||
'unit.aFew' => 'a few',
|
||||
'unit.some' => 'some',
|
||||
'unit.plenty' => 'plenty',
|
||||
|
|
|
|||
|
|
@ -49,14 +49,23 @@ class TranslationsEs extends Translations with BaseTranslations<AppLocale, Trans
|
|||
@override late final _Translations$about$es about = _Translations$about$es._(_root);
|
||||
@override late final _Translations$intro$es intro = _Translations$intro$es._(_root);
|
||||
@override late final _Translations$inventory$es inventory = _Translations$inventory$es._(_root);
|
||||
@override late final _Translations$draft$es draft = _Translations$draft$es._(_root);
|
||||
@override late final _Translations$quickAdd$es quickAdd = _Translations$quickAdd$es._(_root);
|
||||
@override late final _Translations$detail$es detail = _Translations$detail$es._(_root);
|
||||
@override late final _Translations$germination$es germination = _Translations$germination$es._(_root);
|
||||
@override late final _Translations$viability$es viability = _Translations$viability$es._(_root);
|
||||
@override late final _Translations$editVariety$es editVariety = _Translations$editVariety$es._(_root);
|
||||
@override late final _Translations$addLot$es addLot = _Translations$addLot$es._(_root);
|
||||
@override late final _Translations$harvest$es harvest = _Translations$harvest$es._(_root);
|
||||
@override late final _Translations$lotType$es lotType = _Translations$lotType$es._(_root);
|
||||
@override late final _Translations$presentation$es presentation = _Translations$presentation$es._(_root);
|
||||
@override late final _Translations$provenance$es provenance = _Translations$provenance$es._(_root);
|
||||
@override late final _Translations$abundance$es abundance = _Translations$abundance$es._(_root);
|
||||
@override late final _Translations$cropCalendar$es cropCalendar = _Translations$cropCalendar$es._(_root);
|
||||
@override late final _Translations$needsReproduction$es needsReproduction = _Translations$needsReproduction$es._(_root);
|
||||
@override late final _Translations$preservation$es preservation = _Translations$preservation$es._(_root);
|
||||
@override late final _Translations$conditionCheck$es conditionCheck = _Translations$conditionCheck$es._(_root);
|
||||
@override late final _Translations$desiccant$es desiccant = _Translations$desiccant$es._(_root);
|
||||
@override late final _Translations$unit$es unit = _Translations$unit$es._(_root);
|
||||
}
|
||||
|
||||
|
|
@ -154,23 +163,23 @@ class _Translations$backup$es extends Translations$backup$en {
|
|||
|
||||
// Translations
|
||||
@override String get title => 'Copia de seguridad';
|
||||
@override String get exportCsv => 'Exportar a CSV';
|
||||
@override String get exportCsvSubtitle => 'Para hojas de cálculo — sin fotos';
|
||||
@override String get exportJson => 'Exportar a JSON';
|
||||
@override String get exportJsonSubtitle => 'Copia completa, se puede volver a importar';
|
||||
@override String get importJson => 'Importar desde JSON';
|
||||
@override String get importJsonSubtitle => 'Fusiona una copia guardada con este inventario';
|
||||
@override String get importCsv => 'Importar desde CSV';
|
||||
@override String get importCsvSubtitle => 'Añade una lista desde una hoja de cálculo';
|
||||
@override String get importConfirmTitle => '¿Importar una copia guardada?';
|
||||
@override String get exportJson => 'Guardar una copia de seguridad';
|
||||
@override String get exportJsonSubtitle => 'Una copia completa para guardar a salvo, restaurar luego o pasar a otro dispositivo';
|
||||
@override String get importJson => 'Restaurar una copia';
|
||||
@override String get importJsonSubtitle => 'Recupera una copia guardada — no se duplica nada';
|
||||
@override String get exportCsv => 'Exportar a una hoja de cálculo';
|
||||
@override String get exportCsvSubtitle => 'Una lista sencilla para Excel o LibreOffice — sin fotos';
|
||||
@override String get importCsv => 'Importar una lista';
|
||||
@override String get importCsvSubtitle => 'Añade entradas desde una hoja de cálculo';
|
||||
@override String get importConfirmTitle => '¿Restaurar una copia?';
|
||||
@override String get importConfirmBody => 'Las entradas se fusionan con tu inventario; si una entrada existe en ambos lados, gana la versión más reciente. No se duplica nada.';
|
||||
@override String get importCsvConfirmTitle => '¿Importar una lista CSV?';
|
||||
@override String get importCsvConfirmTitle => '¿Importar una lista?';
|
||||
@override String get importCsvConfirmBody => 'Cada fila se añade como una entrada nueva. No fusiona ni reemplaza, así que importar el mismo fichero dos veces lo añade dos veces.';
|
||||
@override String get importAction => 'Importar';
|
||||
@override String get exportSaved => 'Copia guardada';
|
||||
@override String get cancelled => 'Cancelado';
|
||||
@override String importDone({required Object added, required Object updated}) => 'Importado: ${added} nuevas, ${updated} actualizadas';
|
||||
@override String importCsvDone({required Object count}) => 'Importadas ${count} desde CSV';
|
||||
@override String importCsvDone({required Object count}) => 'Añadidas ${count} entradas';
|
||||
@override String get importFailed => 'Este fichero no se pudo leer como una copia de Tanemaki';
|
||||
@override String get failed => 'Algo ha salido mal';
|
||||
}
|
||||
|
|
@ -222,6 +231,25 @@ class _Translations$inventory$es extends Translations$inventory$en {
|
|||
@override String get noMatches => 'Ninguna semilla coincide con los filtros.';
|
||||
@override String get clearFilters => 'Quitar filtros';
|
||||
@override String get uncategorized => 'Sin categoría';
|
||||
@override String get needsReproductionFilter => 'Por reproducir';
|
||||
}
|
||||
|
||||
// Path: draft
|
||||
class _Translations$draft$es extends Translations$draft$en {
|
||||
_Translations$draft$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get capture => 'Capturar fotos';
|
||||
@override String captured({required Object n}) => '${n} capturadas por catalogar';
|
||||
@override String get triageTitle => 'Por catalogar';
|
||||
@override String triageCount({required Object n}) => '${n} por catalogar';
|
||||
@override String get untitled => 'Sin nombre';
|
||||
@override String get nameField => 'Nombra esta semilla';
|
||||
@override String get nameHint => '¿Qué es?';
|
||||
@override String get suggestFromPhoto => 'Sugerir nombre de la foto';
|
||||
@override String get discard => 'Descartar';
|
||||
}
|
||||
|
||||
// Path: quickAdd
|
||||
|
|
@ -282,6 +310,19 @@ class _Translations$germination$es extends Translations$germination$en {
|
|||
@override String result({required Object percent}) => '${percent}%';
|
||||
}
|
||||
|
||||
// Path: viability
|
||||
class _Translations$viability$es extends Translations$viability$en {
|
||||
_Translations$viability$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get expiringSoon => 'Úsala o multiplícala esta temporada';
|
||||
@override String expiringSoonYears({required Object years}) => 'Úsala o multiplícala esta temporada · dura ~${years} años';
|
||||
@override String get expired => 'Supera su viabilidad típica — a multiplicar';
|
||||
@override String expiredYears({required Object years}) => 'Supera su viabilidad típica (~${years} años) — a multiplicar';
|
||||
}
|
||||
|
||||
// Path: editVariety
|
||||
class _Translations$editVariety$es extends Translations$editVariety$en {
|
||||
_Translations$editVariety$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
|
@ -295,6 +336,8 @@ class _Translations$editVariety$es extends Translations$editVariety$en {
|
|||
@override String get notes => 'Notas';
|
||||
@override String get species => 'Especie (del catálogo)';
|
||||
@override String get speciesHint => 'Buscar una especie…';
|
||||
@override String get organic => 'Ecológica';
|
||||
@override String get organicHint => 'Cultivada de forma ecológica (eco)';
|
||||
}
|
||||
|
||||
// Path: addLot
|
||||
|
|
@ -367,6 +410,114 @@ class _Translations$presentation$es extends Translations$presentation$en {
|
|||
@override String get rootBall => 'Cepellón';
|
||||
}
|
||||
|
||||
// Path: provenance
|
||||
class _Translations$provenance$es extends Translations$provenance$en {
|
||||
_Translations$provenance$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get section => 'De dónde viene';
|
||||
@override String get seedsFrom => 'Semillas de';
|
||||
@override String get seedsFromHint => 'Quién las cultivó o las dio';
|
||||
@override String get place => 'Lugar';
|
||||
@override String get placeHint => 'De dónde vienen (con provincia)';
|
||||
@override String get addSeedsFrom => 'Semillas de';
|
||||
@override String get addPlace => 'Lugar';
|
||||
}
|
||||
|
||||
// Path: abundance
|
||||
class _Translations$abundance$es extends Translations$abundance$en {
|
||||
_Translations$abundance$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get add => 'Cuánta tengo';
|
||||
@override String get title => 'Cuánta tengo';
|
||||
@override String get none => 'Sin indicar';
|
||||
@override String get plentyToShare => 'De sobra para compartir';
|
||||
@override String get enoughToShare => 'Bastante, para compartir con moderación';
|
||||
@override String get enoughForMe => 'Suficiente para mí';
|
||||
@override String get runningLow => 'Queda poca';
|
||||
}
|
||||
|
||||
// Path: cropCalendar
|
||||
class _Translations$cropCalendar$es extends Translations$cropCalendar$en {
|
||||
_Translations$cropCalendar$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get add => 'Calendario de cultivo';
|
||||
@override String get title => 'Calendario de cultivo';
|
||||
@override String get sow => 'Siembra';
|
||||
@override String get transplant => 'Trasplante';
|
||||
@override String get flowering => 'Floración';
|
||||
@override String get fruiting => 'Fructificación';
|
||||
@override String get seedHarvest => 'Cosecha de semilla';
|
||||
@override String get unset => '—';
|
||||
}
|
||||
|
||||
// Path: needsReproduction
|
||||
class _Translations$needsReproduction$es extends Translations$needsReproduction$en {
|
||||
_Translations$needsReproduction$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get label => 'Reproducir esta temporada';
|
||||
@override String get hint => 'Cultívala antes de que se acabe la semilla';
|
||||
@override String get badge => 'Por reproducir';
|
||||
}
|
||||
|
||||
// Path: preservation
|
||||
class _Translations$preservation$es extends Translations$preservation$en {
|
||||
_Translations$preservation$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get add => 'Cómo se conserva';
|
||||
@override String get title => 'Cómo se conserva';
|
||||
@override String get none => 'Sin especificar';
|
||||
@override String get jarWithDesiccant => 'Bote con desecante';
|
||||
@override String get glassJar => 'Bote de cristal';
|
||||
@override String get paperEnvelope => 'Sobre de papel';
|
||||
@override String get paperBag => 'Bolsa de papel';
|
||||
@override String get plasticBag => 'Bolsa de plástico';
|
||||
}
|
||||
|
||||
// Path: conditionCheck
|
||||
class _Translations$conditionCheck$es extends Translations$conditionCheck$en {
|
||||
_Translations$conditionCheck$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get advanced => 'Conservación y detalles del banco';
|
||||
@override String get title => 'Revisiones de conservación';
|
||||
@override String get add => 'Añadir revisión';
|
||||
@override String get containers => 'Botes / recipientes';
|
||||
@override String get desiccant => 'Desecante';
|
||||
@override String get none => 'Aún no hay revisiones.';
|
||||
@override String summary({required Object count, required Object state}) => '${count} bote(s) · ${state}';
|
||||
}
|
||||
|
||||
// Path: desiccant
|
||||
class _Translations$desiccant$es extends Translations$desiccant$en {
|
||||
_Translations$desiccant$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
||||
final TranslationsEs _root; // ignore: unused_field
|
||||
|
||||
// Translations
|
||||
@override String get none => 'No tiene';
|
||||
@override String get add => 'Se pone';
|
||||
@override String get replace => 'Se cambia';
|
||||
@override String get dry => 'Azul — seco';
|
||||
@override String get fresh => 'Recién puesto';
|
||||
}
|
||||
|
||||
// Path: unit
|
||||
class _Translations$unit$es extends Translations$unit$en {
|
||||
_Translations$unit$es._(TranslationsEs root) : this._root = root, super.internal(root);
|
||||
|
|
@ -778,23 +929,23 @@ extension on TranslationsEs {
|
|||
'settings.aboutText' => 'Inventario local y cifrado para semillas tradicionales. AGPL-3.0.',
|
||||
'settings.aboutOpen' => 'Acerca de Tanemaki',
|
||||
'backup.title' => 'Copia de seguridad',
|
||||
'backup.exportCsv' => 'Exportar a CSV',
|
||||
'backup.exportCsvSubtitle' => 'Para hojas de cálculo — sin fotos',
|
||||
'backup.exportJson' => 'Exportar a JSON',
|
||||
'backup.exportJsonSubtitle' => 'Copia completa, se puede volver a importar',
|
||||
'backup.importJson' => 'Importar desde JSON',
|
||||
'backup.importJsonSubtitle' => 'Fusiona una copia guardada con este inventario',
|
||||
'backup.importCsv' => 'Importar desde CSV',
|
||||
'backup.importCsvSubtitle' => 'Añade una lista desde una hoja de cálculo',
|
||||
'backup.importConfirmTitle' => '¿Importar una copia guardada?',
|
||||
'backup.exportJson' => 'Guardar una copia de seguridad',
|
||||
'backup.exportJsonSubtitle' => 'Una copia completa para guardar a salvo, restaurar luego o pasar a otro dispositivo',
|
||||
'backup.importJson' => 'Restaurar una copia',
|
||||
'backup.importJsonSubtitle' => 'Recupera una copia guardada — no se duplica nada',
|
||||
'backup.exportCsv' => 'Exportar a una hoja de cálculo',
|
||||
'backup.exportCsvSubtitle' => 'Una lista sencilla para Excel o LibreOffice — sin fotos',
|
||||
'backup.importCsv' => 'Importar una lista',
|
||||
'backup.importCsvSubtitle' => 'Añade entradas desde una hoja de cálculo',
|
||||
'backup.importConfirmTitle' => '¿Restaurar una copia?',
|
||||
'backup.importConfirmBody' => 'Las entradas se fusionan con tu inventario; si una entrada existe en ambos lados, gana la versión más reciente. No se duplica nada.',
|
||||
'backup.importCsvConfirmTitle' => '¿Importar una lista CSV?',
|
||||
'backup.importCsvConfirmTitle' => '¿Importar una lista?',
|
||||
'backup.importCsvConfirmBody' => 'Cada fila se añade como una entrada nueva. No fusiona ni reemplaza, así que importar el mismo fichero dos veces lo añade dos veces.',
|
||||
'backup.importAction' => 'Importar',
|
||||
'backup.exportSaved' => 'Copia guardada',
|
||||
'backup.cancelled' => 'Cancelado',
|
||||
'backup.importDone' => ({required Object added, required Object updated}) => 'Importado: ${added} nuevas, ${updated} actualizadas',
|
||||
'backup.importCsvDone' => ({required Object count}) => 'Importadas ${count} desde CSV',
|
||||
'backup.importCsvDone' => ({required Object count}) => 'Añadidas ${count} entradas',
|
||||
'backup.importFailed' => 'Este fichero no se pudo leer como una copia de Tanemaki',
|
||||
'backup.failed' => 'Algo ha salido mal',
|
||||
'about.title' => 'Acerca de',
|
||||
|
|
@ -828,6 +979,16 @@ extension on TranslationsEs {
|
|||
'inventory.noMatches' => 'Ninguna semilla coincide con los filtros.',
|
||||
'inventory.clearFilters' => 'Quitar filtros',
|
||||
'inventory.uncategorized' => 'Sin categoría',
|
||||
'inventory.needsReproductionFilter' => 'Por reproducir',
|
||||
'draft.capture' => 'Capturar fotos',
|
||||
'draft.captured' => ({required Object n}) => '${n} capturadas por catalogar',
|
||||
'draft.triageTitle' => 'Por catalogar',
|
||||
'draft.triageCount' => ({required Object n}) => '${n} por catalogar',
|
||||
'draft.untitled' => 'Sin nombre',
|
||||
'draft.nameField' => 'Nombra esta semilla',
|
||||
'draft.nameHint' => '¿Qué es?',
|
||||
'draft.suggestFromPhoto' => 'Sugerir nombre de la foto',
|
||||
'draft.discard' => 'Descartar',
|
||||
'quickAdd.title' => 'Añadir una semilla',
|
||||
'quickAdd.labelField' => 'Nombre',
|
||||
'quickAdd.labelRequired' => 'Ponle un nombre',
|
||||
|
|
@ -859,12 +1020,18 @@ extension on TranslationsEs {
|
|||
'germination.germinated' => 'Germinadas',
|
||||
'germination.none' => 'Aún no hay pruebas de germinación.',
|
||||
'germination.result' => ({required Object percent}) => '${percent}%',
|
||||
'viability.expiringSoon' => 'Úsala o multiplícala esta temporada',
|
||||
'viability.expiringSoonYears' => ({required Object years}) => 'Úsala o multiplícala esta temporada · dura ~${years} años',
|
||||
'viability.expired' => 'Supera su viabilidad típica — a multiplicar',
|
||||
'viability.expiredYears' => ({required Object years}) => 'Supera su viabilidad típica (~${years} años) — a multiplicar',
|
||||
'editVariety.title' => 'Editar semilla',
|
||||
'editVariety.name' => 'Nombre',
|
||||
'editVariety.category' => 'Categoría',
|
||||
'editVariety.notes' => 'Notas',
|
||||
'editVariety.species' => 'Especie (del catálogo)',
|
||||
'editVariety.speciesHint' => 'Buscar una especie…',
|
||||
'editVariety.organic' => 'Ecológica',
|
||||
'editVariety.organicHint' => 'Cultivada de forma ecológica (eco)',
|
||||
'addLot.title' => 'Añadir lote',
|
||||
'addLot.year' => 'Fecha de cosecha',
|
||||
'addLot.quantity' => '¿Cuánta?',
|
||||
|
|
@ -897,6 +1064,51 @@ extension on TranslationsEs {
|
|||
'presentation.plug' => 'Alvéolo',
|
||||
'presentation.bareRoot' => 'Raíz desnuda',
|
||||
'presentation.rootBall' => 'Cepellón',
|
||||
'provenance.section' => 'De dónde viene',
|
||||
'provenance.seedsFrom' => 'Semillas de',
|
||||
'provenance.seedsFromHint' => 'Quién las cultivó o las dio',
|
||||
'provenance.place' => 'Lugar',
|
||||
'provenance.placeHint' => 'De dónde vienen (con provincia)',
|
||||
'provenance.addSeedsFrom' => 'Semillas de',
|
||||
'provenance.addPlace' => 'Lugar',
|
||||
'abundance.add' => 'Cuánta tengo',
|
||||
'abundance.title' => 'Cuánta tengo',
|
||||
'abundance.none' => 'Sin indicar',
|
||||
'abundance.plentyToShare' => 'De sobra para compartir',
|
||||
'abundance.enoughToShare' => 'Bastante, para compartir con moderación',
|
||||
'abundance.enoughForMe' => 'Suficiente para mí',
|
||||
'abundance.runningLow' => 'Queda poca',
|
||||
'cropCalendar.add' => 'Calendario de cultivo',
|
||||
'cropCalendar.title' => 'Calendario de cultivo',
|
||||
'cropCalendar.sow' => 'Siembra',
|
||||
'cropCalendar.transplant' => 'Trasplante',
|
||||
'cropCalendar.flowering' => 'Floración',
|
||||
'cropCalendar.fruiting' => 'Fructificación',
|
||||
'cropCalendar.seedHarvest' => 'Cosecha de semilla',
|
||||
'cropCalendar.unset' => '—',
|
||||
'needsReproduction.label' => 'Reproducir esta temporada',
|
||||
'needsReproduction.hint' => 'Cultívala antes de que se acabe la semilla',
|
||||
'needsReproduction.badge' => 'Por reproducir',
|
||||
'preservation.add' => 'Cómo se conserva',
|
||||
'preservation.title' => 'Cómo se conserva',
|
||||
'preservation.none' => 'Sin especificar',
|
||||
'preservation.jarWithDesiccant' => 'Bote con desecante',
|
||||
'preservation.glassJar' => 'Bote de cristal',
|
||||
'preservation.paperEnvelope' => 'Sobre de papel',
|
||||
'preservation.paperBag' => 'Bolsa de papel',
|
||||
'preservation.plasticBag' => 'Bolsa de plástico',
|
||||
'conditionCheck.advanced' => 'Conservación y detalles del banco',
|
||||
'conditionCheck.title' => 'Revisiones de conservación',
|
||||
'conditionCheck.add' => 'Añadir revisión',
|
||||
'conditionCheck.containers' => 'Botes / recipientes',
|
||||
'conditionCheck.desiccant' => 'Desecante',
|
||||
'conditionCheck.none' => 'Aún no hay revisiones.',
|
||||
'conditionCheck.summary' => ({required Object count, required Object state}) => '${count} bote(s) · ${state}',
|
||||
'desiccant.none' => 'No tiene',
|
||||
'desiccant.add' => 'Se pone',
|
||||
'desiccant.replace' => 'Se cambia',
|
||||
'desiccant.dry' => 'Azul — seco',
|
||||
'desiccant.fresh' => 'Recién puesto',
|
||||
'unit.aFew' => 'unas pocas',
|
||||
'unit.some' => 'algunas',
|
||||
'unit.plenty' => 'muchas',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue