/* ============================================================================ ROUTE COPY - Events Calendar / Applications and Opportunities ---------------------------------------------------------------------------- The message catalogue in ~/i18n holds UI chrome that every page shares (actions, filters, form labels, statuses). Page prose belongs to the page, and lives here. Every string below is taken from the approved draft, docs/SHARPER_Website_Draft_Section_EN_AR.docx - section 4 "Events Calendar" and section 8 "Applications and Opportunities" - in both languages. Where the draft marks a value "TBD" (network eligibility criteria, the response time in weeks, the project email, activity figures) NOTHING is invented: the sentence either omits it or the value comes from the CMS. Parity is enforced by the type: `RouteCopy` is derived from the English object, so a key added on one side and forgotten on the other is a compile error rather than a blank paragraph in production. ========================================================================= */ import type { Locale } from "~/i18n"; const EN = { events: { /* The kicker above an event title. "other" is intentionally empty: an event the CMS did not classify simply gets no kicker. */ eventTypes: { "suq-dialogue": "SUQ Dialogue", training: "Training", "law-session": "Law Session", "network-meeting": "Network Meeting", launch: "Launch", other: "", }, /** Draft 4, EN headline. */ heading: "Upcoming Events", /** Draft 4, EN standfirst. */ intro: "Register for a SUQ dialogue, join a training, or track what’s coming next across Libya.", metaDescription: "Dialogues, trainings and Civil Society Law Sessions across Libya. Register for a SUQ dialogue, join a training, or track what’s coming next.", listLabel: "Events", statusFilterLabel: "Status", emptyHint: "Dialogues, trainings and sessions are published here as soon as they are scheduled.", unavailable: "The events calendar cannot be loaded right now. Please try again in a moment.", formatHybrid: "In person and online", }, eventDetail: { backToList: "Back to the events calendar", aboutHeading: "About this event", detailsHeading: "Event details", registrationDeadlineLabel: "Registration deadline", registerHeading: "Register for this event", waitlistHeading: "Join the waitlist", formIntro: "We use these details only to manage your place and to send joining information.", registrationClosed: "Registration for this event is closed.", /** `event.registrationStatus === "not-required"`. */ registrationNotRequired: "No registration required", registrationNotRequiredNote: "This event is open to all - no registration is needed.", registrationFull: "This event is fully booked. Join the waitlist and we will contact you if a place becomes available.", eventCompleted: "This event has already taken place.", joinOnlineLabel: "Joining link", addToCalendarHint: "Downloads an .ics file you can open in any calendar application.", timeZoneNote: "All times are shown in Libya time (UTC+2).", /** * `event-registration.consentGdpr` is REQUIRED in the CMS, so the reader * has to be asked in plain words rather than opted in silently. */ consentLabel: "I agree that SHARP-ER may store the details above to manage my registration for this event.", consentHint: "We keep them only for as long as the event needs, and never share them with anyone outside the project. You can ask us to delete them at any time.", /** Draft 4, EN confirmation screen, reused for the waitlist variant. */ waitlistConfirmationTitle: "You’re on the waitlist.", waitlistConfirmationBody: "Thank you — {event} on {date} is fully booked, so we have added you to the waitlist. We will email you if a place becomes available.", }, opportunities: { /** Draft 8, EN headline. */ heading: "Get Involved", /** Draft 8, EN standfirst. */ intro: "Whether you’re a civil society organisation or an individual, here’s how to take part in SHARP-ER.", metaDescription: "Calls for expression of interest, SHARP network membership and upcoming sessions — how civil society organisations and individuals take part in SHARP-ER.", pathwaysHeading: "Ways to take part", /* The draft has no call list; this single line keeps the open calls reachable in-site now that the listing band is gone. */ currentCallsLabel: "Open calls:", pathwayCallsTitle: "Apply for a Call for Expression of Interest", pathwayCallsBody: "Open calls for CSO sub-projects and Policy-to-Rights (P2R) initiatives.", pathwayNetworkTitle: "Join the SHARP Network", pathwayNetworkBody: "Become part of the civil society network behind SHARP-ER: regional meetings, peer learning, and joint events.", pathwaySessionsTitle: "Register for a SUQ Dialogue or Training", pathwaySessionsBody: "Take part in an upcoming Search, Understand, Question dialogue or a dialogue-facilitation training.", }, /* ------------------------------------------------------------------------- THE APPLICATION FORM - the redesign draft's #apply band ---------------------------------------------------------------------------- THREE OF THE DRAFT'S SENTENCES ARE NOT REPRODUCED, on the client's own instruction and under CLAUDE.md rule 5: * "PDF or DOCX, up to 10 MB" - not the rule this project runs. The CMS ceiling is UPLOAD_MAX_FILE_SIZE (50 MB by default) over the media types listed in apps/cms/config/plugins.ts, and in any case nothing is uploaded here (see `documentsNote`), so no limit is quoted at all. * "an automatic acknowledgment with your reference number" - there is no reference-number field anywhere in the CMS, so no number is promised. The acknowledgement itself IS modelled, as `application.acknowledgementSentAt`, so it is the only half that survives. * "follows up within four weeks" - that response time appears in no approved document; §8 of the draft marks it "[X weeks] - TBD". The follow-up is stated without a period attached, exactly as the per-call acknowledgement already does. ---------------------------------------------------------------------- */ apply: { /** The draft's "Step {n} of 3" kicker over the form. */ stepOf: "Step {current} of {total}", /** Accessible name of the progress list. */ stepsLabel: "Application progress", stepEligibility: "Eligibility", stepApplication: "Application", stepReview: "Review", /** Announced on the step the reader is on. */ stepCurrent: "current step", stepDone: "done", /** The standfirst beside the form. */ standfirst: "Submissions are acknowledged automatically by email. The consortium reviews complete applications and follows up by email.", formLabel: "Application form", fieldsetLegend: "Your details", routeLabel: "What are you applying for?", /* The short names the draft gives the three routes - the long ones head the pathway cards above and are too long for a select. */ routeCalls: "Call for Expression of Interest", routeNetwork: "SHARP Network membership", routeSessions: "SUQ dialogue or training", organisationLabel: "Organisation name", organisationPlaceholder: "Registered legal name", contactLabel: "Contact person", contactPlaceholder: "Full name", emailLabel: "Email", emailPlaceholder: "name@organisation.ly", regionLabel: "Region of operation", regionPlaceholder: "City or municipality", yearsLabel: "Years of operating history", yearsPlaceholder: "e.g. 4", summaryLabel: "Summary of your proposal", summaryHint: "Briefly describe your organisation and why you are applying.", documentsTitle: "Supporting documents", /** * The draft draws a file input here. There is nowhere for the file to go: * `attachments` is deliberately off the public whitelist in * apps/cms/src/api/application/middlewares/sanitize-submission.ts, and the * Public role cannot upload. A control that accepted a document and then * dropped it would be worse than none, so the panel says plainly what the * form does with documents - and quotes no size limit, because it accepts * no files at all. */ documentsNote: "Documents are not uploaded through this form. Describe any supporting material in the summary above.", /** `application.acknowledgementSentAt` - modelled, so it can be said. */ acknowledgement: "Your submission is acknowledged automatically by email.", submit: "Submit application", errorSummaryTitle: "Please check the form", receivedTitle: "Application received", receivedBody: "Thank you for applying to {route}. An acknowledgement is on its way to the email address you gave us, and our team will review your application and follow up by email.", submitAnother: "Submit another", }, /** `opportunity.opportunityType`, verbatim, with the draft's own wording. */ opportunityTypes: { "call-eoi": "Call for Expression of Interest", "network-membership": "Network membership", training: "Training", grant: "Grant", other: "Opportunity", }, opportunityDetail: { backToList: "Back to applications and opportunities", aboutHeading: "About this opportunity", detailsHeading: "Call details", howToApplyHeading: "How to apply", attachmentsHeading: "Documents", applyHeading: "Apply", statusLabel: "Status", typeLabel: "Type", opensLabel: "Opens", deadlineLabel: "Deadline", formIntro: "Tell us briefly why you are applying. Our team reviews every application.", messageHint: "Briefly describe your organisation and why you are applying.", closedNote: "This call is closed. It stays published for reference.", upcomingNote: "This call opens on {date}.", externalApplication: "Applications for this call are handled on an external site.", /** * Draft 8 marks the response time "[X weeks] - TBD" and the CMS has no * field for it, so no number is ever named. */ applicationReceivedBody: "Thank you for your application. Our team will review it and follow up by email.", }, form: { /** Honeypot label - never seen by a human, read by a bot. */ honeypotLabel: "Leave this field empty", submissionFailed: "Your details could not be submitted. Please try again in a moment.", }, }; export type RouteCopy = typeof EN; const AR: RouteCopy = { events: { eventTypes: { "suq-dialogue": "حوار سوق", training: "تدريب", "law-session": "جلسة قانونية", "network-meeting": "اجتماع الشبكة", launch: "إطلاق", other: "", }, heading: "الفعاليات القادمة", intro: "سجّل في حوار SUQ، أو انضم إلى تدريب، أو تابع ما هو قادم في مختلف أنحاء ليبيا.", metaDescription: "حوارات وتدريبات وجلسات قانون المجتمع المدني في مختلف أنحاء ليبيا. سجّل في حوار SUQ، أو انضم إلى تدريب، أو تابع ما هو قادم.", listLabel: "الفعاليات", statusFilterLabel: "الحالة", emptyHint: "تُنشر هنا الحوارات والتدريبات والجلسات فور تحديد مواعيدها.", unavailable: "تعذّر تحميل تقويم الفعاليات في الوقت الحالي. يرجى المحاولة مرة أخرى بعد قليل.", formatHybrid: "حضوري وعبر الإنترنت", }, eventDetail: { backToList: "العودة إلى تقويم الفعاليات", aboutHeading: "عن الفعالية", detailsHeading: "تفاصيل الفعالية", registrationDeadlineLabel: "الموعد النهائي للتسجيل", registerHeading: "سجّل في هذه الفعالية", waitlistHeading: "انضم إلى قائمة الانتظار", formIntro: "نستخدم هذه البيانات فقط لإدارة مكانك وإرسال تفاصيل الانضمام.", registrationClosed: "أُغلق التسجيل في هذه الفعالية.", registrationNotRequired: "لا يلزم التسجيل", registrationNotRequiredNote: "هذه الفعالية مفتوحة للجميع، ولا حاجة إلى التسجيل.", registrationFull: "اكتمل العدد في هذه الفعالية. انضم إلى قائمة الانتظار وسنتواصل معك في حال توفّر مكان.", eventCompleted: "انتهت هذه الفعالية.", joinOnlineLabel: "رابط الانضمام", addToCalendarHint: "يُنزّل ملف .ics يمكن فتحه في أي تطبيق تقويم.", timeZoneNote: "جميع الأوقات معروضة بتوقيت ليبيا (UTC+2).", consentLabel: "أوافق على أن يحتفظ مشروع SHARP-ER بالبيانات أعلاه لإدارة تسجيلي في هذه الفعالية.", consentHint: "نحتفظ بها فقط للمدة التي تتطلبها الفعالية، ولا نشاركها مع أي جهة خارج المشروع. ويمكنك أن تطلب حذفها في أي وقت.", waitlistConfirmationTitle: "تمت إضافتك إلى قائمة الانتظار.", waitlistConfirmationBody: "شكرًا لك — اكتمل العدد في {event} بتاريخ {date}، لذلك أضفناك إلى قائمة الانتظار. سنراسلك عبر البريد الإلكتروني في حال توفّر مكان.", }, opportunities: { heading: "شارك معنا", intro: "سواء كنتم منظمة مجتمع مدني أو فردًا، إليكم كيفية المشاركة في SHARP-ER.", metaDescription: "دعوات للتعبير عن الاهتمام، وعضوية شبكة SHARP، وجلسات قادمة — كيف تشارك منظمات المجتمع المدني والأفراد في SHARP-ER.", pathwaysHeading: "طرق المشاركة", currentCallsLabel: "الدعوات المفتوحة:", pathwayCallsTitle: "التقديم على دعوة للتعبير عن الاهتمام", pathwayCallsBody: "دعوات مفتوحة للمشاريع الفرعية لمنظمات المجتمع المدني ومبادرات «من السياسة إلى الحقوق» (P2R).", pathwayNetworkTitle: "انضم إلى شبكة SHARP", pathwayNetworkBody: "كن جزءًا من شبكة المجتمع المدني وراء SHARP-ER: اجتماعات إقليمية، وتعلّم بين الأقران، وفعاليات مشتركة.", pathwaySessionsTitle: "سجّل في حوار SUQ أو تدريب", pathwaySessionsBody: "شارك في حوار قادم من نوع «ابحث، افهم، اسأل» أو في تدريب على تيسير الحوار.", }, apply: { stepOf: "الخطوة {current} من {total}", stepsLabel: "مراحل تقديم الطلب", stepEligibility: "الأهلية", stepApplication: "الطلب", stepReview: "المراجعة", stepCurrent: "الخطوة الحالية", stepDone: "مكتملة", standfirst: "يصلك إشعار تلقائي باستلام طلبك عبر البريد الإلكتروني. ويراجع الائتلاف الطلبات المكتملة ويتواصل معك عبر البريد الإلكتروني.", formLabel: "نموذج التقديم", fieldsetLegend: "بياناتك", routeLabel: "ما الذي تقدّم عليه؟", routeCalls: "دعوة للتعبير عن الاهتمام", routeNetwork: "عضوية شبكة SHARP", routeSessions: "حوار SUQ أو تدريب", organisationLabel: "اسم المنظمة", organisationPlaceholder: "الاسم القانوني المسجَّل", contactLabel: "الشخص المسؤول", contactPlaceholder: "الاسم الكامل", emailLabel: "البريد الإلكتروني", emailPlaceholder: "name@organisation.ly", regionLabel: "نطاق العمل", regionPlaceholder: "المدينة أو البلدية", yearsLabel: "عدد سنوات العمل", yearsPlaceholder: "مثال: 4", summaryLabel: "ملخّص المقترح", summaryHint: "صف باختصار منظمتك وسبب تقديمك.", documentsTitle: "المستندات الداعمة", documentsNote: "لا تُرفَق المستندات عبر هذا النموذج. صف أي مواد داعمة في الملخّص أعلاه.", acknowledgement: "يصلك إشعار تلقائي باستلام طلبك عبر البريد الإلكتروني.", submit: "إرسال الطلب", errorSummaryTitle: "يرجى مراجعة النموذج", receivedTitle: "تم استلام الطلب", receivedBody: "شكرًا لتقديمك على {route}. سيصلك إشعار بالاستلام على البريد الإلكتروني الذي زوّدتنا به، وسيراجع فريقنا طلبك ويتواصل معك عبر البريد الإلكتروني.", submitAnother: "تقديم طلب آخر", }, opportunityTypes: { "call-eoi": "دعوة للتعبير عن الاهتمام", "network-membership": "عضوية الشبكة", training: "تدريب", grant: "منحة", other: "فرصة", }, opportunityDetail: { backToList: "العودة إلى طلبات وفرص المشاركة", aboutHeading: "عن هذه الفرصة", detailsHeading: "تفاصيل الدعوة", howToApplyHeading: "كيفية التقديم", attachmentsHeading: "المستندات", applyHeading: "قدّم طلبك", statusLabel: "الحالة", typeLabel: "النوع", opensLabel: "تاريخ الفتح", deadlineLabel: "الموعد النهائي", formIntro: "أخبرنا باختصار عن سبب تقديمك. يراجع فريقنا كل طلب.", messageHint: "صف باختصار منظمتك وسبب تقديمك.", closedNote: "أُغلقت هذه الدعوة، وتبقى منشورة للاطّلاع.", upcomingNote: "تُفتح هذه الدعوة بتاريخ {date}.", externalApplication: "يتم التقديم على هذه الدعوة عبر موقع خارجي.", applicationReceivedBody: "شكرًا لتقديم طلبك. سيراجعه فريقنا ويتواصل معك عبر البريد الإلكتروني.", }, form: { honeypotLabel: "اترك هذا الحقل فارغًا", submissionFailed: "تعذّر إرسال بياناتك. يرجى المحاولة مرة أخرى بعد قليل.", }, }; const COPY: Readonly> = { en: EN, ar: AR }; /** The route copy for a locale. Falls back to English, never to "". */ export function getRouteCopy(locale: Locale): RouteCopy { return COPY[locale] ?? EN; }