mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-20 22:01:45 +00:00
fix(i18n): translate hardcoded strings in JourneyDetailPage and fix ellipsis in all languages
- Replace all remaining hardcoded strings in JourneyDetailPage JourneySettingsDialog with t() calls - Add 14 missing translation keys to all 13 non-English language files (trips.member*, common.expand/collapse, inspector.remove, memories.*, journey.*) - Fix common.loading and common.saving to use Unicode ellipsis (…) instead of three dots (...) - Update 4 test files that expected three-dot ellipsis to use Unicode ellipsis - All 2541 tests passing
This commit is contained in:
@@ -47,7 +47,7 @@ describe('AuditLogPanel', () => {
|
||||
}),
|
||||
);
|
||||
render(<AuditLogPanel serverTimezone="UTC" />);
|
||||
expect(screen.getByText('Loading...')).toBeInTheDocument();
|
||||
expect(screen.getByText('Loading…')).toBeInTheDocument();
|
||||
expect(document.querySelector('table')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('GitHubPanel', () => {
|
||||
|
||||
it('FE-ADMIN-GH-002: all support links have correct href and target=_blank', async () => {
|
||||
render(<GitHubPanel />);
|
||||
await waitFor(() => expect(screen.queryByText('Loading...')).not.toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText('Loading…')).not.toBeInTheDocument());
|
||||
|
||||
const kofi = screen.getByText('Ko-fi').closest('a')!;
|
||||
expect(kofi).toHaveAttribute('href', 'https://ko-fi.com/mauriceboe');
|
||||
@@ -272,7 +272,7 @@ describe('GitHubPanel', () => {
|
||||
|
||||
it('FE-ADMIN-GH-016: support card hover effects fire without error', async () => {
|
||||
render(<GitHubPanel />);
|
||||
await waitFor(() => expect(screen.queryByText('Loading...')).not.toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.queryByText('Loading…')).not.toBeInTheDocument());
|
||||
|
||||
const kofiLink = screen.getByText('Ko-fi').closest('a')!;
|
||||
fireEvent.mouseEnter(kofiLink);
|
||||
|
||||
@@ -189,7 +189,7 @@ export default function DayDetailPanel({ day, days, places, categories = [], tri
|
||||
</div>
|
||||
{!collapsed && formattedDate && <div style={{ fontSize: 12, color: 'var(--text-muted)', marginTop: 1 }}>{formattedDate}</div>}
|
||||
</div>
|
||||
<button onClick={(e) => { e.stopPropagation(); toggleCollapse() }} title={collapsed ? 'Expand' : 'Collapse'}
|
||||
<button onClick={(e) => { e.stopPropagation(); toggleCollapse() }} title={collapsed ? t('common.expand') : t('common.collapse')}
|
||||
style={{ background: 'var(--bg-secondary)', border: 'none', borderRadius: 10, width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', flexShrink: 0, transition: 'all 0.15s ease' }}
|
||||
onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-hover)'}
|
||||
onMouseLeave={e => e.currentTarget.style.background = 'var(--bg-secondary)'}>
|
||||
|
||||
@@ -601,7 +601,7 @@ export default function PlaceInspector({
|
||||
{selectedDayId && (
|
||||
assignmentInDay ? (
|
||||
<ActionButton onClick={() => onRemoveAssignment(selectedDayId, assignmentInDay.id)} variant="ghost" icon={<Minus size={13} />}
|
||||
label={<><span className="hidden sm:inline">{t('inspector.removeFromDay')}</span><span className="sm:hidden">Remove</span></>} />
|
||||
label={<><span className="hidden sm:inline">{t('inspector.removeFromDay')}</span><span className="sm:hidden">{t('inspector.remove')}</span></>} />
|
||||
) : (
|
||||
<ActionButton onClick={() => onAssignToDay(place.id)} variant="primary" icon={<Plus size={13} />} label={t('inspector.addToDay')} />
|
||||
)
|
||||
|
||||
@@ -107,7 +107,7 @@ export default function NotificationsTab(): React.ReactElement {
|
||||
}
|
||||
|
||||
const renderContent = () => {
|
||||
if (!matrix) return <p style={{ fontSize: 12, color: 'var(--text-faint)', fontStyle: 'italic' }}>Loading…</p>
|
||||
if (!matrix) return <p style={{ fontSize: 12, color: 'var(--text-faint)', fontStyle: 'italic' }}>{t('common.loading')}</p>
|
||||
|
||||
if (visibleChannels.length === 0) {
|
||||
return (
|
||||
@@ -119,7 +119,7 @@ export default function NotificationsTab(): React.ReactElement {
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
|
||||
{saving && <p style={{ fontSize: 11, color: 'var(--text-faint)', marginBottom: 8 }}>Saving…</p>}
|
||||
{saving && <p style={{ fontSize: 11, color: 'var(--text-faint)', marginBottom: 8 }}>{t('common.saving')}</p>}
|
||||
{matrix.available_channels.webhook && (
|
||||
<div style={{ marginBottom: 16, padding: '12px', background: 'var(--bg-secondary)', borderRadius: 8, border: '1px solid var(--border-primary)' }}>
|
||||
<label style={{ display: 'block', fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)', marginBottom: 4 }}>
|
||||
|
||||
@@ -253,7 +253,7 @@ export default function PhotoProvidersSection(): React.ReactElement {
|
||||
onClick={() => handleSaveProvider(provider)}
|
||||
disabled={!canSave || !!saving[provider.id] || isProviderSaveDisabled(provider)}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-slate-900 text-white rounded-lg text-sm hover:bg-slate-700 disabled:bg-slate-400"
|
||||
title={!canSave ? 'Save route is not configured for this provider' : isProviderSaveDisabled(provider) ? 'Please fill all required fields' : ''}
|
||||
title={!canSave ? t('memories.saveRouteNotConfigured') : isProviderSaveDisabled(provider) ? t('memories.fillRequiredFields') : ''}
|
||||
>
|
||||
<Save className="w-4 h-4" /> {t('common.save')}
|
||||
</button>
|
||||
@@ -261,7 +261,7 @@ export default function PhotoProvidersSection(): React.ReactElement {
|
||||
onClick={() => handleTestProvider(provider)}
|
||||
disabled={!canTest || testing}
|
||||
className="flex items-center gap-2 px-4 py-2 border border-slate-200 rounded-lg text-sm hover:bg-slate-50"
|
||||
title={!canTest ? 'Test route is not configured for this provider' : ''}
|
||||
title={!canTest ? t('memories.testRouteNotConfigured') : ''}
|
||||
>
|
||||
{testing
|
||||
? <div className="w-4 h-4 border-2 border-slate-300 border-t-slate-700 rounded-full animate-spin" />
|
||||
|
||||
@@ -284,6 +284,6 @@ describe('TripFormModal', () => {
|
||||
const submitBtns = screen.getAllByText('Create New Trip');
|
||||
const submitBtn = submitBtns.find(el => el.closest('button'))!;
|
||||
await user.click(submitBtn.closest('button')!);
|
||||
await waitFor(() => expect(screen.getByText('Saving...')).toBeInTheDocument());
|
||||
await waitFor(() => expect(screen.getByText('Saving…')).toBeInTheDocument());
|
||||
});
|
||||
});
|
||||
|
||||
@@ -385,8 +385,8 @@ export default function TripFormModal({ isOpen, onClose, onSave, trip, onCoverUp
|
||||
try {
|
||||
await tripsApi.removeMember(trip!.id, m.id)
|
||||
setExistingMembers(prev => prev.filter(x => x.id !== m.id))
|
||||
toast.success(`${m.username} removed`)
|
||||
} catch { toast.error('Failed to remove') }
|
||||
toast.success(t('trips.memberRemoved', { username: m.username }))
|
||||
} catch { toast.error(t('trips.memberRemoveError')) }
|
||||
}}
|
||||
style={{
|
||||
display: 'flex', alignItems: 'center', gap: 5, padding: '4px 10px', borderRadius: 99,
|
||||
@@ -431,8 +431,8 @@ export default function TripFormModal({ isOpen, onClose, onSave, trip, onCoverUp
|
||||
try {
|
||||
await tripsApi.addMember(trip.id, user.username)
|
||||
setExistingMembers(prev => [...prev, { id: user.id, username: user.username }])
|
||||
toast.success(`${user.username} added`)
|
||||
} catch { toast.error('Failed to add') }
|
||||
toast.success(t('trips.memberAdded', { username: user.username }))
|
||||
} catch { toast.error(t('trips.memberAddError')) }
|
||||
}
|
||||
} else {
|
||||
setSelectedMembers(prev => prev.includes(Number(value)) ? prev : [...prev, Number(value)])
|
||||
|
||||
Reference in New Issue
Block a user