Skip to content

Commit b600a91

Browse files
committed
Enhance internationalization support and update user interface components
- Added new translations for survey permissions and alert messages in English, Portuguese, and Swahili. - Updated the Reset Password and User Modals to utilize i18n for improved localization. - Enhanced the Alert Distribution and Submission Trend charts with translated tooltips and labels for better user experience. - Refactored various components to ensure consistent use of translation functions, improving maintainability and user accessibility.
1 parent 2da36ec commit b600a91

13 files changed

Lines changed: 164 additions & 115 deletions

public/locales/en/admin.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
"createUser": "Create New User",
101101
"editUser": "Edit User: ",
102102
"resetPasswordFor": "Reset Password for ",
103-
"resetPasswordWarning": "Warning: This will immediately reset the password for {{username}}. Make sure to communicate the new password securely to the user."
103+
"resetPasswordWarning": "Warning: This will immediately reset the password for {{username}}. Make sure to communicate the new password securely to the user.",
104+
"surveyPermissionsTitle": "Survey Permissions:",
105+
"surveyPermissionsAdminNote": "Administrators have access to all surveys.",
106+
"surveyPermissionsUserNote": "Regular users are assigned surveys in Airtable."
104107
}
105108
}

public/locales/en/enumerators.json

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,26 +34,32 @@
3434
},
3535
"noData": "No data available for the selected period",
3636
"submissions": "Submissions",
37-
"qualityScore": "Quality Score",
37+
"qualityScore": "Quality Score (%)",
3838
"clickForDetails": "Click to view details",
3939
"cleanSubmissions": "Clean submissions",
4040
"withAlerts": "With alerts",
4141
"dragToZoom": "Drag to zoom into a specific period",
4242
"noSubmissionsDate": "No submissions on this date",
4343
"total": "Total:",
44-
"submissionSuffix": "submission(s)",
44+
"submission": "submission",
45+
"submissionPlural": "submissions",
4546
"noAlerts": "No alerts in this period",
47+
"noAlertsTitle": "No alerts",
4648
"noAlertsDescription": "All submissions in the selected date range passed validation without issues.",
4749
"noAlertsEnumerator": "This enumerator has no flagged submissions in the selected period.",
4850
"alertsDetected": "total alert(s) detected",
51+
"alertCount": "{{count}} total alert",
52+
"alertCountPlural": "{{count}} total alerts",
4953
"alertsTotal": "alert(s) total",
5054
"alert": "Alert: ",
5155
"alertType": "Alert Type: ",
5256
"count": "Count:",
5357
"share": "Share:",
58+
"percentage": "Percentage",
5459
"outOfTotal": "Out of total",
5560
"dataLabel": "data label",
56-
"submissionsOverDays": "submission(s) over X day(s)",
61+
"submissionsOverDays": "{{count}} submission over {{days}} day",
62+
"submissionsOverDaysPlural": "{{count}} submissions over {{days}} days",
5763
"peakDay": "🎯 Peak day",
5864
"dailyAverage": "Daily average"
5965
},

public/locales/pt/admin.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
"createUser": "Criar Novo Utilizador",
101101
"editUser": "Editar Utilizador: ",
102102
"resetPasswordFor": "Repor Palavra-passe de ",
103-
"resetPasswordWarning": "Aviso: Isto vai repor imediatamente a palavra-passe de {{username}}. Certifique-se de comunicar a nova palavra-passe ao utilizador de forma segura."
103+
"resetPasswordWarning": "Aviso: Isto vai repor imediatamente a palavra-passe de {{username}}. Certifique-se de comunicar a nova palavra-passe ao utilizador de forma segura.",
104+
"surveyPermissionsTitle": "Permissões de Inquéritos:",
105+
"surveyPermissionsAdminNote": "Os administradores têm acesso a todos os inquéritos.",
106+
"surveyPermissionsUserNote": "Utilizadores comuns recebem inquéritos atribuídos no Airtable."
104107
}
105108
}

