feat(i18n): complete Portuguese, add Brazilian Portuguese (pt_BR)
Some checks are pending
ci / analyze (push) Waiting to run
ci / test-commons-core (push) Waiting to run
ci / test-app-seeds (push) Waiting to run

Fill the ~74 UI strings pt.i18n.json was missing (saved searches, label
scanning, Plantaré, lot history), then add pt_BR as a proper Brazilian
variant rather than a copy of European Portuguese: tu/teu/tua -> você/
seu/sua with matching verb conjugation, partilhar -> compartilhar, and
Guardar -> Salvar for UI actions (seed-saving keeps "guardar", the
correct term in both variants). Wires AppLocale.ptBr into the language
picker and regenerates slang output.
This commit is contained in:
vjrj 2026-07-20 23:11:01 +02:00
parent 071be44851
commit d80f6d50fa
19 changed files with 5231 additions and 1920 deletions

View file

@ -94,6 +94,7 @@
"langEs": "Español",
"langEn": "English",
"langPt": "Português",
"langPtBr": "Português (Brasil)",
"langAst": "Asturianu",
"langFr": "Français",
"langDe": "Deutsch",
@ -146,9 +147,9 @@
"license": "Llicencia",
"licenseValue": "AGPL-3.0",
"website": "Sitiu web",
"sourceCode": "Códigu fonte",
"translate": "Ayuda a traducir",
"translateSubtitle": "Ayuda a traer Tane a la to llingua",
"sourceCode": "Códigu fonte",
"translate": "Ayuda a traducir",
"translateSubtitle": "Ayuda a traer Tane a la to llingua",
"openSourceLicenses": "Llicencies de códigu abiertu",
"openSourceLicensesSubtitle": "Biblioteques de terceros y les sos llicencies",
"copyright": "© {years} Asociación Comunes, baxo AGPLv3"

View file

@ -95,6 +95,7 @@
"langEs": "Español",
"langEn": "English",
"langPt": "Português",
"langPtBr": "Português (Brasil)",
"langAst": "Asturianu",
"about": "Über",
"aboutText": "Lokale, verschlüsselte Saatgutbank für traditionelle Samen. AGPL-3.0.",
@ -147,9 +148,9 @@
"license": "Lizenz",
"licenseValue": "AGPL-3.0",
"website": "Webseite",
"sourceCode": "Quellcode",
"translate": "Beim Übersetzen helfen",
"translateSubtitle": "Hilf, Tane in deine Sprache zu bringen",
"sourceCode": "Quellcode",
"translate": "Beim Übersetzen helfen",
"translateSubtitle": "Hilf, Tane in deine Sprache zu bringen",
"openSourceLicenses": "Open-Source-Lizenzen",
"openSourceLicensesSubtitle": "Bibliotheken von Drittanbietern und ihre Lizenzen",
"copyright": "© {years} Comunes Association, unter AGPLv3"
@ -723,4 +724,4 @@
"manageEmpty": "Du hast niemanden blockiert",
"unblock": "Entsperren"
}
}
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -95,6 +95,7 @@
"langEs": "Español",
"langEn": "English",
"langPt": "Português",
"langPtBr": "Português (Brasil)",
"langAst": "Asturianu",
"langFr": "Français",
"langDe": "Deutsch",
@ -147,9 +148,9 @@
"license": "Licence",
"licenseValue": "AGPL-3.0",
"website": "Site web",
"sourceCode": "Code source",
"translate": "Aider à traduire",
"translateSubtitle": "Aidez à traduire Tane dans votre langue",
"sourceCode": "Code source",
"translate": "Aider à traduire",
"translateSubtitle": "Aidez à traduire Tane dans votre langue",
"openSourceLicenses": "Licences open source",
"openSourceLicensesSubtitle": "Bibliothèques tiers et leurs licences",
"copyright": "© {years} Association Comunes, sous AGPLv3"

View file

@ -1,46 +1,47 @@
{
"app": {
"title": "Tane"
},
"common": {
"save": "保存",
"cancel": "キャンセル",
"delete": "削除",
"edit": "編集",
"type": "種類",
"comingSoon": "近日公開",
"offline": "オフラインです — 共有を一時停止しています"
},
"menu": {
"tagline": "あなたの種子バンク",
"inventory": "在庫",
"market": "マーケット",
"profile": "プロフィール",
"chat": "チャット",
"wishlist": "お気に入り",
"following": "フォロー中",
"calendar": "カレンダー",
"settings": "設定"
},
"settings": {
"language": "言語",
"systemLanguage": "システムの言語",
"langEs": "Español",
"langEn": "English",
"langPt": "Português",
"langAst": "Asturianu",
"langFr": "Français",
"langDe": "Deutsch",
"langJa": "日本語",
"about": "このアプリについて",
"aboutText": "在来種のためのローカルファースト・暗号化在庫管理。AGPL-3.0。",
"aboutOpen": "Tane について"
},
"home": {
"tagline": "地域の種を分かち合い、育てよう",
"openMarket": "マーケット",
"openMarketSubtitle": "近くの種を見つけて分かち合う",
"yourInventory": "あなたの在庫",
"yourInventorySubtitle": "種を管理する"
}
"app": {
"title": "Tane"
},
"common": {
"save": "保存",
"cancel": "キャンセル",
"delete": "削除",
"edit": "編集",
"type": "種類",
"comingSoon": "近日公開",
"offline": "オフラインです — 共有を一時停止しています"
},
"menu": {
"tagline": "あなたの種子バンク",
"inventory": "在庫",
"market": "マーケット",
"profile": "プロフィール",
"chat": "チャット",
"wishlist": "お気に入り",
"following": "フォロー中",
"calendar": "カレンダー",
"settings": "設定"
},
"settings": {
"language": "言語",
"systemLanguage": "システムの言語",
"langEs": "Español",
"langEn": "English",
"langPt": "Português",
"langPtBr": "Português (Brasil)",
"langAst": "Asturianu",
"langFr": "Français",
"langDe": "Deutsch",
"langJa": "日本語",
"about": "このアプリについて",
"aboutText": "在来種のためのローカルファースト・暗号化在庫管理。AGPL-3.0。",
"aboutOpen": "Tane について"
},
"home": {
"tagline": "地域の種を分かち合い、育てよう",
"openMarket": "マーケット",
"openMarketSubtitle": "近くの種を見つけて分かち合う",
"yourInventory": "あなたの在庫",
"yourInventorySubtitle": "種を管理する"
}
}

