/* Key register — translations. Add a language by copying the `pt` block. Set UI_LANG in .env to choose. */ "use strict"; var I18N = { pt: { _months: ["jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"], brand: "Registo de Chaves", appTitle: "Armários de chaves", admin: "Administração", loginSub: "Introduza o código partilhado.", loginPlaceholder: "Código de acesso", loginBtn: "Entrar", loginWrong: "Código incorreto.", loginMany: "Demasiadas tentativas. Aguarde um minuto.", loginShow: "Mostrar código", loginHide: "Ocultar código", loginFoot: "Acesso restrito à rede privada da igreja.", loading: "A carregar…", noServer: "Não foi possível contactar o servidor.", back: "Voltar ao registo", tabBoard: "Quadro", tabDoors: "Portas", tabPeople: "Pessoas", tabLog: "Movimentos", tabJournal: "Diário", cabinetsN: (n) => `${n} ${n === 1 ? "armário" : "armários"}`, keysIn: (a, b) => `${a} de ${b} chaves no armário`, issuedN: "emprestadas", overdueN: "em atraso", reserveN: "de reserva", searchPerson: "Procurar pessoa…", /* pedido de acesso */ reqTitle: "Pedido de acesso", reqIntro: "Preencha este formulário para pedir acesso a uma zona da igreja. O pedido é analisado pelo responsável pelas chaves — não recebe nenhuma chave por aqui.", reqName: "Nome completo", reqDept: "Departamento ou grupo", reqContact: "Telefone ou email", reqAreas: "Zonas a que precisa de aceder", reqDetail: "Para quê, e durante quanto tempo", reqDetailPh: "Ex.: ensaios do coro às quartas, a partir de setembro.", reqPin: "Código da igreja", reqPinHelp: "Peça o código ao responsável pelas chaves.", reqSend: "Enviar pedido", reqSending: "A enviar…", reqOk: "Pedido enviado.", reqOkMore: "O responsável pelas chaves vai analisá-lo. Não guarde este separador aberto.", reqAnother: "Enviar outro pedido", reqNeedName: "Indique o seu nome.", reqNeedArea: "Escolha pelo menos uma zona.", reqWrongPin: "Código incorreto.", reqTooMany: "Demasiados pedidos. Tente mais tarde.", reqFoot: "Nenhuma chave é entregue através deste formulário.", /* caixa de pedidos */ reqHandPhone: "Passar o telemóvel para alguém preencher", reqKioskDone: "Pode devolver o telemóvel.", reqKioskNext: "Novo pedido", reqNoPinStaff: "Sem código — o pedido está a ser feito a partir da aplicação.", reqFormPublic: "Formulário público, protegido por código.", reqFormOpen: "FORMULÁRIO PÚBLICO SEM CÓDIGO — qualquer pessoa que descubra o endereço pode enviar pedidos.", reqFormPrivate: "Formulário só acessível a quem entra na aplicação.", reqFormOpenIt: "Abrir formulário", reqInbox: "Pedidos de acesso", reqPending: (n) => `${n} por tratar`, reqNone: "Nenhum pedido pendente.", reqOn: (d) => `Recebido em ${d}`, reqMarkDone: "Marcar como tratado", reqNotePh: "O que foi decidido?", reqHandled: "Tratado", reqHandledOn: (d) => `Tratado em ${d}`, /* reports */ reports: "Relatórios", print: "Imprimir", printPdf: "Imprimir / PDF", repOut: "Chaves emprestadas", repOverdue: "Chaves em atraso", repPerson: "Recibo por pessoa", repInventory: "Inventário completo", repAudit: "Folha de auditoria", repGenerated: (d, h) => `Gerado em ${d} às ${h}`, repNothing: "Nada a mostrar.", repChoosePerson: "Escolha uma pessoa", stKeysOut: "emprestadas", stPeople: "pessoas", stOverdue: "em atraso", stTotal: "total", stInCab: "no armário", stReserve: "reserva", cTag: "Nº", cDoor: "Porta", cBuilding: "Edifício", cCabinet: "Armário", cPerson: "Pessoa", cDept: "Departamento", cOut: "Entregue", cDue: "Devolver até", cDays: "Dias", cStatus: "Estado", cHook: "Gancho", cCheck: "Conf.", repSignedOn: (d) => `Assinado em ${d}`, repNoSig: "Sem assinatura registada", repReceiptTitle: "Recibo de chaves", repReceiptIntro: (n) => `Declaro ter em minha posse ${n === 1 ? "a chave" : "as"} ${n === 1 ? "" : n + " chaves"} abaixo indicadas, e comprometo-me a devolvê-${n === 1 ? "la" : "las"} quando solicitado.`, repHolder: "Titular", repResponsible: "Responsável pelas chaves", repDate: "Data", repAuditIntro: "Confirme cada chave presente no armário e assinale a caixa. As chaves emprestadas estão indicadas.", repAuditBy: "Auditoria feita por", repNotes: "Observações", repAllCabinets: "Todos os armários", allTile: "Todos", statuses: { in: "no armário", out: "emprestada", reserve: "reserva", lost: "perdida", retired: "retirada" }, fEverything: "Tudo", fKeys: "Só chaves", fTags: "Etiquetas", fOut: "Emprestadas", fLate: "Em atraso", lgIn: "No armário", lgOut: "Emprestada", lgRes: "Reserva", lgLate: "Em atraso", lgTag: "Etiqueta de alarme", outCount: (n) => `${n} fora`, boardNote: "Um gancho por cada chave física, pela ordem do armário.
Para saber quem abre uma porta, use Portas.", noMatch: "Nada corresponde a esse filtro.", noKeysYet: "Ainda não há chaves. Adicione-as na", onHook: "No seu gancho", reserveCopy: "Cópia de reserva", lost: "Perdida", retired: "Retirada", allIn: "todas no armário", copies: (n) => `${n} ${n === 1 ? "cópia" : "cópias"}`, doorsN: (n) => `${n} ${n === 1 ? "porta" : "portas"}`, searchPlaceholder: "Porta, número de chave, pessoa ou nota", nothingFound: (q) => `Nada encontrado para «${q}».`, doorsNote: "Uma linha por porta. Os pontos são as cópias — cheio está no armário,
vazio está com alguém, cinzento é a reserva.", tagsSection: "Etiquetas de alarme", holdingNow: "Com chaves neste momento", nothingOut: "Sem chaves", inactive: "inativo", keysWord: (n) => `${n} ${n === 1 ? "chave" : "chaves"}`, tagsWord: (n) => `${n} ${n === 1 ? "etiqueta" : "etiquetas"}`, noPeopleYet: "Ainda não há pessoas. Adicione-as na", logTitle: "Todas as entregas, mais recentes primeiro", toWord: "para", backFrom: "devolvida por", signedMark: "assinado", noHandovers: "Ainda não há entregas registadas.", logNote: "As linhas só são acrescentadas, nunca alteradas.", dirOut: "saída", dirIn: "entrada", newEntry: "Nova entrada", journalPlaceholder: "Auditoria feita, fechadura mudada, selo de reserva quebrado…", addJournal: "Adicionar ao diário", journalTitle: "Diário dos armários", journalEmpty: "Ainda não há registos.", journalNote: "Para tudo o que pertence a um armário e não a uma chave.", withSince: (who, d) => `Com ${who} desde ${d}.`, dueWas: (d, n) => `
Devolução prevista ${d} — há ${n} dias.`, issuedToOn: (who, d) => `Entregue a ${who} em ${d}`, dueBack: (d) => `
Devolução prevista ${d}.`, noDueDate: "
Sem data de devolução — posse permanente.", reserveLine: "Cópia de reserva, fora das instalações. A entrega fica automaticamente no diário.", lostLine: "Dada como perdida. Considere mudar a fechadura desta porta.", retiredLine: "Retirada. Mantida apenas pelo histórico.", inCabinet: (c) => `No ${c}`, atHook: (h) => `, gancho ${h}`, fType: "Tipo", vKey: "Chave de porta", vTag: "Etiqueta NFC de alarme", fKeptIn: "Guardada em", fHook: "Gancho", fLockGroup: "Grupo de fechadura", fChipUid: "UID do chip", fMaster: "Chave-mestra", yes: "Sim", no: "Não", fCopiesLiveIn: "Cópias guardadas em", fHoldingNow: "Tem agora", fReturnedPast: "Devolvidas no passado", fPhone: "Telefone", seeAllCopies: (n) => `Ver todas as ${n} cópias`, noteOnHandover: "Nota desta entrega", noteOnKey: "Nota sobre esta chave — permanente", notePlaceholder: "Algo que a próxima pessoa deva saber.", saveNote: "Guardar nota", noteOnDoor: "Nota sobre esta porta", issueTo: "Entregar a alguém", breakSeal: "Quebrar o selo e entregar", takeBack: "Receber de volta", close: "Fechar", cancel: "Cancelar", history: "Histórico", neverIssued: "Nunca foi entregue.", returnedOn: (d) => `devolvida em ${d}`, stillHolding: "ainda a tem", stClosed: "fechado", stOpen: "aberto", stLate: "atraso", currentlyHolds: "Tem neste momento", holdsNothing: "Não tem nada de momento.", returnedSection: "Devolvidas", heldFromTo: (a, b) => `esteve de ${a} a ${b}`, itemsN: (n) => `${n} ${n === 1 ? "item" : "itens"}`, fromCabinets: (s) => `de ${s}`, issueTitle: (t) => `Entregar ${t}`, fromThe: (c) => `do ${c}`, whoTakes: "Quem a vai levar?", reserveWarn: "Esta é uma cópia de último recurso. Ao entregá-la, a porta fica sem reserva.", noActivePeople: "Não há pessoas ativas. Adicione-as na", handover: "Entrega", backBy: "Devolver até", dNone: "Sem data — permanente", d7: "Uma semana", d30: "Um mês", d90: "Três meses", whyNote: "Motivo — nota desta entrega", whyPlaceholder: "Concerto de Natal, revisão da caldeira, novo sacristão…", signature: "Assinatura", signHint: "Dê o telemóvel para assinar", clearSig: "Limpar", confirmHandover: "Confirmar entrega", everyCopy: "Todas as cópias desta chave", sameLock: "Mesmo grupo de fechadura — estas também abrem", doorSummary: (total, out, inC, res, lst) => { const parts = []; if (out) parts.push(`${out} com pessoas`); parts.push(`${inC} no armário`); if (res) parts.push(`${res} de reserva`); if (lst) parts.push(`${lst} perdidas`); return `Existem ${total} ${total === 1 ? "cópia" : "cópias"}. ${parts.join(", ")}.`; }, tHandedOver: "Entregue", tBackIn: "De volta ao armário", tNoteSaved: "Nota guardada", tJournalAdded: "Entrada adicionada", tSaved: "Guardado", tRemoved: "Removido", errors: { "already issued": "Esta chave já está emprestada.", "not currently issued": "Esta chave não está emprestada.", "no such item": "Chave não encontrada.", "no such person": "Pessoa não encontrada.", "not issuable": "Esta chave não pode ser entregue.", "tag required": "O número da chave é obrigatório.", "name required": "O nome é obrigatório.", "that tag is already used": "Esse número de chave já existe.", "door number already used": "Esse número de porta já existe.", "num, building and name required": "Número, edifício e nome são obrigatórios.", "id and name required": "Código e nome são obrigatórios.", "confirmation phrase required": "Tem de escrever a frase de confirmação.", "empty": "Está vazio.", "locked": "Sessão terminada. Recarregue a página.", "wrong pin": "Código incorreto.", "too many requests": "Demasiados pedidos. Tente mais tarde.", }, /* admin */ aItems: "Chaves e etiquetas", aDoors: "Portas", aPeople: "Pessoas", aCabinets: "Armários", aKinds: "Tipos", aData: "Importar / cópias", aAudit: "Alterações", aKindsHelp: "Os tipos de objeto que guarda. A forma diz o que é, o preenchimento diz onde está.", aAddKind: "+ Adicionar tipo", fKindCode: "Código", fKindName: "Nome", fShape: "Forma", fColour: "Cor", shCircle: "Círculo", shRounded: "Quadrado arredondado", shSquare: "Quadrado", deleteKind: "Eliminar este tipo", kindNote: "O código é usado nas importações (coluna kind) e não deve mudar depois de haver chaves com ele. O nome pode mudar à vontade.", kindInUse: (n) => `${n} itens usam este tipo.`, aItemsHelp: (n) => `Uma linha por cada chave física. ${n} no total.`, aFilter: "Filtrar por número, porta ou nota", aAddItem: "+ Adicionar chave ou etiqueta", aAddDoor: "+ Adicionar porta", aAddPerson: "+ Adicionar pessoa", aAddCabinet: "+ Adicionar armário", aTag: "Nº", aDoor: "Porta / zona", aCabinet: "Armário", aHook: "Gancho", aStatus: "Estado", aEdit: "Editar", aNothing: "Ainda não há nada.", aDoorsHelp: (n) => `As portas físicas. As chaves apontam para estas. ${n} no total.`, aNo: "Nº", aLock: "Fechadura", aCopies: "Cópias", aPeopleHelp: "Titulares de chaves. Nunca fazem login — isto é só quem pode receber uma chave.", aName: "Nome", aDept: "Departamento", aHolding: "Tem", aCabinetsHelp: "Onde as chaves ficam fisicamente. Um armário não é um edifício — o escritório pode guardar mestras da igreja.", aOffSite: "fora das instalações", aItemsCount: (n) => `${n} itens`, fNum: "Número", fBuilding: "Edifício", fDoorName: "Nome da porta", fNote: "Nota", fShortCode: "Código curto", fShortName: "Nome curto", fFullName: "Nome completo", fWhereIs: "Onde está e o que a abre", fSort: "Ordem no quadro", fSortHelp: "Número menor aparece primeiro. Deixe a reserva com um número alto para ficar no fim.", fOffSiteLabel: "Fora das instalações — depósito de reserva", fZoneKeys: "Porta (chaves)", fZoneTags: "Zona de alarme (etiquetas)", fNoneTag: "— nenhuma / etiqueta de alarme —", fNone: "— nenhum —", fIsMaster: "É uma chave-mestra", fPermNote: "Nota permanente", fFunction: "Função", fEmail: "Email", fActiveLabel: "Ativo — pode receber chaves", save: "Guardar", deleteRetire: "Eliminar ou retirar esta chave", deleteDoor: "Eliminar esta porta", deactivate: "Desativar", deleteCabinet: "Eliminar este armário", retireNote: "Se tiver histórico de entregas é retirada, nunca eliminada — o histórico tem de sobreviver.", peopleNote: "As pessoas nunca são eliminadas. Aparecem em entregas antigas, e eliminá-las tornaria esse histórico anónimo.", lockGroupNote: "O grupo de fechadura liga portas que partilham o mesmo perfil de chave, para saber o que mais uma chave perdida poderá abrir.", offSiteNote: "As chaves devolvidas a um depósito fora das instalações voltam a reserva e não a no armário, ficando fora da circulação normal.", holdsWarn: (n, tags) => `Tem ${n} ${n === 1 ? "item" : "itens"}: ${tags}. Receba-os de volta antes de desativar.`, impWhat: "O que quer importar?", impOrder: "Importe por esta ordem — as chaves apontam para portas e armários, que têm de existir primeiro.", impItems: "Chaves e etiquetas", impDoors: "Portas", impPeople: "Pessoas", impCabinets: "Armários", impResult2: (c, u) => `Criados ${c}, atualizados ${u}.`, impTitle: "Importar de uma folha de cálculo", impHelp: "Cole CSV. Colunas obrigatórias: tag, door, building. Opcionais: lock_group, cabinet, hook, master, status, kind, notes. As portas e armários que não existirem são criados.", impBtn: "Importar", impResult: (i, d, c) => `Importados ${i} itens, criadas ${d} portas e ${c} armários.`, impSkipped: (n, list) => `
Ignorados ${n}: ${list}`, impNothing: "Não há nada para importar", expTitle: "Exportar", expHelp: "Todo o registo como folha de cálculo. Útil para uma cópia impressa no armário, e prova de que nunca fica preso a esta aplicação.", expBtn: "Descarregar CSV", bkTitle: "Cópia de segurança", bkHelp: "Um único ficheiro SQLite, seguro de descarregar com a aplicação a funcionar. Guarde uma cópia fora desta máquina.", bkBtn: "Descarregar base de dados", wipeTitle: "Apagar tudo", wipeWarn: "Elimina todas as chaves, portas, pessoas, entregas e entradas do diário. Os armários são mantidos. Não há como desfazer — faça primeiro uma cópia de segurança.", wipePlaceholder: "Escreva: DELETE EVERYTHING", wipeBtn: "Apagar o registo", wipeDone: "Registo apagado", auditTitle: "Registo de alterações", auditHelp: "Alterações administrativas, mais recentes primeiro. Com duas pessoas a editar, «quem mudou a 12-B e quando» é uma pergunta que acaba por surgir.", aWhen: "Quando", aWhat: "O quê", aDetail: "Detalhe", imported: "Importado", }, en: { _months: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], brand: "Key Register", appTitle: "Key cabinets", admin: "Admin", loginSub: "Enter the shared passcode.", loginPlaceholder: "Passcode", loginBtn: "Unlock", loginWrong: "Wrong passcode.", loginMany: "Too many attempts. Wait a minute.", loginShow: "Show passcode", loginHide: "Hide passcode", loginFoot: "Restricted to the church private network.", loading: "Loading…", noServer: "Can't reach the server.", back: "Back to the register", tabBoard: "Board", tabDoors: "Doors", tabPeople: "People", tabLog: "Log", tabJournal: "Journal", cabinetsN: (n) => `${n} store${n === 1 ? "" : "s"}`, keysIn: (a, b) => `${a} of ${b} keys in`, issuedN: "issued", overdueN: "overdue", reserveN: "reserve", searchPerson: "Search for a person…", /* access request */ reqTitle: "Access request", reqIntro: "Use this form to request access to an area of the church. The keyholder reviews every request — no key is issued here.", reqName: "Full name", reqDept: "Department or group", reqContact: "Phone or email", reqAreas: "Areas you need access to", reqDetail: "What for, and for how long", reqDetailPh: "e.g. choir rehearsals on Wednesdays, from September.", reqPin: "Church code", reqPinHelp: "Ask the keyholder for the code.", reqSend: "Send request", reqSending: "Sending…", reqOk: "Request sent.", reqOkMore: "The keyholder will review it. You can close this tab.", reqAnother: "Send another request", reqNeedName: "Please enter your name.", reqNeedArea: "Choose at least one area.", reqWrongPin: "Wrong code.", reqTooMany: "Too many requests. Try again later.", reqFoot: "No key is handed over through this form.", reqHandPhone: "Hand the phone to someone to fill in", reqKioskDone: "You can hand the phone back.", reqKioskNext: "New request", reqNoPinStaff: "No code needed — this request is being made from inside the app.", reqFormPublic: "Form is public, protected by a code.", reqFormOpen: "FORM IS PUBLIC WITH NO CODE — anyone who finds the address can submit.", reqFormPrivate: "Form is only reachable by people signed in to the app.", reqFormOpenIt: "Open the form", reqInbox: "Access requests", reqPending: (n) => `${n} to handle`, reqNone: "No pending requests.", reqOn: (d) => `Received ${d}`, reqMarkDone: "Mark as handled", reqNotePh: "What was decided?", reqHandled: "Handled", reqHandledOn: (d) => `Handled ${d}`, /* reports */ reports: "Reports", print: "Print", printPdf: "Print / PDF", repOut: "Keys currently issued", repOverdue: "Overdue keys", repPerson: "Receipt per person", repInventory: "Full inventory", repAudit: "Audit sheet", repGenerated: (d, h) => `Generated ${d} at ${h}`, repNothing: "Nothing to show.", repChoosePerson: "Choose a person", stKeysOut: "issued", stPeople: "people", stOverdue: "overdue", stTotal: "total", stInCab: "in cabinet", stReserve: "reserve", cTag: "Tag", cDoor: "Door", cBuilding: "Building", cCabinet: "Cabinet", cPerson: "Person", cDept: "Department", cOut: "Issued", cDue: "Due back", cDays: "Days", cStatus: "Status", cHook: "Hook", cCheck: "Check", repSignedOn: (d) => `Signed ${d}`, repNoSig: "No signature on record", repReceiptTitle: "Key receipt", repReceiptIntro: (n) => `I confirm that I hold the ${n === 1 ? "key" : n + " keys"} listed below, and undertake to return ${n === 1 ? "it" : "them"} on request.`, repHolder: "Holder", repResponsible: "Keyholder in charge", repDate: "Date", repAuditIntro: "Confirm each key present in the cabinet and tick the box. Issued keys are marked.", repAuditBy: "Audit carried out by", repNotes: "Notes", repAllCabinets: "All cabinets", allTile: "All", statuses: { in: "in cabinet", out: "issued", reserve: "reserve", lost: "lost", retired: "retired" }, fEverything: "Everything", fKeys: "Keys only", fTags: "Alarm tags", fOut: "Currently out", fLate: "Overdue", lgIn: "In cabinet", lgOut: "Issued", lgRes: "Reserve", lgLate: "Overdue", lgTag: "Alarm tag", outCount: (n) => `${n} out`, boardNote: "One peg per piece of metal, in hook order.
For \u201cwho can open this door\u201d, use Doors.", noMatch: "Nothing matches that filter.", noKeysYet: "No keys yet. Add them in", onHook: "On its hook", reserveCopy: "Reserve copy", lost: "Lost", retired: "Retired", allIn: "all in", copies: (n) => `${n} cop${n === 1 ? "y" : "ies"}`, doorsN: (n) => `${n} door${n === 1 ? "" : "s"}`, searchPlaceholder: "Door, key number, person, or note", nothingFound: (q) => `Nothing found for \u201c${q}\u201d.`, doorsNote: "One row per door. Dots are its copies — filled is in a cabinet,
hollow is out with someone, grey is reserve.", tagsSection: "Alarm tags", holdingNow: "Holding something now", nothingOut: "Nothing out", inactive: "inactive", keysWord: (n) => `${n} key${n === 1 ? "" : "s"}`, tagsWord: (n) => `${n} tag${n === 1 ? "" : "s"}`, noPeopleYet: "No people yet. Add them in", logTitle: "Every handover, newest first", toWord: "to", backFrom: "back from", signedMark: "signed", noHandovers: "No handovers recorded yet.", logNote: "Rows are only ever added, never edited.", dirOut: "out", dirIn: "in", newEntry: "New entry", journalPlaceholder: "Audit done, lock changed, reserve seal broken…", addJournal: "Add to journal", journalTitle: "Cabinet journal", journalEmpty: "Nothing recorded yet.", journalNote: "For everything that belongs to a cabinet rather than to one key.", withSince: (w, d) => `With ${w} since ${d}.`, dueWas: (d, n) => `
Due back ${d} — ${n} days ago.`, issuedToOn: (w, d) => `Issued to ${w} on ${d}`, dueBack: (d) => `
Due back ${d}.`, noDueDate: "
No return date — held permanently.", reserveLine: "Reserve copy, off site. Issuing it is logged in the journal automatically.", lostLine: "Reported lost. Consider re-keying this door.", retiredLine: "Retired. Kept for its history only.", inCabinet: (c) => `In the ${c}`, atHook: (h) => `, hook ${h}`, fType: "Type", vKey: "Door key", vTag: "NFC alarm tag", fKeptIn: "Kept in", fHook: "Hook", fLockGroup: "Lock group", fChipUid: "Chip UID", fMaster: "Master key", yes: "Yes", no: "No", fCopiesLiveIn: "Copies live in", fHoldingNow: "Holding now", fReturnedPast: "Returned in the past", fPhone: "Phone", seeAllCopies: (n) => `See all ${n} copies`, noteOnHandover: "Note on this handover", noteOnKey: "Note on this key — permanent", notePlaceholder: "Anything the next person should know.", saveNote: "Save note", noteOnDoor: "Note on this door", issueTo: "Issue to someone", breakSeal: "Break seal and issue", takeBack: "Take it back", close: "Close", cancel: "Cancel", history: "History", neverIssued: "Never been issued.", returnedOn: (d) => `returned ${d}`, stillHolding: "still holding it", stClosed: "closed", stOpen: "open", stLate: "late", currentlyHolds: "Currently holds", holdsNothing: "Holds nothing right now.", returnedSection: "Returned", heldFromTo: (a, b) => `held ${a} → ${b}`, itemsN: (n) => `${n} item${n === 1 ? "" : "s"}`, fromCabinets: (s) => `from ${s}`, issueTitle: (t) => `Issue ${t}`, fromThe: (c) => `from the ${c}`, whoTakes: "Who is taking it?", reserveWarn: "This is a last-resort copy. Issuing it leaves the door without a reserve.", noActivePeople: "No active people. Add them in", handover: "Handover", backBy: "Back by", dNone: "No date — permanent", d7: "One week", d30: "One month", d90: "Three months", whyNote: "Why — note on this handover", whyPlaceholder: "Christmas concert, boiler service, new caretaker…", signature: "Signature", signHint: "Hand them the phone to sign", clearSig: "Clear", confirmHandover: "Confirm handover", everyCopy: "Every copy of this key", sameLock: "Same lock group — these open too", doorSummary: (total, out, inC, res, lst) => { const parts = []; if (out) parts.push(`${out} with people`); parts.push(`${inC} in cabinets`); if (res) parts.push(`${res} reserve`); if (lst) parts.push(`${lst} lost`); return `${total} cop${total === 1 ? "y" : "ies"} exist. ${parts.join(", ")}.`; }, tHandedOver: "Handed over", tBackIn: "Back in the cabinet", tNoteSaved: "Note saved", tJournalAdded: "Journal entry added", tSaved: "Saved", tRemoved: "Removed", errors: {}, aItems: "Keys & tags", aDoors: "Doors", aPeople: "People", aCabinets: "Cabinets", aData: "Import / backup", aAudit: "Change log", aItemsHelp: (n) => `One row per physical piece of metal. ${n} in total.`, aFilter: "Filter by tag, door, or note", aAddItem: "+ Add a key or tag", aAddDoor: "+ Add a door", aAddPerson: "+ Add a person", aAddCabinet: "+ Add a cabinet", aTag: "Tag", aDoor: "Door / zone", aCabinet: "Cabinet", aHook: "Hook", aStatus: "Status", aEdit: "Edit", aNothing: "Nothing yet.", aDoorsHelp: (n) => `The physical doors. Keys point at these. ${n} in total.`, aNo: "No.", aLock: "Lock", aCopies: "Copies", aPeopleHelp: "Key holders. They never log in — this is just who can be handed a key.", aName: "Name", aDept: "Department", aHolding: "Holding", aCabinetsHelp: "Where keys physically live. A cabinet is not a building — the office can hold church masters.", aOffSite: "off site", aItemsCount: (n) => `${n} items`, fNum: "Number", fBuilding: "Building", fDoorName: "Door name", fNote: "Note", fShortCode: "Short code", fShortName: "Short name", fFullName: "Full name", fWhereIs: "Where it is, and what opens it", fSort: "Board order", fSortHelp: "Lower numbers come first. Give the reserve store a high number to keep it last.", fOffSiteLabel: "Off site — reserve store", fZoneKeys: "Door (keys)", fZoneTags: "Alarm zone (tags)", fNoneTag: "— none / alarm tag —", fNone: "— none —", fIsMaster: "This is a master key", fPermNote: "Permanent note", fFunction: "Function", fEmail: "Email", fActiveLabel: "Active — can be handed keys", save: "Save", deleteRetire: "Delete or retire this key", deleteDoor: "Delete this door", deactivate: "Deactivate", deleteCabinet: "Delete this cabinet", retireNote: "If it has handover history it is retired, never deleted — the history has to survive.", peopleNote: "People are never deleted. They appear in old handovers, and deleting them would make that history anonymous.", lockGroupNote: "Lock group ties doors that share a key profile, so you can see what else a lost key might open.", offSiteNote: "Keys returned to an off-site store go back to reserve rather than in cabinet, so they stay out of everyday circulation.", holdsWarn: (n, tags) => `Currently holds ${n} item${n === 1 ? "" : "s"}: ${tags}. Take those back before deactivating.`, impWhat: "What do you want to import?", impOrder: "Import in this order — keys point at doors and cabinets, which must exist first.", impItems: "Keys & tags", impDoors: "Doors", impPeople: "People", impCabinets: "Cabinets", impResult2: (c, u) => `Created ${c}, updated ${u}.`, impTitle: "Import from a spreadsheet", impHelp: "Paste CSV. Required columns: tag, door, building. Optional: lock_group, cabinet, hook, master, status, kind, notes. Doors and cabinets that don't exist are created.", impBtn: "Import", impResult: (i, d, c) => `Imported ${i} items, created ${d} doors and ${c} cabinets.`, impSkipped: (n, list) => `
Skipped ${n}: ${list}`, impNothing: "Nothing to import", expTitle: "Export", expHelp: "The whole register as a spreadsheet. Useful for a printed copy in the cabinet, and proof you are never locked into this app.", expBtn: "Download CSV", bkTitle: "Backup", bkHelp: "One SQLite file, safe to download while the app is running. Keep a copy somewhere that is not this machine.", bkBtn: "Download database", wipeTitle: "Clear everything", wipeWarn: "Deletes every key, door, person, handover and journal entry. Cabinets are kept. There is no undo — download a backup first.", wipePlaceholder: "Type: DELETE EVERYTHING", wipeBtn: "Clear the register", wipeDone: "Register cleared", auditTitle: "Change log", auditHelp: "Admin changes, newest first. With two of you editing, \u201cwho moved 12-B and when\u201d is a question that comes up.", aWhen: "When", aWhat: "What", aDetail: "Detail", imported: "Imported", }, }; /* Chosen by the server from UI_LANG; falls back to Portuguese. `var`, not `let`, so the binding is a real global shared with app.js and admin.js rather than scoped to this script. */ var T = I18N.pt; function setLang(code) { T = I18N[code] || I18N.pt; document.documentElement.lang = I18N[code] ? code : "pt"; } /* Server errors arrive in English; show a translated version when we have one. */ function errMsg(m) { return (T.errors && T.errors[m]) || m; }