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;
|
|||
|
|
}
|