30cdb5064a
~300 lines of code that were independently duplicated in Dashboard.tsx and Comparison.tsx are now in shared modules: - src/lib/locale.ts — LC interface, EN and AR language configs (merged fields from both pages into one unified interface) - src/lib/dateHelpers.ts — MONTH_KEYS, isLeap, makePresets, guessPreset, periodNameL, dateRangeTextL, currentMonth, shiftYear - src/components/shared/PeriodPicker.tsx — InlinePicker + PeriodHero - src/components/shared/AltMultiSelect.tsx — AltMultiSelect - src/components/shared/MetricCard.tsx — MetricCard Dashboard.tsx and Comparison.tsx now import from these shared modules. Zero behavioral changes — all props, ARIA, and render output unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
140 lines
5.9 KiB
TypeScript
140 lines
5.9 KiB
TypeScript
// ─── language config ──────────────────────────────────────────────
|
||
// Shared LC interface used by Dashboard and Comparison.
|
||
// Fields marked with a comment are only consumed by one page but kept
|
||
// here so both components share a single type.
|
||
export interface LC {
|
||
dir: 'ltr' | 'rtl';
|
||
/** @deprecated Fonts are now loaded from index.html; kept for compatibility */
|
||
fontImport: string;
|
||
bodyFont: string;
|
||
displayFont: string;
|
||
monoFont: string;
|
||
monthFull: string[];
|
||
monthShort: string[];
|
||
periods: Record<string, string>;
|
||
fullYearLabel: (y: number) => string;
|
||
dateRangeSep: string;
|
||
backLink: string;
|
||
backTo: string;
|
||
pageTitle: string;
|
||
pageSub: string;
|
||
// Dashboard
|
||
changePeriod: string;
|
||
close: string;
|
||
apply: string;
|
||
filter: string;
|
||
allDistricts: string;
|
||
allChannels: string;
|
||
allMuseums: string;
|
||
countDistricts: (n: number) => string;
|
||
countChannels: (n: number) => string;
|
||
countMuseums: (n: number) => string;
|
||
reset: string;
|
||
exclVAT: string;
|
||
inclVAT: string;
|
||
keyMetrics: string;
|
||
revenue: string;
|
||
visitors: string;
|
||
tickets: string;
|
||
avgRev: string;
|
||
pilgrims: string;
|
||
captureRate: string;
|
||
charts: string;
|
||
trendTitle: string;
|
||
museumTitle: string;
|
||
channelTitle: string;
|
||
districtTitle: string;
|
||
daily: string;
|
||
weekly: string;
|
||
monthly: string;
|
||
newLabel: string;
|
||
clearSel: string;
|
||
monthSection: string;
|
||
periodSection: string;
|
||
from: string;
|
||
to: string;
|
||
vsLabel: string;
|
||
barLabel: string;
|
||
pieLabel: string;
|
||
absLabel: string;
|
||
pctLabel: string;
|
||
// Comparison-specific
|
||
currentRole: string;
|
||
previousRole: string;
|
||
currentHint: string;
|
||
previousHint: string;
|
||
vs: string;
|
||
}
|
||
|
||
export const EN: LC = {
|
||
dir: 'ltr',
|
||
fontImport: `@import url('https://fonts.googleapis.com/css2?family=DM+Serif+Display:ital@0;1&family=Outfit:wght@300;400;500;600;700&display=swap');`,
|
||
bodyFont: "'Outfit', sans-serif",
|
||
displayFont: "'DM Serif Display', serif",
|
||
monoFont: "ui-monospace, 'Cascadia Code', monospace",
|
||
monthFull: ['January','February','March','April','May','June','July','August','September','October','November','December'],
|
||
monthShort: ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'],
|
||
periods: { q1:'Q1', q2:'Q2', q3:'Q3', q4:'Q4', h1:'H1', h2:'H2', full:'Full Year' },
|
||
fullYearLabel: (y) => String(y),
|
||
dateRangeSep: '→',
|
||
backLink: 'Back to Dashboard', backTo: '/',
|
||
pageTitle: 'Overview', pageSub: 'Museum performance at a glance.',
|
||
changePeriod: 'Change period', close: 'Cancel', apply: 'Apply',
|
||
filter: 'Filter',
|
||
allDistricts: 'All districts', allChannels: 'All channels', allMuseums: 'All museums',
|
||
countDistricts: (n) => `${n} districts`,
|
||
countChannels: (n) => `${n} channels`,
|
||
countMuseums: (n) => `${n} museums`,
|
||
reset: 'Reset', exclVAT: 'Excl. VAT', inclVAT: 'Incl. VAT',
|
||
keyMetrics: 'Key Metrics',
|
||
revenue: 'Revenue', visitors: 'Visitors', tickets: 'Tickets',
|
||
avgRev: 'Avg Rev / Visitor', pilgrims: 'Pilgrims', captureRate: 'Capture Rate %',
|
||
charts: 'Charts',
|
||
trendTitle: 'Trend over time', museumTitle: 'By museum',
|
||
channelTitle: 'By channel', districtTitle: 'By district',
|
||
daily: 'Daily', weekly: 'Weekly', monthly: 'Monthly',
|
||
newLabel: 'New', clearSel: 'Clear selection',
|
||
monthSection: 'Month', periodSection: 'Quarter · Half · Year',
|
||
from: 'From', to: 'To', vsLabel: 'vs',
|
||
barLabel: 'Bar', pieLabel: 'Pie', absLabel: '#', pctLabel: '%',
|
||
currentRole: 'This period', previousRole: 'Compared to',
|
||
currentHint: 'primary', previousHint: 'auto year −1',
|
||
vs: 'vs',
|
||
};
|
||
|
||
export const AR: LC = {
|
||
dir: 'rtl',
|
||
fontImport: `@import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Sans+Arabic:wght@300;400;500;600;700&display=swap');`,
|
||
bodyFont: "'IBM Plex Sans Arabic', sans-serif",
|
||
displayFont: "'IBM Plex Sans Arabic', sans-serif",
|
||
monoFont: "'IBM Plex Sans Arabic', sans-serif",
|
||
monthFull: ['يناير','فبراير','مارس','أبريل','مايو','يونيو','يوليو','أغسطس','سبتمبر','أكتوبر','نوفمبر','ديسمبر'],
|
||
monthShort: ['ينا','فبر','مار','أبر','ماي','يون','يول','أغس','سبت','أكت','نوف','ديس'],
|
||
periods: { q1:'ر١', q2:'ر٢', q3:'ر٣', q4:'ر٤', h1:'ن١', h2:'ن٢', full:'السنة' },
|
||
fullYearLabel: (y) => `${y} كاملاً`,
|
||
dateRangeSep: '–',
|
||
backLink: 'العودة إلى لوحة التحكم', backTo: '/ar',
|
||
pageTitle: 'نظرة عامة', pageSub: 'أداء المتاحف في لمحة.',
|
||
changePeriod: 'تغيير الفترة', close: 'إلغاء', apply: 'تطبيق',
|
||
filter: 'تصفية',
|
||
allDistricts: 'كل المناطق', allChannels: 'كل القنوات', allMuseums: 'كل المتاحف',
|
||
countDistricts: (n) => `${n} مناطق`,
|
||
countChannels: (n) => `${n} قنوات`,
|
||
countMuseums: (n) => `${n} متاحف`,
|
||
reset: 'إعادة ضبط', exclVAT: 'بدون ضريبة', inclVAT: 'مع ضريبة',
|
||
keyMetrics: 'المؤشرات الرئيسية',
|
||
revenue: 'الإيرادات', visitors: 'الزوار', tickets: 'التذاكر',
|
||
avgRev: 'متوسط الإيراد / زائر', pilgrims: 'الحجاج والمعتمرون', captureRate: 'معدل الاستيعاب %',
|
||
charts: 'المخططات',
|
||
trendTitle: 'الاتجاه عبر الزمن', museumTitle: 'حسب المتحف',
|
||
channelTitle: 'حسب القناة', districtTitle: 'حسب المنطقة',
|
||
daily: 'يومي', weekly: 'أسبوعي', monthly: 'شهري',
|
||
newLabel: 'جديد', clearSel: 'مسح التحديد',
|
||
monthSection: 'الشهر', periodSection: 'ربع · نصف · سنة',
|
||
from: 'من', to: 'إلى', vsLabel: 'مقابل',
|
||
barLabel: 'أعمدة', pieLabel: 'دائرة', absLabel: '#', pctLabel: '%',
|
||
currentRole: 'الفترة الحالية', previousRole: 'مقارنةً بـ',
|
||
currentHint: 'رئيسية', previousHint: 'تلقائياً −١ سنة',
|
||
vs: 'مقابل',
|
||
};
|