Files
template-app/apps/web/src/ui/messages.ts
T
2026-11-14 09:56:45 +00:00

419 lines
18 KiB
TypeScript

// SPDX-License-Identifier: LicenseRef-ConusAI-Template-1.0
// This app's own message catalogue, merged over the kit's (spec §10.4). Every string a page shows
// is a key here, in English and in Lithuanian, so a locale is a catalogue and not a code change.
//
// Every module's messages -- the kernel's included -- come from its manifest (`i18n: { en, lt }`) and are
// merged by kit-i18n from the registry, so a module's strings reach the pages with no edit outside the
// module. What is here is the app shell's own: the `app.*` messages.
import { appModules } from "@app/modules"
import { buildRegistry } from "@conusai-kit/core"
import { type Catalogues, moduleCatalogues } from "@conusai-kit/i18n"
const en = {
consent: {
title: "Privacy choices",
body: "Accept optional analytics, or reject them. Accepting and rejecting are equally easy. Session replay is separate and stays off unless you select it.",
replay: "Also allow session replay, with text, inputs and media masked",
accept: "Accept analytics",
reject: "Reject analytics and replay",
reopen: "Privacy choices",
gpc: "Global Privacy Control is on: analytics and replay stay off.",
},
app: {
signIn: "Sign in",
signOut: "Sign out",
signedOut: "You are signed out.",
signedOutBody: "Close this tab, or sign in again.",
home: "Home",
organizations: "Organizations",
chooseOrganization: "Choose an organization to continue.",
noOrganizations: "You are not a member of an organization yet.",
askForInvitation: "Ask your organization's administrator for an invitation.",
createOrganization: "Create an organization",
name: "Name",
slug: "Short name",
create: "Create",
cancel: "Cancel",
role: "Role",
email: "E-mail address",
invite: "Invite",
remove: "Remove",
save: "Save",
workspaces: "Workspaces",
chooseWorkspace: "Choose a workspace to view its projects.",
projects: "Projects",
members: "Members",
invitations: "Invitations",
settings: "Settings",
audit: "Audit",
auditEmpty: "No audit events for this organization yet.",
action: "Action",
outcome: "Outcome",
when: "When",
resource: "Resource",
status: "Status",
failed: "That did not work: {detail}",
open: "Open",
workspace: "Workspace",
project: "Project",
},
shell: {
organization: "Organization",
language: "Language",
languageEn: "English",
languageLt: "Lietuvių",
theme: "Theme",
themeDark: "Dark",
themeLight: "Light",
themeSystem: "System",
switchToLight: "Switch to light theme",
switchToDark: "Switch to dark theme",
account: "Signed in as {name}",
sections: "Settings sections",
helpSections: "Help sections",
guides: "Guides",
support: "Support",
general: "General",
organizationTitle: "Organization",
defaultLanguage: "Default language",
defaultLanguageHint: "New members start in this language.",
saved: "Saved",
projects: "Projects",
},
onboarding: {
title: "Create your organization",
description: "Your organization holds members, workspaces and projects. You will be its owner.",
name: "Organization name",
nameHelp: "Usually your company or team. You can change it later.",
address: "Address",
addressHelp: "Lowercase letters, numbers and hyphens. Used in links.",
continue: "Continue",
required: "Fill this in.",
addressInvalid: "Use lowercase letters, numbers and single hyphens.",
addressTaken: "This address is taken. Choose another.",
failed: "The organization could not be created. Try again.",
workspaceName: "General",
workspaceSlug: "general",
},
signin: {
title: "Sign in",
createAccount: "Create an account",
devTitle: "Development sign-in",
devHelp:
"This deployment has no identity provider, so any e-mail address signs in. It exists for development and is refused in production.",
devSubmit: "Sign in",
notConfigured:
"Sign-in is not configured for this deployment. Ask the person who runs it to set an identity provider.",
error: {
sessionExpired: "Your session has ended. Sign in again.",
noTransaction: "That sign-in was not started in this browser, or it took too long. Start again.",
denied: "The identity provider did not let you in. Try again, or use another account.",
provider: "The identity provider could not complete the sign-in. Try again in a moment.",
failed: "Signing in did not work. Try again.",
},
// kit:convex-better-auth:begin
account: {
name: "Name",
password: "Password",
passwordHelp: "At least {min} characters.",
signIn: "Sign in",
signUp: "Create the account",
toSignUp: "No account yet? Create one",
toSignIn: "Already have an account? Sign in",
signUpTitle: "Create an account",
signUpIntro: "Create an account with your e-mail address and a password.",
error: {
invalid: "That e-mail address and password do not match an account.",
exists: "An account with that e-mail address exists already. Sign in instead.",
disabled: "This account is disabled. Ask the people who run this app.",
rateLimited: "Too many attempts. Wait a moment and try again.",
unavailable: "Signing in is not possible right now. Try again in a moment.",
failed: "That did not work. Check the form and try again.",
},
},
// kit:convex-better-auth:end
},
invite: {
title: "You are invited",
lead: "{email} is invited to join {org} as {role}.",
leadNoRole: "{email} is invited to join {org}.",
expires: "The link works once, until {date}.",
createAccount: "Create your account",
haveAccount: "I have an account: sign in",
signInFirst: "Sign in with the e-mail address the invitation was sent to, then come back to this page.",
signedInAs: "You are signed in as {email}.",
otherAccount: "This invitation is for {email}. Sign in with that address to accept it.",
accept: "Accept the invitation",
accepted: "You joined {org}.",
switchAccount: "Sign in with another account",
error: {
unknown: "This invitation link is not valid. Check that you have all of it, or ask for a new one.",
invalid:
"This invitation is not valid for the account you are signed in with. Sign in with the address it was sent to, or ask for a new one.",
used: "This invitation has already been used. Sign in to open the organization.",
revoked: "This invitation was revoked. Ask an administrator of the organization for a new one.",
expired: "This invitation has expired. Ask an administrator of the organization for a new one.",
member: "You are already a member of this organization.",
failed: "The invitation could not be accepted. Try again.",
},
},
boundary: {
errorTitle: "Something went wrong",
errorBody: "The page could not be shown. Try again. If it keeps happening, tell the person who runs this app.",
errorCode: "Error code: {digest}",
retry: "Try again",
notFoundTitle: "Page not found",
notFoundBody: "There is nothing at this address, or you do not have access to it.",
forbiddenTitle: "You do not have access",
forbiddenBody: "Your role does not allow this page. Ask an administrator of the organization.",
home: "Back to the start",
loading: "Loading",
},
workspace: {
title: "Workspace {name}",
list: "Workspaces",
none: "There are no workspaces you can see.",
create: "Create a workspace",
visibility: "Visibility",
visibilityOrg: "Everyone in the organization",
visibilityRestricted: "Invited members only",
default: "Default",
projects: "Projects",
overview: "Workspace overview",
group: "Workspace",
projectGroup: "Project",
chooseProject: "Choose a project",
switchProject: "Switch project",
organizationSettings: "Organization settings",
nextAction: "Open a project to continue its work, or choose a workspace tool from the sidebar.",
projectCount: "{count, plural, one {# project} other {# projects}}",
noProjects: "There are no projects in this workspace yet.",
createProject: "Create a project",
module: "Module",
},
project: {
title: "Project {name}",
overview: "Project overview",
work: "Work in this project",
noSections: "This project has no sections available to you.",
archived: "This project is archived.",
module: "Created by the module {module}",
},
} as const
const lt = {
consent: {
title: "Privatumo pasirinkimai",
body: "Priimkite neprivalomą analitiką arba ją atmeskite. Priimti ir atmesti vienodai paprasta. Seanso atkūrimas yra atskiras ir išlieka išjungtas, jei jo nepasirinksite.",
replay: "Taip pat leisti seanso atkūrimą, paslėpus tekstą, įvestis ir vaizdinę medžiagą",
accept: "Priimti analitiką",
reject: "Atmesti analitiką ir atkūrimą",
reopen: "Privatumo pasirinkimai",
gpc: "Įjungtas Global Privacy Control: analitika ir atkūrimas išlieka išjungti.",
},
app: {
signIn: "Prisijungti",
signOut: "Atsijungti",
signedOut: "Jūs atsijungėte.",
signedOutBody: "Užverkite šią kortelę arba prisijunkite iš naujo.",
home: "Pradžia",
organizations: "Organizacijos",
chooseOrganization: "Pasirinkite organizaciją, kad tęstumėte.",
noOrganizations: "Kol kas nesate jokios organizacijos narys.",
askForInvitation: "Paprašykite savo organizacijos administratoriaus pakvietimo.",
createOrganization: "Sukurti organizaciją",
name: "Pavadinimas",
slug: "Trumpasis pavadinimas",
create: "Sukurti",
cancel: "Atsisakyti",
role: "Rolė",
email: "El. pašto adresas",
invite: "Pakviesti",
remove: "Pašalinti",
save: "Išsaugoti",
workspaces: "Darbo erdvės",
chooseWorkspace: "Pasirinkite darbo erdvę, kad peržiūrėtumėte jos projektus.",
projects: "Projektai",
members: "Nariai",
invitations: "Pakvietimai",
settings: "Nustatymai",
audit: "Auditas",
auditEmpty: "Šiai organizacijai audito įrašų dar nėra.",
action: "Veiksmas",
outcome: "Rezultatas",
when: "Kada",
resource: "Objektas",
status: "Būsena",
failed: "Nepavyko: {detail}",
open: "Atverti",
workspace: "Darbo erdvė",
project: "Projektas",
},
shell: {
organization: "Organizacija",
language: "Kalba",
languageEn: "English",
languageLt: "Lietuvių",
theme: "Tema",
themeDark: "Tamsi",
themeLight: "Šviesi",
themeSystem: "Sistemos",
switchToLight: "Perjungti į šviesią temą",
switchToDark: "Perjungti į tamsią temą",
account: "Prisijungęs: {name}",
sections: "Nustatymų skyriai",
helpSections: "Pagalbos skyriai",
guides: "Gidai",
support: "Pagalba",
general: "Bendrieji",
organizationTitle: "Organizacija",
defaultLanguage: "Numatytoji kalba",
defaultLanguageHint: "Nauji nariai pradeda šia kalba.",
saved: "Išsaugota",
projects: "Projektai",
},
onboarding: {
title: "Sukurkite savo organizaciją",
description: "Organizacijoje yra nariai, darbo erdvės ir projektai. Jūsų vaidmuo bus „Savininkas“.",
name: "Organizacijos pavadinimas",
nameHelp: "Dažniausiai tai jūsų įmonė arba komanda. Vėliau galėsite pakeisti.",
address: "Adresas",
addressHelp: "Mažosios raidės, skaičiai ir brūkšneliai. Naudojama nuorodose.",
continue: "Tęsti",
required: "Užpildykite šį lauką.",
addressInvalid: "Naudokite mažąsias raides, skaičius ir pavienius brūkšnelius.",
addressTaken: "Šis adresas užimtas. Pasirinkite kitą.",
failed: "Organizacijos sukurti nepavyko. Bandykite dar kartą.",
workspaceName: "Bendra",
workspaceSlug: "bendra",
},
signin: {
title: "Prisijungimas",
createAccount: "Sukurti paskyrą",
devTitle: "Prisijungimas kūrimo aplinkoje",
devHelp:
"Šioje diegtyje nėra tapatybės teikėjo, todėl prisijungti galima su bet kuriuo el. pašto adresu. Tai skirta kūrimui, o produkcinėje aplinkoje neveikia.",
devSubmit: "Prisijungti",
notConfigured:
"Prisijungimas šioje diegtyje nesukonfigūruotas. Paprašykite ją administruojančio asmens nurodyti tapatybės teikėją.",
error: {
sessionExpired: "Jūsų sesija baigėsi. Prisijunkite iš naujo.",
noTransaction: "Šis prisijungimas nebuvo pradėtas šioje naršyklėje arba užtruko per ilgai. Pradėkite iš naujo.",
denied: "Tapatybės teikėjas jūsų neįleido. Bandykite dar kartą arba naudokite kitą paskyrą.",
provider: "Tapatybės teikėjas nesugebėjo užbaigti prisijungimo. Bandykite dar kartą už kelių akimirkų.",
failed: "Prisijungti nepavyko. Bandykite dar kartą.",
},
// kit:convex-better-auth:begin
account: {
name: "Vardas",
password: "Slaptažodis",
passwordHelp: "Ne mažiau kaip {min} simbolių.",
signIn: "Prisijungti",
signUp: "Sukurti paskyrą",
toSignUp: "Dar neturite paskyros? Sukurkite",
toSignIn: "Jau turite paskyrą? Prisijunkite",
signUpTitle: "Paskyros kūrimas",
signUpIntro: "Sukurkite paskyrą su savo el. pašto adresu ir slaptažodžiu.",
error: {
invalid: "Toks el. pašto adresas ir slaptažodis neatitinka jokios paskyros.",
exists: "Paskyra su šiuo el. pašto adresu jau yra. Prisijunkite.",
disabled: "Ši paskyra išjungta. Kreipkitės į šios programos administratorius.",
rateLimited: "Per daug bandymų. Palaukite ir bandykite dar kartą.",
unavailable: "Šiuo metu prisijungti neįmanoma. Bandykite dar kartą už kelių akimirkų.",
failed: "Nepavyko. Patikrinkite formą ir bandykite dar kartą.",
},
},
// kit:convex-better-auth:end
},
invite: {
title: "Esate pakviesti",
lead: "Adresas {email} pakviestas prisijungti prie „{org}“ su role „{role}“.",
leadNoRole: "Adresas {email} pakviestas prisijungti prie „{org}“.",
expires: "Nuoroda veikia vieną kartą, iki {date}.",
createAccount: "Susikurti paskyrą",
haveAccount: "Jau turiu paskyrą: prisijungti",
signInFirst: "Prisijunkite su el. pašto adresu, kuriuo gavote kvietimą, ir grįžkite į šį puslapį.",
signedInAs: "Esate prisijungę kaip {email}.",
otherAccount: "Šis kvietimas skirtas adresui {email}. Prisijunkite šiuo adresu, kad jį priimtumėte.",
accept: "Priimti kvietimą",
accepted: "Prisijungėte prie „{org}“.",
switchAccount: "Prisijungti kita paskyra",
error: {
unknown: "Ši kvietimo nuoroda negalioja. Patikrinkite, ar nukopijavote ją visą, arba paprašykite naujos.",
invalid:
"Šis kvietimas netinka paskyrai, su kuria esate prisijungę. Prisijunkite su adresu, kuriuo jį gavote, arba paprašykite naujo.",
used: "Šis kvietimas jau panaudotas. Prisijunkite, kad atvertumėte organizaciją.",
revoked: "Šis kvietimas atšauktas. Paprašykite organizacijos administratoriaus naujo.",
expired: "Šio kvietimo galiojimas baigėsi. Paprašykite organizacijos administratoriaus naujo.",
member: "Jau esate šios organizacijos narys.",
failed: "Kvietimo priimti nepavyko. Bandykite dar kartą.",
},
},
boundary: {
errorTitle: "Kažkas nepavyko",
errorBody:
"Puslapio parodyti nepavyko. Bandykite dar kartą. Jei klaida kartosis, praneškite šią programą administruojančiam asmeniui.",
errorCode: "Klaidos kodas: {digest}",
retry: "Bandyti dar kartą",
notFoundTitle: "Puslapis nerastas",
notFoundBody: "Šiuo adresu nieko nėra arba neturite prieigos.",
forbiddenTitle: "Neturite prieigos",
forbiddenBody: "Jūsų rolė šio puslapio neleidžia. Kreipkitės į organizacijos administratorių.",
home: "Grįžti į pradžią",
loading: "Kraunama",
},
workspace: {
title: "Darbo erdvė „{name}“",
list: "Darbo erdvės",
none: "Matomų darbo erdvių nėra.",
create: "Sukurti darbo erdvę",
visibility: "Matomumas",
visibilityOrg: "Visi organizacijos nariai",
visibilityRestricted: "Tik pakviesti nariai",
default: "Numatytoji",
projects: "Projektai",
overview: "Darbo erdvės apžvalga",
group: "Darbo erdvė",
projectGroup: "Projektas",
chooseProject: "Pasirinkite projektą",
switchProject: "Perjungti projektą",
organizationSettings: "Organizacijos nustatymai",
nextAction: "Atverkite projektą ir tęskite darbą arba šoninėje juostoje pasirinkite darbo erdvės įrankį.",
projectCount: "{count, plural, one {# projektas} few {# projektai} other {# projektų}}",
noProjects: "Šioje darbo erdvėje projektų dar nėra.",
createProject: "Sukurti projektą",
module: "Modulis",
},
project: {
title: "Projektas „{name}“",
overview: "Projekto apžvalga",
work: "Darbas šiame projekte",
noSections: "Šiame projekte jums prieinamų skyrių nėra.",
archived: "Šis projektas suarchyvuotas.",
module: "Sukūrė modulis: {module}",
},
} as const
/** `tenancy.nav.members` is one key with a dot inside the module's own part, so it is flattened. */
const flatten = (input: Record<string, unknown>, prefix = ""): Record<string, string> => {
const out: Record<string, string> = {}
for (const [key, value] of Object.entries(input)) {
const name = prefix ? `${prefix}.${key}` : key
if (typeof value === "string") out[name] = value
else Object.assign(out, flatten(value as Record<string, unknown>, name))
}
return out
}
const ownCatalogues = (source: Record<string, Record<string, unknown>>): Record<string, Record<string, string>> =>
Object.fromEntries(Object.entries(source).map(([module, messages]) => [module, flatten(messages)]))
/** The kit's built-in messages and every module's, from the registry this app boots with. */
const fromModules = moduleCatalogues(buildRegistry([...appModules]))
export const appCatalogues: Catalogues = {
en: { ...fromModules.en, ...ownCatalogues(en) },
lt: { ...fromModules.lt, ...ownCatalogues(lt) },
}