View file

@ -12,6 +12,19 @@
"remove": "Remover dos favoritos",
"unavailable": "Já não está disponível"
},
"savedSearches": {
"title": "Pesquisas guardadas",
"empty": "Ainda não há pesquisas guardadas. Guarda uma pesquisa no mercado e avisamos-te quando aparecer algo parecido na tua zona.",
"save": "Guardar esta pesquisa",
"nameLabel": "Dá um nome a esta pesquisa",
"namePlaceholder": "ex.: Tomates perto de mim",
"saved": "Pesquisa guardada — vamos avisar-te sobre novas correspondências perto de ti",
"openTooltip": "Pesquisas guardadas",
"delete": "Eliminar",
"deleteConfirm": "Eliminar esta pesquisa guardada?",
"newMatchesBadge": "{n} novas",
"alert": "Sementes perto de ti: {label}"
},
"seedSaving": {
"title": "Guardar a sua semente",
"subtitle": "O que é preciso para manter a variedade fiel",
@ -95,6 +108,7 @@
"langEs": "Español",
"langEn": "English",
"langPt": "Português",
"langPtBr": "Português (Brasil)",
"langAst": "Asturianu",
"langFr": "Français",
"langDe": "Deutsch",
@ -147,9 +161,9 @@
"license": "Licença",
"licenseValue": "AGPL-3.0",
"website": "Sítio web",
"sourceCode": "Código-fonte",
"translate": "Ajuda a traduzir",
"translateSubtitle": "Ajuda a trazer o Tane para o teu idioma",
"sourceCode": "Código-fonte",
"translate": "Ajuda a traduzir",
"translateSubtitle": "Ajuda a trazer o Tane para o teu idioma",
"openSourceLicenses": "Licenças de código aberto",
"openSourceLicensesSubtitle": "Bibliotecas de terceiros e as suas licenças",
"copyright": "© {years} Associação Comunes, sob AGPLv3"
@ -226,6 +240,10 @@
"addLink": "Adicionar ligação",
"linkUrl": "URL",
"linkTitle": "Título (opcional)",
"reference": "Saber mais",
"refGbif": "GBIF",
"refWikipedia": "Wikipédia",
"refWikispecies": "Wikispecies",
"notes": "Notas",
"addLot": "Adicionar lote",
"editLot": "Editar lote",
@ -351,6 +369,15 @@
"saved": "Etiquetas guardadas",
"cancelled": "Cancelado"
},
"scan": {
"action": "Digitalizar um rótulo de semente",
"title": "Digitalizar um rótulo",
"notALabel": "Esse código não é um rótulo de semente",
"addTitle": "Não está na tua coleção",
"addBody": "Adicionar “{label}” às tuas sementes?",
"add": "Adicionar",
"added": "Adicionado à tua coleção"
},
"cropCalendar": {
"add": "Calendário de cultivo",
"title": "Calendário de cultivo",
@ -645,7 +672,30 @@
"dueByHint": "Um lembrete gentil, nunca imposto",
"pickDate": "Escolher data",
"clearDate": "Limpar data",
"sectionTitle": "Compromissos"
"sectionTitle": "Compromissos",
"propose": "Propor um Plantaré assinado",
"proposeHelp": "Ambos mantêm a mesma promessa, assinada pelos dois — prova de que esta semente mudou de mãos e será cultivada e devolvida.",
"proposeTo": "Com {name}",
"sent": "Proposta enviada — a aguardar que assinem",
"seedLabel": "Que semente?",
"seedHint": "A variedade a que se refere esta promessa",
"returnKindLabel": "O que volta?",
"returnSimilar": "Uma quantidade semelhante de semente",
"returnSimilarNote": "polinização aberta · não transgénico · cultivado organicamente",
"returnWork": "Algumas horas de trabalho",
"returnOther": "Outra coisa",
"workHoursLabel": "Quantas horas?",
"proposalsSection": "À espera da tua resposta",
"incomingFrom": "{name} propõe um Plantaré",
"accept": "Aceitar e assinar",
"declineAction": "Recusar",
"declineReasonHint": "Motivo (opcional)",
"acceptedToast": "Assinado — agora ambos o mantêm",
"declinedToast": "Recusado",
"badgeAwaiting": "A aguardar assinatura",
"badgeSigned": "Assinado por ambos",
"badgeDeclined": "Recusado",
"offline": "Estás offline — será enviado quando reconectares"
},
"handover": {
"title": "Dei ou recebi sementes",
@ -660,6 +710,37 @@
"promiseGave": "Vão devolver-me semente",
"promiseReceived": "Vou devolver semente"
},
"history": {
"title": "História deste lote",
"tooltip": "História",
"sowToday": "Semeado hoje",
"harvestToday": "Colhido hoje",
"sownRecorded": "Sementeira registada",
"harvestRecorded": "Colheita registada",
"movementReceived": "Recebido",
"movementGiven": "Oferecido",
"movementSown": "Semeado",
"movementHarvested": "Colhido",
"movementGerminationTest": "Teste de germinação",
"movementSplit": "Dividido em lotes",
"movementDiscarded": "Descartado",
"created": "Adicionado à tua coleção",
"from": "De {origin}",
"germinationResult": "Teste de germinação — {percent}%",
"linkedEarlier": "Vem de um lote anterior",
"outcomeQuestion": "Como correu?",
"outcomeGood": "Bem",
"outcomeMixed": "Mais ou menos",
"outcomePoor": "Mal",
"outcomeNoteHint": "Uma nota para o teu eu futuro (opcional)",
"outcomeSaved": "Registado",
"ratedGood": "Correu bem",
"ratedMixed": "Correu mais ou menos",
"ratedPoor": "Correu mal",
"outcomeTitle": "Nota da estação",
"outcomeYear": "Estação {year}",
"isolationHint": "Esta espécie cruza-se com vizinhas próximas — cultiva-a a cerca de {meters} m de distância de outras para a manter pura"
},
"sale": {
"title": "Vendas",
"help": "Regista semente vendida ou comprada — dinheiro, Ğ1 ou qualquer moeda. Um modelo separado do presente e do Plantare. Nunca se cobra comissão pelas sementes.",

View file

@ -0,0 +1,810 @@
{
"avatar": {
"title": "A sua foto ou avatar",
"fromPhoto": "Tirar ou escolher uma foto",
"illustration": "Ou escolhe um desenho",
"remove": "Remover"
},
"favorites": {
"title": "Favoritos",
"empty": "Ainda não tem favoritos. Salve ofertas que goste do mercado.",
"save": "Salvar nos favoritos",
"remove": "Remover dos favoritos",
"unavailable": "Já não está disponível"
},
"savedSearches": {
"title": "Pesquisas salvas",
"empty": "Ainda não há pesquisas salvas. Salve uma pesquisa no mercado e te avisamos quando aparecer algo parecido na sua zona.",
"save": "Salvar esta pesquisa",
"nameLabel": "Dá um nome a esta pesquisa",
"namePlaceholder": "ex.: Tomates perto de mim",
"saved": "Pesquisa salva — vamos te avisar sobre novas correspondências perto de você",
"openTooltip": "Pesquisas salvas",
"delete": "Eliminar",
"deleteConfirm": "Eliminar esta pesquisa salva?",
"newMatchesBadge": "{n} novas",
"alert": "Sementes perto de você: {label}"
},
"seedSaving": {
"title": "Guardar a sua semente",
"subtitle": "O que é preciso para manter a variedade fiel",
"lifeCycle": "Ciclo",
"cycleAnnual": "Anual",
"cycleBiennial": "Bienal — dá semente no 2.º ano",
"cyclePerennial": "Perene",
"pollination": "Polinização",
"pollSelf": "Autopoliniza-se",
"pollCross": "Cruza-se com outras",
"pollMixed": "Autopoliniza-se, mas às vezes cruza",
"byInsect": "por insetos",
"byWind": "pelo vento",
"isolation": "Separe-a",
"isolationRange": "{min}{max} m de outras variedades",
"isolationSingle": "{min} m de outras variedades",
"plants": "Guarde de várias plantas",
"plantsValue": "De pelo menos {n} plantas",
"processing": "Como limpá-la",
"procDry": "Semente seca (debulhar)",
"procWet": "Semente húmida (fermentar e lavar)",
"difficulty": "Dificuldade",
"diffEasy": "Fácil",
"diffMedium": "Média",
"diffHard": "Difícil",
"advisory": "Orientativo — adapte-o ao seu clima e variedade.",
"sourcePrefix": "Fonte"
},
"calendar": {
"title": "Este mês",
"filterChip": "Este mês",
"selfNote": "O que você anotou nas suas variedades.",
"nothing": "Nada anotado para {month}."
},
"app": {
"title": "Tane"
},
"bootstrap": {
"failed": "O Tane não conseguiu iniciar",
"retry": "Tentar de novo"
},
"common": {
"save": "Salvar",
"cancel": "Cancelar",
"delete": "Eliminar",
"edit": "Editar",
"type": "Tipo",
"comingSoon": "Em breve",
"offline": "Sem ligação — a compartilha está em pausa"
},
"home": {
"tagline": "Compartilha e cultiva sementes locais",
"openMarket": "Mercado",
"openMarketSubtitle": "Descobre e compartilha sementes por perto",
"yourInventory": "O seu inventário",
"yourInventorySubtitle": "Gere as suas 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 seu banco de sementes",
"inventory": "Inventário",
"market": "Mercado",
"profile": "O seu perfil",
"chat": "Conversas",
"wishlist": "Favoritos",
"following": "A seguir",
"plantares": "Plantares",
"sales": "Vendas",
"calendar": "Calendário",
"settings": "Definições"
},
"settings": {
"language": "Idioma",
"systemLanguage": "Idioma do sistema",
"langEs": "Español",
"langEn": "English",
"langPt": "Português",
"langPtBr": "Português (Brasil)",
"langAst": "Asturianu",
"langFr": "Français",
"langDe": "Deutsch",
"langJa": "日本語",
"about": "Acerca de",
"aboutText": "Inventário local e cifrado para sementes tradicionais. AGPL-3.0.",
"aboutOpen": "Acerca do Tane"
},
"backup": {
"title": "Cópia de segurança",
"autoBackupTitle": "Cópias automáticas",
"autoBackupLast": "Última cópia em {date} · a cada {days} dias",
"autoBackupNone": "Uma cópia é salva automaticamente a cada {days} dias",
"exportJson": "Salvar 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 salva — 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 seu 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 arquivo duas vezes acrescenta-o duas vezes.",
"importAction": "Importar",
"exportSaved": "Cópia salva",
"cancelled": "Cancelado",
"importDone": "Importado: {added} novas, {updated} atualizadas",
"importCsvDone": "{count} entradas acrescentadas",
"importFailed": "Este arquivo não pôde ser lido como uma cópia do Tane",
"failed": "Algo correu mal",
"recoveryTitle": "O seu código de recuperação",
"recoverySubtitle": "Imprime-o e guarda-o bem: abre as suas cópias noutro aparelho",
"recoveryIntro": "Este código abre as suas cópias salvas e recupera o seu banco em qualquer aparelho. Guarde duas cópias em papel em lugares seguros, como a sua melhor semente. Quem o tiver pode ler as suas cópias, por isso não o compartilhe com ninguém.",
"recoveryCopy": "Copiar",
"recoverySave": "Salvar a folha",
"recoverySheetTitle": "Tane — a sua folha de recuperação",
"recoveryPromptTitle": "Escreve o seu código de recuperação",
"recoveryPromptBody": "Esta cópia foi salva com outro código. Escreve o código da sua 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 compartilhar sementes e plântulas tradicionais.",
"intro": "O Tane (種, \"semente\" em japonês) ajuda pessoas e coletivos a manter um inventário amigável do seu banco de sementes, decidir o que oferecem e compartilhá-lo localmente — sem um intermediário central que possa controlar, censurar ou ser multado por isso. O seu nome vem de tanemaki (種まき), \"semear / espalhar sementes\". 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 compartilhado) 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 Tane é o Plantare digital.",
"version": "Versão",
"license": "Licença",
"licenseValue": "AGPL-3.0",
"website": "Sítio web",
"sourceCode": "Código-fonte",
"translate": "Ajuda a traduzir",
"translateSubtitle": "Ajuda a trazer o Tane para o seu idioma",
"openSourceLicenses": "Licenças de código aberto",
"openSourceLicensesSubtitle": "Bibliotecas de terceiros e as suas licenças",
"copyright": "© {years} Associação Comunes, sob AGPLv3"
},
"intro": {
"skip": "Saltar",
"next": "Seguinte",
"start": "Começar",
"menuEntry": "Como funciona o Tane",
"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 compartilha."
},
"inventory": {
"title": "O seu banco de sementes, no bolso",
"body": "Anote o que tem, de que ano, quanto e de onde veio — com o nome que você usa. Uma foto e um nome chegam para começar."
},
"privacy": {
"title": "Seu, e só seu",
"body": "Sem conta, sem internet, sem rastreadores. Os seus dados vivem cifrados no seu aparelho, e só o que você escolher é compartilhado."
},
"share": {
"title": "Compartilhar, como sempre se fez",
"body": "Ofereça o que sobra — dar, trocar ou vender — e deixe que alguém perto de você o encontre. Só se mostra uma distância aproximada, nunca a sua 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 seus filtros.",
"clearFilters": "Limpar filtros",
"uncategorized": "Sem categoria",
"needsReproductionFilter": "Para reproduzir",
"loadError": "Não foi possível abrir o seu banco de sementes. Talvez estivesse ocupado — tenta de novo.",
"retry": "Tentar de novo"
},
"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": "Salvar",
"saveAndAddAnother": "Salvar 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)",
"reference": "Saber mais",
"refGbif": "GBIF",
"refWikipedia": "Wikipédia",
"refWikispecies": "Wikispecies",
"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…",
"speciesSuggested": "Sugerida pelo nome",
"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 compartilhar",
"enoughToShare": "Bastante, para compartilhar com moderação",
"enoughForMe": "Suficiente para mim",
"runningLow": "Resta pouca"
},
"share": {
"add": "Compartilhas esta?",
"title": "Compartilhas esta?",
"nudge": "Tem de sobra: podia compartilhar um pouco.",
"price": "Preço",
"priceHint": "Deixe vazio para combinar depois",
"private": "Só para mim",
"gift": "Para dar",
"exchange": "Para trocar",
"sell": "À venda",
"filterChip": "Compartilho",
"printCatalog": "Imprimir o que compartilho",
"catalogTitle": "O que compartilho",
"catalogSaved": "Catálogo salvo",
"cancelled": "Cancelado"
},
"printLabels": {
"action": "Imprimir etiquetas",
"title": "Imprimir etiquetas",
"selectHint": "Escolhe as sementes para imprimir as etiquetas",
"selectAll": "Selecionar tudo",
"selected": "{n} selecionadas",
"none": "Seleciona sementes primeiro",
"format": "Tamanho da etiqueta",
"formatStickers": "Autocolantes pequenos",
"formatStickersHint": "Muitas etiquetas pequenas por folha — para colar em envelopes",
"formatCards": "Cartões grandes",
"formatCardsHint": "Menos etiquetas, maiores — para frascos e caixas",
"count": "{n} etiquetas",
"save": "Salvar etiquetas",
"saved": "Etiquetas salvas",
"cancelled": "Cancelado"
},
"scan": {
"action": "Digitalizar um rótulo de semente",
"title": "Digitalizar um rótulo",
"notALabel": "Esse código não é um rótulo de semente",
"addTitle": "Não está na sua coleção",
"addBody": "Adicionar “{label}” às suas sementes?",
"add": "Adicionar",
"added": "Adicionado à sua coleção"
},
"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",
"editorHint": "Anote os meses típicos desta variedade na sua zona — são suas notas.",
"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"
}
},
"market": {
"title": "Sementes perto de você",
"subtitle": "O que outras pessoas compartilham por perto",
"notSetUp": "Ainda não configurou a compartilha",
"notSetUpBody": "Ativa a compartilha para ver e dar sementes a pessoas por perto. Mantém-se aproximado — a sua zona, nunca a sua morada exata.",
"setUp": "Configurar a compartilha",
"cantReach": "Não é possível ligar aos servidores neste momento",
"cantReachBody": "Tenta de novo, ou verifica os servidores na configuração avançada.",
"retry": "Tentar de novo",
"setArea": "Indica a sua zona",
"setAreaBody": "Diz ao mercado a sua zona aproximada para ver sementes por perto.",
"searching": "A procurar pela sua zona…",
"empty": "Ainda não há sementes compartilhadas perto de você",
"searchHint": "Procurar nestas sementes",
"noMatches": "Nenhuma semente compartilhada corresponde à procura",
"near": "Perto de você",
"contact": "Mensagem",
"mine": "Você",
"configTitle": "Configuração de compartilha",
"setupIntro": "Compartilhar com pessoas por perto é opcional. Basta indicar a sua zona aproximada — já está conectado a servidores comunitários compartilhados para que outras pessoas encontrem o que você oferece, sem nenhuma empresa no meio.",
"areaLabel": "A sua zona",
"areaHelp": "Mantém-se aproximado de propósito — a sua zona, nunca um ponto exato.",
"areaSet": "A sua zona está definida — aproximada, nunca o seu ponto exato",
"areaNotSet": "Zona por definir — usa a sua localização, ou adiciona um código em Avançado",
"advanced": "Avançado",
"areaCodeLabel": "Código de zona",
"areaCodeHint": "Um código curto como sp3e9 — não um nome de lugar",
"serversLabel": "Servidores da comunidade",
"serversHelp": "Escolha que servidores usar. Deixe assim se não souber.",
"serversAdvanced": "Adicionar outro servidor",
"serverAddress": "Endereço do servidor",
"serverInvalid": "Introduz um endereço válido (wss://…)",
"save": "Salvar",
"saved": "Salvo",
"wanted": "Procuro",
"shareMine": "Compartilhar as minhas sementes",
"sharedCount": "Compartilhadas {n} sementes",
"nothingToShare": "Marca primeiro algumas sementes para dar, trocar ou vender",
"useLocation": "Usar a minha localização aproximada",
"locationFailed": "Não foi possível obter a sua localização — verifica se a localização está ativa e a permissão concedida",
"queued": "Salvo — vamos compartilhá-las quando você tiver conexão",
"shareFailed": "Não foi possível contactar os servidores — as suas sementes não foram compartilhadas. Tenta de novo daqui a pouco.",
"rangeLabel": "Até onde procurar",
"rangeNear": "Muito perto",
"rangeArea": "Pela minha zona",
"rangeRegion": "A minha região",
"sharedBy": "Compartilhado por",
"noProfile": "Esta pessoa ainda não compartilhou o seu perfil",
"copyId": "Copiar código",
"idCopied": "Código copiado",
"photo": "Foto"
},
"profile": {
"title": "O seu perfil",
"name": "Nome",
"nameHint": "Como os outros te veem",
"about": "Sobre você",
"aboutHint": "Uma linha — o que cultivas, onde",
"g1": "Endereço Ğ1 (opcional)",
"g1Hint": "Para que te paguem em Ğ1 — separado da sua chave",
"yourId": "A sua identidade",
"idHelp": "Compartilha-a para que te reconheçam",
"copy": "Copiar",
"copied": "Copiado",
"save": "Salvar",
"saved": "Perfil salvo",
"identities": "As suas identidades",
"identitiesHelp": "Mantém identidades separadas — cada uma com as suas mensagens e contactos. Todas vêm da sua única cópia de segurança, por isso mudar não acrescenta nada para lembrar.",
"identityLabel": "Identidade {n}",
"current": "Em uso",
"newIdentity": "Nova identidade",
"switchTitle": "Mudar de identidade?",
"switchBody": "As mensagens e contatos são guardados separadamente para cada identidade. Pode voltar quando quiser.",
"switchAction": "Mudar"
},
"chatList": {
"title": "Mensagens",
"empty": "Ainda não há conversas. Escreve a alguém a partir do mercado."
},
"chat": {
"title": "Conversa",
"hint": "Escreve uma mensagem…",
"send": "Enviar",
"empty": "Ainda não há mensagens — diz olá",
"offline": "Configura a compartilha para enviar mensagens",
"payG1": "Pagar em Ğ1",
"g1Copied": "Endereço Ğ1 copiado — cola-o na sua carteira",
"today": "Hoje",
"yesterday": "Ontem",
"sendError": "Não foi possível enviar — verifica a sua ligação",
"noLinks": "Não são permitidos links nas mensagens"
},
"trust": {
"none": "Ainda ninguém os avaliza",
"count": "Avalizada por {n}",
"vouch": "Conheço esta pessoa",
"vouched": "Avalizas esta pessoa",
"circle": "No seu círculo"
},
"yourPeople": {
"title": "A sua gente",
"help": "Pessoas que conheces e avalizas, e pessoas que te avalizam.",
"youVouchFor": "Você avaliza",
"vouchesForYou": "Avalizam-te",
"youVouchForEmpty": "Ainda não avaliza ninguém. Quando conhecer alguém, abra a conversa com essa pessoa e toque em \"Conheço esta pessoa\".",
"vouchesForYouEmpty": "Ainda ninguém te avaliza",
"revoke": "Deixar de avalizar",
"revokeConfirm": "Deixar de avalizar esta pessoa?",
"offline": "Sem conexão — tente novamente quando estiver online"
},
"ratings": {
"rate": "Avaliar esta pessoa",
"edit": "Editar a sua avaliação",
"commentHint": "Como correu? (opcional)",
"fromYourCircle": "{n} de pessoas que conheces",
"retract": "Remover a sua avaliação",
"saved": "Avaliação salva"
},
"notifications": {
"newMessageFrom": "Nova mensagem de {name}"
},
"plantare": {
"title": "Plantares",
"help": "Um Plantare é o compromisso de reproduzir uma semente e devolver uma parte — assim uma variedade continua a viajar de mão em mão. Não é uma venda.",
"add": "Adicionar compromisso",
"empty": "Ainda não há compromissos. Quando compartilhar ou receber semente com o compromisso de reproduzi-la e devolver algo, anote aqui.",
"iReturn": "Reproduzo e devolvo eu",
"owedToMe": "Devolvem-me a mim",
"direction": "Quem reproduz e devolve",
"counterparty": "Com quem?",
"counterpartyHint": "Uma pessoa ou um coletivo (opcional)",
"owed": "O que é devolvido?",
"owedHint": "p. ex. um punhado na próxima temporada (opcional)",
"note": "Nota (opcional)",
"save": "Salvar",
"markReturned": "Marcar devolvido",
"markForgiven": "Dar por saldado",
"reopen": "Reabrir",
"delete": "Remover",
"statusReturned": "Devolvido",
"statusForgiven": "Saldado",
"openSection": "Pendentes",
"settledSection": "Feitos",
"removeConfirm": "Remover este compromisso?",
"returnBy": "Devolver até {date}",
"overdue": "vencido",
"dueByLabel": "Devolver até (opcional)",
"dueByHint": "Um lembrete gentil, nunca imposto",
"pickDate": "Escolher data",
"clearDate": "Limpar data",
"sectionTitle": "Compromissos",
"propose": "Propor um Plantaré assinado",
"proposeHelp": "Ambos mantêm a mesma promessa, assinada pelos dois — prova de que esta semente mudou de mãos e será cultivada e devolvida.",
"proposeTo": "Com {name}",
"sent": "Proposta enviada — a aguardar que assinem",
"seedLabel": "Que semente?",
"seedHint": "A variedade a que se refere esta promessa",
"returnKindLabel": "O que volta?",
"returnSimilar": "Uma quantidade semelhante de semente",
"returnSimilarNote": "polinização aberta · não transgénico · cultivado organicamente",
"returnWork": "Algumas horas de trabalho",
"returnOther": "Outra coisa",
"workHoursLabel": "Quantas horas?",
"proposalsSection": "À espera da sua resposta",
"incomingFrom": "{name} propõe um Plantaré",
"accept": "Aceitar e assinar",
"declineAction": "Recusar",
"declineReasonHint": "Motivo (opcional)",
"acceptedToast": "Assinado — agora ambos o mantêm",
"declinedToast": "Recusado",
"badgeAwaiting": "A aguardar assinatura",
"badgeSigned": "Assinado por ambos",
"badgeDeclined": "Recusado",
"offline": "Você está offline — será enviado quando reconectar"
},
"handover": {
"title": "Dei ou recebi sementes",
"help": "Uma oferta, uma troca ou uma venda: anota-o, com promessa de devolver semente ou sem ela.",
"iGave": "Dei sementes",
"iReceived": "Recebi sementes",
"whichLot": "De que lote?",
"howMuch": "Quanto?",
"allOfIt": "Tudo",
"partOfIt": "Uma parte",
"paymentChip": "Houve dinheiro pelo meio",
"promiseGave": "Vão devolver-me semente",
"promiseReceived": "Vou devolver semente"
},
"history": {
"title": "História deste lote",
"tooltip": "História",
"sowToday": "Semeado hoje",
"harvestToday": "Colhido hoje",
"sownRecorded": "Sementeira registada",
"harvestRecorded": "Colheita registada",
"movementReceived": "Recebido",
"movementGiven": "Oferecido",
"movementSown": "Semeado",
"movementHarvested": "Colhido",
"movementGerminationTest": "Teste de germinação",
"movementSplit": "Dividido em lotes",
"movementDiscarded": "Descartado",
"created": "Adicionado à sua coleção",
"from": "De {origin}",
"germinationResult": "Teste de germinação — {percent}%",
"linkedEarlier": "Vem de um lote anterior",
"outcomeQuestion": "Como correu?",
"outcomeGood": "Bem",
"outcomeMixed": "Mais ou menos",
"outcomePoor": "Mal",
"outcomeNoteHint": "Uma nota para o seu eu futuro (opcional)",
"outcomeSaved": "Registado",
"ratedGood": "Correu bem",
"ratedMixed": "Correu mais ou menos",
"ratedPoor": "Correu mal",
"outcomeTitle": "Nota da estação",
"outcomeYear": "Estação {year}",
"isolationHint": "Esta espécie cruza-se com vizinhas próximas — cultiva-a a cerca de {meters} m de distância de outras para a manter pura"
},
"sale": {
"title": "Vendas",
"help": "Regista semente vendida ou comprada — dinheiro, Ğ1 ou qualquer moeda. Um modelo separado do presente e do Plantare. Nunca se cobra comissão pelas sementes.",
"add": "Registar venda",
"empty": "Ainda não há vendas. Anota aqui o que vendes ou compras.",
"iSold": "Vendi",
"iBought": "Comprei",
"direction": "Vendes ou compras?",
"counterparty": "Com quem?",
"counterpartyHint": "Uma pessoa ou um coletivo (opcional)",
"amount": "Montante",
"currency": "Moeda",
"currencyHint": "€, Ğ1, horas… (opcional)",
"hours": "horas",
"note": "Nota (opcional)",
"save": "Salvar",
"delete": "Remover",
"removeConfirm": "Remover esta venda?"
},
"legal": {
"title": "Privacidade e regras",
"subtitle": "A sua privacidade, as regras do mercado e a legalidade das sementes",
"privacyTitle": "A sua privacidade",
"privacyBody": "O Tane funciona sem conta, e tudo o que você registra fica no seu dispositivo, cifrado. Não há publicidade, nem rastreadores, nem servidor do Tane.\n\nNada é compartilhado a não ser que você queira: quando publica uma oferta ou o seu perfil, ou envia uma mensagem, viaja por servidores comunitários. As ofertas levam apenas uma zona aproximada — nunca a sua morada.\n\nO que publica é público, e podem ficar cópias mesmo depois de você retirar — por isso compartilhe com cuidado.",
"rulesTitle": "As regras do jogo",
"rulesBody": "O Tane é uma ferramenta, não uma loja: as trocas são acordadas diretamente entre pessoas e ninguém fica com comissão. Isso também significa que é responsável pelo que oferece e envia.\n\nNo mercado: seja honesto com suas sementes, ofereça apenas o que pode compartilhar, trate bem as pessoas e não faça spam. Pode bloquear qualquer pessoa e denunciar ofertas ou pessoas que quebrem as regras — as denúncias são tratadas nos servidores comunitários.",
"seedsTitle": "Sobre compartilhar sementes e mudas",
"seedsBody": "Oferecer e trocar sementes entre amadores é amplamente reconhecido na maioria dos países. Vender pode ser diferente: em muitos lugares, vender sementes de variedades não registadas oficialmente é restrito — consulta as regras locais antes de pedir um preço.\n\nEnviar sementes para outro país também costuma ser restrito, e as variedades protegidas comercialmente não podem ser propagadas sem autorização. Na dúvida, melhor local e melhor oferta.\n\nO mesmo se aplica a mudas e plantas jovens, mas a planta viva pode ter regras de transporte e fitossanitárias mais rígidas do que a semente: movê-la entre regiões ou países pode exigir controlos adicionais.",
"readFull": "Ler os documentos completos na web"
},
"marketGate": {
"title": "Antes de entrar no mercado",
"intro": "O mercado é um espaço compartilhado entre vizinhas e vizinhos. Ao continuar, aceitas umas poucas regras simples:",
"ruleHonest": "Seja honesto com as sementes que oferece",
"ruleLegal": "Compartilhe apenas o que pode compartilhar onde vive",
"ruleRespect": "Trata bem as pessoas — sem spam nem abusos",
"publicNote": "O que você publicar aqui é público, e podem ficar cópias mesmo que você retire depois.",
"viewLegal": "Privacidade e regras",
"accept": "Aceito",
"decline": "Agora não"
},
"report": {
"offer": "Denunciar esta oferta",
"person": "Denunciar esta pessoa",
"title": "Denunciar",
"prompt": "O que se passa?",
"reasonSpam": "Spam ou uma burla",
"reasonAbuse": "Abusivo ou desrespeitoso",
"reasonIllegal": "Sementes que não deviam ser oferecidas",
"reasonOther": "Outra coisa",
"detailsHint": "Acrescenta detalhes (opcional)",
"send": "Enviar denúncia",
"sentHidden": "Denúncia enviada — já não voltas a ver isto",
"failed": "Não foi possível enviar a denúncia — verifica a sua ligação",
"alsoBlock": "Bloquear também esta pessoa"
},
"block": {
"action": "Bloquear esta pessoa",
"confirmTitle": "Bloquear esta pessoa?",
"confirmBody": "Deixa de ver as suas ofertas e mensagens. Pode desbloqueá-la mais tarde em Pessoas bloqueadas, na configuração de compartilhamento.",
"confirm": "Bloquear",
"blockedToast": "Pessoa bloqueada — as suas ofertas e mensagens ficam ocultas",
"manageTitle": "Pessoas bloqueadas",
"manageEmpty": "Você não bloqueou ninguém",
"unblock": "Desbloquear"
}
}

