465 lines
29 KiB
JavaScript
465 lines
29 KiB
JavaScript
/* 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.<br>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,<br>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 <b>${who}</b> desde ${d}.`,
|
|
dueWas: (d, n) => `<br>Devolução prevista ${d} — <b>há ${n} dias</b>.`,
|
|
issuedToOn: (who, d) => `Entregue a <b>${who}</b> em ${d}`,
|
|
dueBack: (d) => `<br>Devolução prevista ${d}.`,
|
|
noDueDate: "<br>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 <b>${total} ${total === 1 ? "cópia" : "cópias"}</b>. ${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 <em>reserva</em> e não a <em>no armário</em>, 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 <b>${c}</b>, atualizados <b>${u}</b>.`,
|
|
impTitle: "Importar de uma folha de cálculo",
|
|
impHelp: "Cole CSV. Colunas obrigatórias: <b>tag</b>, <b>door</b>, <b>building</b>. 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 <b>${i}</b> itens, criadas ${d} portas e ${c} armários.`,
|
|
impSkipped: (n, list) => `<br>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.<br>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,<br>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 <b>${w}</b> since ${d}.`,
|
|
dueWas: (d, n) => `<br>Due back ${d} — <b>${n} days ago</b>.`,
|
|
issuedToOn: (w, d) => `Issued to <b>${w}</b> on ${d}`,
|
|
dueBack: (d) => `<br>Due back ${d}.`,
|
|
noDueDate: "<br>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 `<b>${total} cop${total === 1 ? "y" : "ies"}</b> 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 <em>reserve</em> rather than <em>in cabinet</em>, 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 <b>${c}</b>, updated <b>${u}</b>.`,
|
|
impTitle: "Import from a spreadsheet",
|
|
impHelp: "Paste CSV. Required columns: <b>tag</b>, <b>door</b>, <b>building</b>. 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 <b>${i}</b> items, created ${d} doors and ${c} cabinets.`,
|
|
impSkipped: (n, list) => `<br>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; }
|