public/locales/pt/enumerators.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,25 @@
4141
"dragToZoom": "Arraste para aumentar um período específico",
4242
"noSubmissionsDate": "Sem submissões nesta data",
4343
"total": "Total:",
44-
"submissionSuffix": "submissão(ões)",
44+
"submission": "submissão",
45+
"submissionPlural": "submissões",
4546
"noAlerts": "Sem alertas neste período",
47+
"noAlertsTitle": "Sem alertas",
4648
"noAlertsDescription": "Todas as submissões no período selecionado passaram na validação sem problemas.",
4749
"noAlertsEnumerator": "Este enumerador não tem submissões sinalizadas no período selecionado.",
4850
"alertsDetected": "alerta(s) detetado(s) no total",
51+
"alertCount": "{{count}} alerta no total",
52+
"alertCountPlural": "{{count}} alertas no total",
4953
"alertsTotal": "alerta(s) no total",
5054
"alert": "Alerta: ",
5155
"alertType": "Tipo de Alerta: ",
5256
"count": "Contagem:",
5357
"share": "Percentagem:",
58+
"percentage": "Percentagem",
5459
"outOfTotal": "Do total",
5560
"dataLabel": "rótulo de dados",
56-
"submissionsOverDays": "submissão(ões) ao longo de X dia(s)",
61+
"submissionsOverDays": "{{count}} submissão ao longo de {{days}} dia",
62+
"submissionsOverDaysPlural": "{{count}} submissões ao longo de {{days}} dias",
5763
"peakDay": "🎯 Dia de pico",
5864
"dailyAverage": "Média diária"
5965
},

public/locales/sw/admin.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@
100100
"createUser": "Unda Mtumiaji Mpya",
101101
"editUser": "Hariri Mtumiaji: ",
102102
"resetPasswordFor": "Weka Upya Nenosiri kwa ",
103-
"resetPasswordWarning": "Onyo: Hii itaweka upya nenosiri la {{username}} mara moja. Hakikisha unawasilisha nenosiri jipya kwa usalama kwa mtumiaji."
103+
"resetPasswordWarning": "Onyo: Hii itaweka upya nenosiri la {{username}} mara moja. Hakikisha unawasilisha nenosiri jipya kwa usalama kwa mtumiaji.",
104+
"surveyPermissionsTitle": "Ruhusa za Tafiti:",
105+
"surveyPermissionsAdminNote": "Wasimamizi wana ufikiaji wa tafiti zote.",
106+
"surveyPermissionsUserNote": "Watumiaji wa kawaida wanapangiwa tafiti kwenye Airtable."
104107
}
105108
}

public/locales/sw/enumerators.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,25 @@
4141
"dragToZoom": "Buruta ili kukuza kipindi mahususi",
4242
"noSubmissionsDate": "Hakuna uwasilishaji katika tarehe hii",
4343
"total": "Jumla:",
44-
"submissionSuffix": "uwasilishaji",
44+
"submission": "uwasilishaji",
45+
"submissionPlural": "uwasilishaji",
4546
"noAlerts": "Hakuna tahadhari katika kipindi hiki",
47+
"noAlertsTitle": "Hakuna tahadhari",
4648
"noAlertsDescription": "Uwasilishaji wote katika kipindi kilichochaguliwa wamepitisha uthibitishaji bila matatizo.",
4749
"noAlertsEnumerator": "Mkusanyaji huyu hana uwasilishaji ulioainishwa katika kipindi kilichochaguliwa.",
4850
"alertsDetected": "jumla ya tahadhari zilizogunduliwa",
51+
"alertCount": "{{count}} tahadhari jumla",
52+
"alertCountPlural": "{{count}} tahadhari jumla",
4953
"alertsTotal": "jumla ya tahadhari",
5054
"alert": "Tahadhari: ",
5155
"alertType": "Aina ya Tahadhari: ",
5256
"count": "Idadi:",
5357
"share": "Sehemu:",
58+
"percentage": "Asilimia",
5459
"outOfTotal": "Kati ya jumla",
5560
"dataLabel": "lebo ya data",
56-
"submissionsOverDays": "uwasilishaji katika siku X",
61+
"submissionsOverDays": "{{count}} uwasilishaji katika siku {{days}}",
62+
"submissionsOverDaysPlural": "{{count}} uwasilishaji katika siku {{days}}",
5763
"peakDay": "🎯 Siku yenye kilele",
5864
"dailyAverage": "Wastani wa kila siku"
5965
},

src/components/Admin/ResetPasswordModal.tsx

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import React, { useState } from 'react';
2+
import { useTranslation } from 'react-i18next';
23
import { IconAlertTriangle } from '@tabler/icons-react';
34
import { User } from '../../api/admin';
45
import { getApiBaseUrl } from '../../utils/apiConfig';
@@ -10,6 +11,7 @@ interface ResetPasswordModalProps {
1011
}
1112

1213
const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose, onSuccess }) => {
14+
const { t } = useTranslation('admin');
1315
const [newPassword, setNewPassword] = useState('');
1416
const [confirmPassword, setConfirmPassword] = useState('');
1517
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -21,12 +23,12 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose,
2123

2224
// Validation
2325
if (!newPassword.trim() || newPassword.length < 8) {
24-
setError('Password must be at least 8 characters');
26+
setError(t('form.passwordMinLength'));
2527
return;
2628
}
2729

2830
if (newPassword !== confirmPassword) {
29-
setError('Passwords do not match');
31+
setError(t('form.passwordsNoMatch'));
3032
return;
3133
}
3234

@@ -37,7 +39,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose,
3739
const token = localStorage.getItem('authToken');
3840

3941
if (!token) {
40-
setError('Authentication token not found. Please log in again.');
42+
setError(t('messages.tokenNotFound'));
4143
setIsSubmitting(false);
4244
return;
4345
}
@@ -53,29 +55,29 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose,
5355
});
5456

