248 lines
13 KiB
TypeScript
248 lines
13 KiB
TypeScript
/* ============================================================================
|
||
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: {
|
||
/** 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",
|
||
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.",
|
||
listHeading: "Current calls",
|
||
listLabel: "Calls and opportunities",
|
||
statusFilterLabel: "Status",
|
||
empty: "There are no calls or opportunities to show yet.",
|
||
emptyHint:
|
||
"Calls for expression of interest are published here as soon as they open.",
|
||
unavailable:
|
||
"Calls and opportunities cannot be loaded right now. Please try again in a moment.",
|
||
},
|
||
/** `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: {
|
||
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: "طرق المشاركة",
|
||
pathwayCallsTitle: "التقديم على دعوة للتعبير عن الاهتمام",
|
||
pathwayCallsBody:
|
||
"دعوات مفتوحة للمشاريع الفرعية لمنظمات المجتمع المدني ومبادرات «من السياسة إلى الحقوق» (P2R).",
|
||
pathwayNetworkTitle: "انضم إلى شبكة SHARP",
|
||
pathwayNetworkBody:
|
||
"كن جزءًا من شبكة المجتمع المدني وراء SHARP-ER: اجتماعات إقليمية، وتعلّم بين الأقران، وفعاليات مشتركة.",
|
||
pathwaySessionsTitle: "سجّل في حوار SUQ أو تدريب",
|
||
pathwaySessionsBody:
|
||
"شارك في حوار قادم من نوع «ابحث، افهم، اسأل» أو في تدريب على تيسير الحوار.",
|
||
listHeading: "الدعوات الحالية",
|
||
listLabel: "الدعوات والفرص",
|
||
statusFilterLabel: "الحالة",
|
||
empty: "لا توجد دعوات أو فرص لعرضها حتى الآن.",
|
||
emptyHint: "تُنشر هنا دعوات التعبير عن الاهتمام فور فتحها.",
|
||
unavailable:
|
||
"تعذّر تحميل الدعوات والفرص في الوقت الحالي. يرجى المحاولة مرة أخرى بعد قليل.",
|
||
},
|
||
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<Record<Locale, RouteCopy>> = { 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;
|
||
}
|