View file

@ -3,10 +3,10 @@
/// Source: lib/i18n
/// To regenerate, run: `dart run slang`
///
/// Locales: 7
/// Strings: 3566 (509 per locale)
/// Locales: 8
/// Strings: 4287 (535 per locale)
///
/// Built on 2026-07-18 at 10:28 UTC
/// Built on 2026-07-20 at 21:06 UTC
// coverage:ignore-file
// ignore_for_file: type=lint, unused_import
@ -24,6 +24,7 @@ import 'strings_es.g.dart' as l_es;
import 'strings_fr.g.dart' as l_fr;
import 'strings_ja.g.dart' as l_ja;
import 'strings_pt.g.dart' as l_pt;
import 'strings_pt_BR.g.dart' as l_pt_BR;
part 'strings_en.g.dart';
/// Supported locales.
@ -39,7 +40,8 @@ enum AppLocale with BaseAppLocale<AppLocale, Translations> {
es(languageCode: 'es'),
fr(languageCode: 'fr'),
ja(languageCode: 'ja'),
pt(languageCode: 'pt');
pt(languageCode: 'pt'),
ptBr(languageCode: 'pt', countryCode: 'BR');
const AppLocale({
required this.languageCode,
@ -113,6 +115,12 @@ enum AppLocale with BaseAppLocale<AppLocale, Translations> {
cardinalResolver: cardinalResolver,
ordinalResolver: ordinalResolver,
);
case AppLocale.ptBr:
return l_pt_BR.TranslationsPtBr(
overrides: overrides,
cardinalResolver: cardinalResolver,
ordinalResolver: ordinalResolver,
);
}
}

View file

@ -262,6 +262,7 @@ class _Translations$settings$ast extends Translations$settings$en {
@override String get langEs => 'Español';
@override String get langEn => 'English';
@override String get langPt => 'Português';
@override String get langPtBr => 'Português (Brasil)';
@override String get langAst => 'Asturianu';
@override String get langFr => 'Français';
@override String get langDe => 'Deutsch';
@ -1491,6 +1492,7 @@ extension on TranslationsAst {
'settings.langEs' => 'Español',
'settings.langEn' => 'English',
'settings.langPt' => 'Português',
'settings.langPtBr' => 'Português (Brasil)',
'settings.langAst' => 'Asturianu',
'settings.langFr' => 'Français',
'settings.langDe' => 'Deutsch',
@ -1928,9 +1930,9 @@ extension on TranslationsAst {
'handover.promiseGave' => 'Van devolveme semiente',
'handover.promiseReceived' => 'Voi devolver semiente',
'sale.title' => 'Ventes',
'sale.help' => 'Rexistra semilla vendida o mercada — dineru, Ğ1 o cualquier moneda. Un modelu aparte del regalu y del Plantare. Enxamás se cobra comisión poles semilles.',
_ => null,
} ?? switch (path) {
'sale.help' => 'Rexistra semilla vendida o mercada — dineru, Ğ1 o cualquier moneda. Un modelu aparte del regalu y del Plantare. Enxamás se cobra comisión poles semilles.',
'sale.add' => 'Rexistrar venta',
'sale.empty' => 'Entá nun hai ventes. Anota equí lo que vendes o merques.',
'sale.iSold' => 'Vendí',

View file

@ -263,6 +263,7 @@ class _Translations$settings$de extends Translations$settings$en {
@override String get langEs => 'Español';
@override String get langEn => 'English';
@override String get langPt => 'Português';
@override String get langPtBr => 'Português (Brasil)';
@override String get langAst => 'Asturianu';
@override String get about => 'Über';
@override String get aboutText => 'Lokale, verschlüsselte Saatgutbank für traditionelle Samen. AGPL-3.0.';
@ -1488,6 +1489,7 @@ extension on TranslationsDe {
'settings.langEs' => 'Español',
'settings.langEn' => 'English',
'settings.langPt' => 'Português',
'settings.langPtBr' => 'Português (Brasil)',
'settings.langAst' => 'Asturianu',
'settings.about' => 'Über',
'settings.aboutText' => 'Lokale, verschlüsselte Saatgutbank für traditionelle Samen. AGPL-3.0.',
@ -1924,9 +1926,9 @@ extension on TranslationsDe {
'sale.add' => 'Verkauf notieren',
'sale.empty' => 'Noch keine Verkäufe. Notiere hier, was du verkaufst oder kaufst.',
'sale.iSold' => 'Ich verkaufte',
'sale.iBought' => 'Ich kaufte',
_ => null,
} ?? switch (path) {
'sale.iBought' => 'Ich kaufte',
'sale.direction' => 'Verkauft oder gekauft?',
'sale.counterparty' => 'Mit wem?',
'sale.counterpartyHint' => 'Eine Person oder ein Kollektiv (optional)',

View file

@ -460,6 +460,9 @@ class Translations$settings$en {
/// en: 'Português'
String get langPt => 'Português';
/// en: 'Português (Brasil)'
String get langPtBr => 'Português (Brasil)';
/// en: 'Asturianu'
String get langAst => 'Asturianu';
@ -2864,6 +2867,7 @@ extension on Translations {
'settings.langEs' => 'Español',
'settings.langEn' => 'English',
'settings.langPt' => 'Português',
'settings.langPtBr' => 'Português (Brasil)',
'settings.langAst' => 'Asturianu',
'settings.langFr' => 'Français',
'settings.langDe' => 'Deutsch',
@ -3289,9 +3293,9 @@ extension on Translations {
'plantare.statusReturned' => 'Returned',
'plantare.statusForgiven' => 'Settled',
'plantare.openSection' => 'Open',
'plantare.settledSection' => 'Done',
_ => null,
} ?? switch (path) {
'plantare.settledSection' => 'Done',
'plantare.removeConfirm' => 'Remove this commitment?',
'plantare.returnBy' => ({required Object date}) => 'Return by ${date}',
'plantare.overdue' => 'overdue',

View file

@ -286,6 +286,7 @@ class _Translations$settings$es extends Translations$settings$en {
@override String get langEs => 'Español';
@override String get langEn => 'English';
@override String get langPt => 'Português';
@override String get langPtBr => 'Português (Brasil)';
@override String get langFr => 'Français';
@override String get langDe => 'Deutsch';
@override String get langJa => '日本語';
@ -1605,6 +1606,7 @@ extension on TranslationsEs {
'settings.langEs' => 'Español',
'settings.langEn' => 'English',
'settings.langPt' => 'Português',
'settings.langPtBr' => 'Português (Brasil)',
'settings.langFr' => 'Français',
'settings.langDe' => 'Deutsch',
'settings.langJa' => '日本語',
@ -2030,9 +2032,9 @@ extension on TranslationsEs {
'plantare.statusForgiven' => 'Saldado',
'plantare.openSection' => 'Pendientes',
'plantare.settledSection' => 'Hechos',
'plantare.removeConfirm' => '¿Quitar este compromiso?',
_ => null,
} ?? switch (path) {
'plantare.removeConfirm' => '¿Quitar este compromiso?',
'plantare.returnBy' => ({required Object date}) => 'Devolver antes del ${date}',
'plantare.overdue' => 'vencido',
'plantare.dueByLabel' => 'Devolver antes de (opcional)',

View file

@ -263,6 +263,7 @@ class _Translations$settings$fr extends Translations$settings$en {
@override String get langEs => 'Español';
@override String get langEn => 'English';
@override String get langPt => 'Português';
@override String get langPtBr => 'Português (Brasil)';
@override String get langAst => 'Asturianu';
@override String get langFr => 'Français';
@override String get langDe => 'Deutsch';
@ -1488,6 +1489,7 @@ extension on TranslationsFr {
'settings.langEs' => 'Español',
'settings.langEn' => 'English',
'settings.langPt' => 'Português',
'settings.langPtBr' => 'Português (Brasil)',
'settings.langAst' => 'Asturianu',
'settings.langFr' => 'Français',
'settings.langDe' => 'Deutsch',
@ -1924,9 +1926,9 @@ extension on TranslationsFr {
'sale.add' => 'Enregistrer une vente',
'sale.empty' => 'Pas encore de ventes. Notez ici ce que vous vendez ou achetez.',
'sale.iSold' => 'J\'ai vendu',
'sale.iBought' => 'J\'ai acheté',
_ => null,
} ?? switch (path) {
'sale.iBought' => 'J\'ai acheté',
'sale.direction' => 'Vendu ou acheté ?',
'sale.counterparty' => 'Avec qui ?',
'sale.counterpartyHint' => 'Une personne ou un collectif (optionnel)',

View file

@ -102,6 +102,7 @@ class _Translations$settings$ja extends Translations$settings$en {
@override String get langEs => 'Español';
@override String get langEn => 'English';
@override String get langPt => 'Português';
@override String get langPtBr => 'Português (Brasil)';
@override String get langAst => 'Asturianu';
@override String get langFr => 'Français';
@override String get langDe => 'Deutsch';
@ -155,6 +156,7 @@ extension on TranslationsJa {
'settings.langEs' => 'Español',
'settings.langEn' => 'English',
'settings.langPt' => 'Português',
'settings.langPtBr' => 'Português (Brasil)',
'settings.langAst' => 'Asturianu',
'settings.langFr' => 'Français',
'settings.langDe' => 'Deutsch',

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -57,6 +57,7 @@ List<(AppLocale, String)> _languages(Translations t) => [
(AppLocale.ast, t.settings.langAst),
(AppLocale.en, t.settings.langEn),
(AppLocale.pt, t.settings.langPt),
(AppLocale.ptBr, t.settings.langPtBr),
(AppLocale.fr, t.settings.langFr),
(AppLocale.de, t.settings.langDe),
(AppLocale.ja, t.settings.langJa),

View file

@ -0,0 +1,41 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tane/i18n/strings.g.dart';
/// Brazilian Portuguese (`pt_BR`) is the first locale in the app to carry a
/// region code alongside a base language that already has its own locale
/// (`pt`, European Portuguese) a case slang and the settings picker had
/// never exercised before. These tests pin that both variants are wired
/// distinctly and neither silently falls back to the other.
void main() {
test('pt and pt_BR are both supported, as distinct locales', () {
expect(
AppLocaleUtils.supportedLocales,
containsAll([const Locale('pt'), const Locale('pt', 'BR')]),
);
});
test('core strings resolve in Brazilian Portuguese', () {
final ptBr = AppLocale.ptBr.buildSync();
expect(ptBr.menu.inventory, 'Inventário');
expect(ptBr.common.save, 'Salvar');
expect(ptBr.settings.langPtBr, 'Português (Brasil)');
});
test('pt_BR wording diverges from pt where Brazilian usage differs', () {
final pt = AppLocale.pt.buildSync();
final ptBr = AppLocale.ptBr.buildSync();
// European Portuguese uses "Guardar"; Brazilian software uses "Salvar".
expect(pt.common.save, 'Guardar');
expect(ptBr.common.save, 'Salvar');
});
test('pt_BR translates a key added after the initial pt rollout', () {
final en = AppLocale.en.buildSync();
final ptBr = AppLocale.ptBr.buildSync();
// savedSearches was a later addition; if pt_BR were missing it, this
// would silently surface the English fallback instead.
expect(ptBr.savedSearches.title, isNot(en.savedSearches.title));
expect(ptBr.savedSearches.title, isNotEmpty);
});
}