5557
if (!response.ok) {
56-
const errorData = await response.json().catch(() => ({ message: 'Failed to reset password' }));
58+
const errorData = await response.json().catch(() => ({ message: t('form.resetPasswordFailed') }));
5759
if (response.status === 401) {
58-
setError('Authentication failed. Please log in again.');
60+
setError(t('form.authFailed'));
5961
} else if (response.status === 403) {
60-
setError('You do not have permission to reset passwords.');
62+
setError(t('form.permissionDenied'));
6163
} else {
62-
setError(errorData.message || errorData.error || 'Failed to reset password');
64+
setError(errorData.message || errorData.error || t('form.resetPasswordFailed'));
6365
}
6466
return;
6567
}
6668

6769
const result = await response.json();
6870

6971
if (result.success) {
70-
alert(`Password reset successfully for ${user.username}`);
72+
alert(`${t('form.passwordResetSuccess')}${user.username}`);
7173
onSuccess();
7274
onClose();
7375
} else {
74-
setError(result.message || 'Failed to reset password');
76+
setError(result.message || t('form.resetPasswordFailed'));
7577
}
7678
} catch (err) {
7779
console.error('Reset password error:', err);
78-
setError('An unexpected error occurred. Please try again.');
80+
setError(t('form.unexpectedError'));
7981
} finally {
8082
setIsSubmitting(false);
8183
}
@@ -91,7 +93,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose,
9193
<div className="modal-dialog modal-dialog-centered">
9294
<div className="modal-content">
9395
<div className="modal-header">
94-
<h5 className="modal-title">Reset Password for {user.username}</h5>
96+
<h5 className="modal-title">{t('modal.resetPasswordFor')}{user.username}</h5>
9597
<button type="button" className="btn-close" onClick={onClose}></button>
9698
</div>
9799
<form onSubmit={handleSubmit}>
@@ -106,37 +108,36 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose,
106108
)}
107109

108110
<div className="mb-3">
109-
<label className="form-label required">New Password</label>
111+
<label className="form-label required">{t('form.newPassword')}</label>
110112
<input
111113
type="password"
112114
className="form-control"
113115
value={newPassword}
114116
onChange={(e) => setNewPassword(e.target.value)}
115117
disabled={isSubmitting}
116-
placeholder="Enter new password"
118+
placeholder={t('form.newPasswordPlaceholder')}
117119
required
118120
/>
119-
<small className="form-hint">Minimum 8 characters</small>
121+
<small className="form-hint">{t('form.minCharacters')}</small>
120122
</div>
121123

122124
<div className="mb-3">
123-
<label className="form-label required">Confirm Password</label>
125+
<label className="form-label required">{t('form.confirmPassword')}</label>
124126
<input
125127
type="password"
126128
className="form-control"
127129
value={confirmPassword}
128130
onChange={(e) => setConfirmPassword(e.target.value)}
129131
disabled={isSubmitting}
130-
placeholder="Confirm new password"
132+
placeholder={t('form.confirmPasswordPlaceholder')}
131133
required
132134
/>
133135
</div>
134136

135137
<div className="alert alert-warning">
136138
<IconAlertTriangle className="icon alert-icon" size={24} stroke={2} />
137139
<div>
138-
<strong>Warning:</strong> This will immediately reset the password for {user.username}.
139-
Make sure to communicate the new password securely to the user.
140+
{t('modal.resetPasswordWarning', { username: user.username })}
140141
</div>
141142
</div>
142143
</div>
@@ -148,7 +149,7 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose,
148149
onClick={onClose}
149150
disabled={isSubmitting}
150151
>
151-
Cancel
152+
{t('form.cancel')}
152153
</button>
153154
<button
154155
type="submit"
@@ -158,10 +159,10 @@ const ResetPasswordModal: React.FC<ResetPasswordModalProps> = ({ user, onClose,
158159
{isSubmitting ? (
159160
<>
160161
<span className="spinner-border spinner-border-sm me-2"></span>
161-
Resetting...
162+
{t('form.resetting')}
162163
</>
163164
) : (
164-
'Reset Password'
165+
t('form.resetPassword')
165166
)}
166167
</button>
167168
</div>

0 commit comments

Comments
 (0)