i18n: translate all shared trip page strings to 9 languages
This commit is contained in:
@@ -170,6 +170,22 @@ const ar: Record<string, string | { name: string; category: string }[]> = {
|
||||
'share.permMap': 'الخريطة والخطة',
|
||||
'share.permBookings': 'الحجوزات',
|
||||
'share.permPacking': 'الأمتعة',
|
||||
'shared.expired': 'الرابط منتهي أو غير صالح',
|
||||
'shared.expiredHint': 'رابط الرحلة المشترك لم يعد نشطًا.',
|
||||
'shared.readOnly': 'عرض للقراءة فقط',
|
||||
'shared.tabPlan': 'الخطة',
|
||||
'shared.tabBookings': 'الحجوزات',
|
||||
'shared.tabPacking': 'قائمة التعبئة',
|
||||
'shared.tabBudget': 'الميزانية',
|
||||
'shared.tabChat': 'الدردشة',
|
||||
'shared.days': 'أيام',
|
||||
'shared.places': 'أماكن',
|
||||
'shared.other': 'أخرى',
|
||||
'shared.totalBudget': 'إجمالي الميزانية',
|
||||
'shared.messages': 'رسائل',
|
||||
'shared.sharedVia': 'تمت المشاركة عبر',
|
||||
'shared.confirmed': 'مؤكد',
|
||||
'shared.pending': 'قيد الانتظار',
|
||||
'share.permBudget': 'الميزانية',
|
||||
'share.permCollab': 'الدردشة',
|
||||
'settings.on': 'تشغيل',
|
||||
|
||||
@@ -165,6 +165,22 @@ const br: Record<string, string | { name: string; category: string }[]> = {
|
||||
'share.permMap': 'Mapa e plano',
|
||||
'share.permBookings': 'Reservas',
|
||||
'share.permPacking': 'Mala',
|
||||
'shared.expired': 'Link expirado ou inválido',
|
||||
'shared.expiredHint': 'Este link de viagem compartilhado não está mais ativo.',
|
||||
'shared.readOnly': 'Visualização somente leitura',
|
||||
'shared.tabPlan': 'Plano',
|
||||
'shared.tabBookings': 'Reservas',
|
||||
'shared.tabPacking': 'Bagagem',
|
||||
'shared.tabBudget': 'Orçamento',
|
||||
'shared.tabChat': 'Chat',
|
||||
'shared.days': 'dias',
|
||||
'shared.places': 'lugares',
|
||||
'shared.other': 'Outros',
|
||||
'shared.totalBudget': 'Orçamento total',
|
||||
'shared.messages': 'mensagens',
|
||||
'shared.sharedVia': 'Compartilhado via',
|
||||
'shared.confirmed': 'Confirmado',
|
||||
'shared.pending': 'Pendente',
|
||||
'share.permBudget': 'Orçamento',
|
||||
'share.permCollab': 'Chat',
|
||||
'settings.on': 'Ligado',
|
||||
|
||||
@@ -165,6 +165,22 @@ const de: Record<string, string | { name: string; category: string }[]> = {
|
||||
'share.permMap': 'Karte & Plan',
|
||||
'share.permBookings': 'Buchungen',
|
||||
'share.permPacking': 'Packliste',
|
||||
'shared.expired': 'Link abgelaufen oder ungültig',
|
||||
'shared.expiredHint': 'Dieser geteilte Reise-Link ist nicht mehr aktiv.',
|
||||
'shared.readOnly': 'Nur-Lesen Ansicht',
|
||||
'shared.tabPlan': 'Plan',
|
||||
'shared.tabBookings': 'Buchungen',
|
||||
'shared.tabPacking': 'Packliste',
|
||||
'shared.tabBudget': 'Budget',
|
||||
'shared.tabChat': 'Chat',
|
||||
'shared.days': 'Tage',
|
||||
'shared.places': 'Orte',
|
||||
'shared.other': 'Sonstige',
|
||||
'shared.totalBudget': 'Gesamtbudget',
|
||||
'shared.messages': 'Nachrichten',
|
||||
'shared.sharedVia': 'Geteilt über',
|
||||
'shared.confirmed': 'Bestätigt',
|
||||
'shared.pending': 'Ausstehend',
|
||||
'share.permBudget': 'Budget',
|
||||
'share.permCollab': 'Chat',
|
||||
'settings.on': 'An',
|
||||
|
||||
@@ -165,6 +165,22 @@ const en: Record<string, string | { name: string; category: string }[]> = {
|
||||
'share.permMap': 'Map & Plan',
|
||||
'share.permBookings': 'Bookings',
|
||||
'share.permPacking': 'Packing',
|
||||
'shared.expired': 'Link expired or invalid',
|
||||
'shared.expiredHint': 'This shared trip link is no longer active.',
|
||||
'shared.readOnly': 'Read-only shared view',
|
||||
'shared.tabPlan': 'Plan',
|
||||
'shared.tabBookings': 'Bookings',
|
||||
'shared.tabPacking': 'Packing',
|
||||
'shared.tabBudget': 'Budget',
|
||||
'shared.tabChat': 'Chat',
|
||||
'shared.days': 'days',
|
||||
'shared.places': 'places',
|
||||
'shared.other': 'Other',
|
||||
'shared.totalBudget': 'Total Budget',
|
||||
'shared.messages': 'messages',
|
||||
'shared.sharedVia': 'Shared via',
|
||||
'shared.confirmed': 'Confirmed',
|
||||
'shared.pending': 'Pending',
|
||||
'share.permBudget': 'Budget',
|
||||
'share.permCollab': 'Chat',
|
||||
'settings.on': 'On',
|
||||
|
||||
@@ -166,6 +166,22 @@ const es: Record<string, string> = {
|
||||
'share.permMap': 'Mapa y plan',
|
||||
'share.permBookings': 'Reservas',
|
||||
'share.permPacking': 'Equipaje',
|
||||
'shared.expired': 'Enlace expirado o inválido',
|
||||
'shared.expiredHint': 'Este enlace de viaje compartido ya no está activo.',
|
||||
'shared.readOnly': 'Vista de solo lectura',
|
||||
'shared.tabPlan': 'Plan',
|
||||
'shared.tabBookings': 'Reservas',
|
||||
'shared.tabPacking': 'Equipaje',
|
||||
'shared.tabBudget': 'Presupuesto',
|
||||
'shared.tabChat': 'Chat',
|
||||
'shared.days': 'días',
|
||||
'shared.places': 'lugares',
|
||||
'shared.other': 'Otro',
|
||||
'shared.totalBudget': 'Presupuesto total',
|
||||
'shared.messages': 'mensajes',
|
||||
'shared.sharedVia': 'Compartido vía',
|
||||
'shared.confirmed': 'Confirmado',
|
||||
'shared.pending': 'Pendiente',
|
||||
'share.permBudget': 'Presupuesto',
|
||||
'share.permCollab': 'Chat',
|
||||
'settings.on': 'Activado',
|
||||
|
||||
@@ -165,6 +165,22 @@ const fr: Record<string, string> = {
|
||||
'share.permMap': 'Carte et plan',
|
||||
'share.permBookings': 'Réservations',
|
||||
'share.permPacking': 'Bagages',
|
||||
'shared.expired': 'Lien expiré ou invalide',
|
||||
'shared.expiredHint': 'Ce lien de partage n\'est plus actif.',
|
||||
'shared.readOnly': 'Vue en lecture seule',
|
||||
'shared.tabPlan': 'Plan',
|
||||
'shared.tabBookings': 'Réservations',
|
||||
'shared.tabPacking': 'Bagages',
|
||||
'shared.tabBudget': 'Budget',
|
||||
'shared.tabChat': 'Chat',
|
||||
'shared.days': 'jours',
|
||||
'shared.places': 'lieux',
|
||||
'shared.other': 'Autre',
|
||||
'shared.totalBudget': 'Budget total',
|
||||
'shared.messages': 'messages',
|
||||
'shared.sharedVia': 'Partagé via',
|
||||
'shared.confirmed': 'Confirmé',
|
||||
'shared.pending': 'En attente',
|
||||
'share.permBudget': 'Budget',
|
||||
'share.permCollab': 'Chat',
|
||||
'settings.on': 'Activé',
|
||||
|
||||
@@ -165,6 +165,22 @@ const nl: Record<string, string> = {
|
||||
'share.permMap': 'Kaart en plan',
|
||||
'share.permBookings': 'Boekingen',
|
||||
'share.permPacking': 'Paklijst',
|
||||
'shared.expired': 'Link verlopen of ongeldig',
|
||||
'shared.expiredHint': 'Deze gedeelde reislink is niet meer actief.',
|
||||
'shared.readOnly': 'Alleen-lezen weergave',
|
||||
'shared.tabPlan': 'Plan',
|
||||
'shared.tabBookings': 'Boekingen',
|
||||
'shared.tabPacking': 'Paklijst',
|
||||
'shared.tabBudget': 'Budget',
|
||||
'shared.tabChat': 'Chat',
|
||||
'shared.days': 'dagen',
|
||||
'shared.places': 'plaatsen',
|
||||
'shared.other': 'Overig',
|
||||
'shared.totalBudget': 'Totaal budget',
|
||||
'shared.messages': 'berichten',
|
||||
'shared.sharedVia': 'Gedeeld via',
|
||||
'shared.confirmed': 'Bevestigd',
|
||||
'shared.pending': 'In afwachting',
|
||||
'share.permBudget': 'Budget',
|
||||
'share.permCollab': 'Chat',
|
||||
'settings.on': 'Aan',
|
||||
|
||||
@@ -165,6 +165,22 @@ const ru: Record<string, string> = {
|
||||
'share.permMap': 'Карта и план',
|
||||
'share.permBookings': 'Бронирования',
|
||||
'share.permPacking': 'Вещи',
|
||||
'shared.expired': 'Ссылка устарела или недействительна',
|
||||
'shared.expiredHint': 'Эта ссылка на поездку больше не активна.',
|
||||
'shared.readOnly': 'Режим только для чтения',
|
||||
'shared.tabPlan': 'План',
|
||||
'shared.tabBookings': 'Бронирования',
|
||||
'shared.tabPacking': 'Багаж',
|
||||
'shared.tabBudget': 'Бюджет',
|
||||
'shared.tabChat': 'Чат',
|
||||
'shared.days': 'дней',
|
||||
'shared.places': 'мест',
|
||||
'shared.other': 'Прочее',
|
||||
'shared.totalBudget': 'Общий бюджет',
|
||||
'shared.messages': 'сообщений',
|
||||
'shared.sharedVia': 'Поделено через',
|
||||
'shared.confirmed': 'Подтверждено',
|
||||
'shared.pending': 'Ожидает',
|
||||
'share.permBudget': 'Бюджет',
|
||||
'share.permCollab': 'Чат',
|
||||
'settings.on': 'Вкл.',
|
||||
|
||||
@@ -165,6 +165,22 @@ const zh: Record<string, string> = {
|
||||
'share.permMap': '地图与计划',
|
||||
'share.permBookings': '预订',
|
||||
'share.permPacking': '行李',
|
||||
'shared.expired': '链接已过期或无效',
|
||||
'shared.expiredHint': '此共享旅行链接已失效。',
|
||||
'shared.readOnly': '只读共享视图',
|
||||
'shared.tabPlan': '计划',
|
||||
'shared.tabBookings': '预订',
|
||||
'shared.tabPacking': '行李',
|
||||
'shared.tabBudget': '预算',
|
||||
'shared.tabChat': '聊天',
|
||||
'shared.days': '天',
|
||||
'shared.places': '个地点',
|
||||
'shared.other': '其他',
|
||||
'shared.totalBudget': '总预算',
|
||||
'shared.messages': '条消息',
|
||||
'shared.sharedVia': '通过以下分享',
|
||||
'shared.confirmed': '已确认',
|
||||
'shared.pending': '待确认',
|
||||
'share.permBudget': '预算',
|
||||
'share.permCollab': '聊天',
|
||||
'settings.on': '开',
|
||||
|
||||
@@ -55,8 +55,8 @@ export default function SharedTripPage() {
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: '#f3f4f6' }}>
|
||||
<div style={{ textAlign: 'center', padding: 40 }}>
|
||||
<div style={{ fontSize: 48, marginBottom: 16 }}>🔒</div>
|
||||
<h1 style={{ fontSize: 20, fontWeight: 700, color: '#111827' }}>Link expired or invalid</h1>
|
||||
<p style={{ color: '#6b7280', marginTop: 8 }}>This shared trip link is no longer active.</p>
|
||||
<h1 style={{ fontSize: 20, fontWeight: 700, color: '#111827' }}>{t('shared.expired')}</h1>
|
||||
<p style={{ color: '#6b7280', marginTop: 8 }}>{t('shared.expiredHint')}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@@ -109,11 +109,11 @@ export default function SharedTripPage() {
|
||||
{[trip.start_date, trip.end_date].filter(Boolean).map((d: string) => new Date(d + 'T00:00:00').toLocaleDateString(locale, { day: 'numeric', month: 'short', year: 'numeric' })).join(' — ')}
|
||||
</span>
|
||||
{days?.length > 0 && <span style={{ fontSize: 11, opacity: 0.4 }}>·</span>}
|
||||
{days?.length > 0 && <span style={{ fontSize: 11, opacity: 0.5 }}>{days.length} days</span>}
|
||||
{days?.length > 0 && <span style={{ fontSize: 11, opacity: 0.5 }}>{days.length} {t('shared.days')}</span>}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div style={{ marginTop: 12, fontSize: 9, fontWeight: 500, letterSpacing: 1.5, textTransform: 'uppercase', opacity: 0.25 }}>Read-only shared view</div>
|
||||
<div style={{ marginTop: 12, fontSize: 9, fontWeight: 500, letterSpacing: 1.5, textTransform: 'uppercase', opacity: 0.25 }}>{t('shared.readOnly')}</div>
|
||||
|
||||
{/* Language picker - top right */}
|
||||
<div style={{ position: 'absolute', top: 12, right: 12, zIndex: 10 }}>
|
||||
@@ -142,11 +142,11 @@ export default function SharedTripPage() {
|
||||
{/* Tabs */}
|
||||
<div style={{ display: 'flex', gap: 6, marginBottom: 20, overflowX: 'auto', padding: '2px 0' }}>
|
||||
{[
|
||||
{ id: 'plan', label: 'Plan', Icon: Map },
|
||||
...(permissions?.share_bookings ? [{ id: 'bookings', label: 'Bookings', Icon: Ticket }] : []),
|
||||
...(permissions?.share_packing ? [{ id: 'packing', label: 'Packing', Icon: Luggage }] : []),
|
||||
...(permissions?.share_budget ? [{ id: 'budget', label: 'Budget', Icon: Wallet }] : []),
|
||||
...(permissions?.share_collab ? [{ id: 'collab', label: 'Chat', Icon: MessageCircle }] : []),
|
||||
{ id: 'plan', label: t('shared.tabPlan'), Icon: Map },
|
||||
...(permissions?.share_bookings ? [{ id: 'bookings', label: t('shared.tabBookings'), Icon: Ticket }] : []),
|
||||
...(permissions?.share_packing ? [{ id: 'packing', label: t('shared.tabPacking'), Icon: Luggage }] : []),
|
||||
...(permissions?.share_budget ? [{ id: 'budget', label: t('shared.tabBudget'), Icon: Wallet }] : []),
|
||||
...(permissions?.share_collab ? [{ id: 'collab', label: t('shared.tabChat'), Icon: MessageCircle }] : []),
|
||||
].map(tab => (
|
||||
<button key={tab.id} onClick={() => setActiveTab(tab.id)} style={{
|
||||
padding: '8px 18px', borderRadius: 12, border: '1.5px solid', cursor: 'pointer',
|
||||
@@ -202,7 +202,7 @@ export default function SharedTripPage() {
|
||||
<Hotel size={8} /> {acc.place_name}
|
||||
</span>
|
||||
))}
|
||||
<span style={{ fontSize: 11, color: '#9ca3af' }}>{da.length} {da.length === 1 ? 'place' : 'places'}</span>
|
||||
<span style={{ fontSize: 11, color: '#9ca3af' }}>{da.length} {t('shared.places')}</span>
|
||||
</div>
|
||||
|
||||
{selectedDay === day.id && merged.length > 0 && (
|
||||
@@ -287,7 +287,7 @@ export default function SharedTripPage() {
|
||||
</div>
|
||||
</div>
|
||||
<span style={{ fontSize: 10, padding: '2px 8px', borderRadius: 20, fontWeight: 600, background: r.status === 'confirmed' ? 'rgba(22,163,74,0.1)' : 'rgba(217,119,6,0.1)', color: r.status === 'confirmed' ? '#16a34a' : '#d97706' }}>
|
||||
{r.status}
|
||||
{r.status === 'confirmed' ? t('shared.confirmed') : t('shared.pending')}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
@@ -298,7 +298,7 @@ export default function SharedTripPage() {
|
||||
{/* Packing */}
|
||||
{activeTab === 'packing' && (packing || []).length > 0 && (
|
||||
<div style={{ background: 'var(--bg-card, white)', borderRadius: 14, border: '1px solid var(--border-faint, #e5e7eb)', overflow: 'hidden' }}>
|
||||
{Object.entries((packing || []).reduce((g: any, i: any) => { const c = i.category || 'Other'; (g[c] = g[c] || []).push(i); return g }, {})).map(([cat, items]: [string, any]) => (
|
||||
{Object.entries((packing || []).reduce((g: any, i: any) => { const c = i.category || t('shared.other'); (g[c] = g[c] || []).push(i); return g }, {})).map(([cat, items]: [string, any]) => (
|
||||
<div key={cat}>
|
||||
<div style={{ padding: '8px 16px', background: '#f9fafb', fontSize: 11, fontWeight: 700, color: '#6b7280', textTransform: 'uppercase', letterSpacing: '0.05em', borderBottom: '1px solid #f3f4f6' }}>{cat}</div>
|
||||
{items.map((item: any) => (
|
||||
@@ -313,13 +313,13 @@ export default function SharedTripPage() {
|
||||
|
||||
{/* Budget */}
|
||||
{activeTab === 'budget' && (budget || []).length > 0 && (() => {
|
||||
const grouped = (budget || []).reduce((g: any, i: any) => { const c = i.category || 'Other'; (g[c] = g[c] || []).push(i); return g }, {})
|
||||
const grouped = (budget || []).reduce((g: any, i: any) => { const c = i.category || t('shared.other'); (g[c] = g[c] || []).push(i); return g }, {})
|
||||
const total = (budget || []).reduce((s: number, i: any) => s + (parseFloat(i.total_price) || 0), 0)
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
||||
{/* Total card */}
|
||||
<div style={{ background: 'linear-gradient(135deg, #000 0%, #1a1a2e 100%)', borderRadius: 14, padding: '20px 24px', color: 'white' }}>
|
||||
<div style={{ fontSize: 10, fontWeight: 500, letterSpacing: 1, textTransform: 'uppercase', opacity: 0.5 }}>Total Budget</div>
|
||||
<div style={{ fontSize: 10, fontWeight: 500, letterSpacing: 1, textTransform: 'uppercase', opacity: 0.5 }}>{t('shared.totalBudget')}</div>
|
||||
<div style={{ fontSize: 28, fontWeight: 700, marginTop: 4 }}>{total.toLocaleString(locale, { minimumFractionDigits: 2 })} {trip.currency || 'EUR'}</div>
|
||||
</div>
|
||||
{/* By category */}
|
||||
@@ -346,7 +346,7 @@ export default function SharedTripPage() {
|
||||
<div style={{ background: 'var(--bg-card, white)', borderRadius: 14, border: '1px solid var(--border-faint, #e5e7eb)', overflow: 'hidden' }}>
|
||||
<div style={{ padding: '12px 16px', background: '#f9fafb', borderBottom: '1px solid #f3f4f6', display: 'flex', alignItems: 'center', gap: 8 }}>
|
||||
<MessageCircle size={14} color="#6b7280" />
|
||||
<span style={{ fontSize: 12, fontWeight: 700, color: '#374151' }}>Chat · {(collab || []).length} messages</span>
|
||||
<span style={{ fontSize: 12, fontWeight: 700, color: '#374151' }}>{t('shared.tabChat')} · {(collab || []).length} {t('shared.messages')}</span>
|
||||
</div>
|
||||
<div style={{ maxHeight: 500, overflowY: 'auto', padding: '12px 16px', display: 'flex', flexDirection: 'column', gap: 10 }}>
|
||||
{(collab || []).map((msg: any, i: number) => {
|
||||
@@ -382,7 +382,7 @@ export default function SharedTripPage() {
|
||||
<div style={{ textAlign: 'center', padding: '40px 0 20px' }}>
|
||||
<div style={{ display: 'inline-flex', alignItems: 'center', gap: 8, padding: '8px 16px', borderRadius: 20, background: 'var(--bg-card, white)', border: '1px solid var(--border-faint, #e5e7eb)', boxShadow: '0 1px 3px rgba(0,0,0,0.04)' }}>
|
||||
<img src="/icons/icon.svg" alt="TREK" width="18" height="18" style={{ borderRadius: 4 }} />
|
||||
<span style={{ fontSize: 11, color: '#9ca3af' }}>Shared via <strong style={{ color: '#6b7280' }}>TREK</strong></span>
|
||||
<span style={{ fontSize: 11, color: '#9ca3af' }}>{t('shared.sharedVia')} <strong style={{ color: '#6b7280' }}>TREK</strong></span>
|
||||
</div>
|
||||
<div style={{ marginTop: 8, fontSize: 10, color: '#d1d5db' }}>Made with <span style={{ color: '#ef4444' }}>♥</span> by Maurice · <a href="https://github.com/mauriceboe/TREK" style={{ color: '#9ca3af', textDecoration: 'none' }}>GitHub</a></div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user