Skip to content

Commit 2efd010

Browse files
author
Saket Hatwar
committed
Add Translations
1 parent 252052d commit 2efd010

17 files changed

+1125
-237
lines changed

Makefile

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,8 @@ locales:
9797
npx i18next-conv -l hi -s modules/datadict/locale/hi/LC_MESSAGES/datadict.po -t modules/datadict/locale/hi/LC_MESSAGES/datadict.json
9898
npx i18next-conv -l ja -s modules/datadict/locale/ja/LC_MESSAGES/datadict.po -t modules/datadict/locale/ja/LC_MESSAGES/datadict.json
9999
msgfmt -o modules/dataquery/locale/ja/LC_MESSAGES/dataquery.mo modules/dataquery/locale/ja/LC_MESSAGES/dataquery.po
100+
msgfmt -o modules/dataquery/locale/hi/LC_MESSAGES/dataquery.mo modules/dataquery/locale/hi/LC_MESSAGES/dataquery.po
101+
npx i18next-conv -l hi -s modules/dataquery/locale/hi/LC_MESSAGES/dataquery.po -t modules/dataquery/locale/hi/LC_MESSAGES/dataquery.json
100102
msgfmt -o modules/data_release/locale/ja/LC_MESSAGES/data_release.mo modules/data_release/locale/ja/LC_MESSAGES/data_release.po
101103
npx i18next-conv -l ja -s modules/data_release/locale/ja/LC_MESSAGES/data_release.po -t modules/data_release/locale/ja/LC_MESSAGES/data_release.json
102104
msgfmt -o modules/data_release/locale/hi/LC_MESSAGES/data_release.mo modules/data_release/locale/hi/LC_MESSAGES/data_release.po
@@ -153,8 +155,9 @@ data_release: modules/data_release/locale/hi/LC_MESSAGES/data_release.mo modules
153155
instrument_manager: modules/instrument_manager/locale/ja/LC_MESSAGES/instrument_manager.mo
154156
target=instrument_manager npm run compile
155157

156-
dataquery: modules/dataquery/locale/ja/LC_MESSAGES/dataquery.mo
157-
msgfmt -o modules/dataquery/locale/ja/LC_MESSAGES/dataquery.mo modules/dataquery/locale/ja/LC_MESSAGES/dataquery.po
158+
dataquery:
159+
msgfmt -o modules/dataquery/locale/hi/LC_MESSAGES/dataquery.mo modules/dataquery/locale/hi/LC_MESSAGES/dataquery.po
160+
npx i18next-conv -l hi -s modules/dataquery/locale/hi/LC_MESSAGES/dataquery.po -t modules/dataquery/locale/hi/LC_MESSAGES/dataquery.json
158161
target=dataquery npm run compile
159162

160163
login: modules/login/locale/ja/LC_MESSAGES/login.mo

jsx/I18nSetup.d.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
declare module "I18nSetup" {
2+
import i18n from "i18next";
3+
export default i18n;
4+
}

modules/dataquery/jsx/definefields.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {CheckboxElement} from 'jsx/Form';
66
import {FullDictionary, FieldDictionary, DictionaryCategory} from './types';
77
import {CategoriesAPIReturn} from './hooks/usedatadictionary';
88
import {APIQueryField, VisitOption} from './types';
9-
9+
import {useTranslation} from 'react-i18next';
1010

1111
/**
1212
* Displays a single field to be selected for querying
@@ -46,6 +46,7 @@ function QueryField(props: {
4646
) => void,
4747
defaultVisits: string[],
4848
}) {
49+
const {t} = useTranslation('dataquery');
4950
const item=props.item;
5051
const className = props.selected ?
5152
'list-group-item active' :
@@ -93,14 +94,14 @@ function QueryField(props: {
9394

9495
if (props.selected) {
9596
visits = <div onClick={(e) => e.stopPropagation()}>
96-
<h4>Visits</h4>
97+
<h4>{t('Visits', {ns: 'loris'})}</h4>
9798
<Select options={selectOptions.map((visit: string): VisitOption => {
9899
return {value: visit, label: visit};
99100
})
100101
}
101102
isMulti
102103
onChange={selected}
103-
placeholder='Select Visits'
104+
placeholder={t('Select Visits', {ns: 'loris'})}
104105
value={selectedVisits.map( (visit: string): VisitOption => {
105106
return {value: visit, label: visit};
106107
})

modules/dataquery/jsx/definefilters.addfiltermodal.tsx

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
VisitOption,
1919
} from './types';
2020
import {CategoriesAPIReturn} from './hooks/usedatadictionary';
21+
import {useTranslation} from 'react-i18next';
2122

2223
/**
2324
* Renders a selectable list of visits
@@ -33,6 +34,7 @@ function VisitList(props: {
3334
options: string[],
3435
onChange: (newvals: string[]) => void,
3536
}) {
37+
const {t} = useTranslation('dataquery');
3638
const selectOptions: VisitOption[] = props.options.map(
3739
(vl) => {
3840
return {value: vl, label: vl};
@@ -50,7 +52,7 @@ function VisitList(props: {
5052
newvals.map((valobj) => valobj.value)
5153
);
5254
}}
53-
placeholder='Select Visits'
55+
placeholder={t('Select Visits', {ns: 'dataquery'})}
5456
value={selectedVisits}
5557
menuPortalTarget={document.body}
5658
styles={{menuPortal:
@@ -92,6 +94,7 @@ function AddFilterModal(props: {
9294
module: string,
9395
category: string,
9496
}) {
97+
const {t} = useTranslation('dataquery');
9598
let fieldSelect;
9699
let criteriaSelect;
97100
let visitSelect;
@@ -129,11 +132,11 @@ function AddFilterModal(props: {
129132
if (fieldDictionary) {
130133
let valueSelect;
131134
if (op) {
132-
valueSelect = valueInput(fieldDictionary, op, value, setValue);
135+
valueSelect = valueInput(fieldDictionary, op, value, setValue,t);
133136
}
134137

135138
criteriaSelect = <div>
136-
<h3>Criteria</h3>
139+
<h3>{t('Criteria', {ns: 'dataquery'})}</h3>
137140
<div style={{display: 'flex'}}>
138141
<div style={{width: '20%'}}>
139142
<FilterableSelectGroup groups={
@@ -142,7 +145,7 @@ function AddFilterModal(props: {
142145
onChange={(value: string, operator: string) => {
143146
setOp(operator as Operators);
144147
}}
145-
placeholder="Select an operator"
148+
placeholder={t('Select an operator', {ns: 'dataquery'})}
146149
/>
147150
</div>
148151
<div style={{width: '80%'}}>{valueSelect}</div>
@@ -151,7 +154,7 @@ function AddFilterModal(props: {
151154

152155
if (fieldDictionary.scope == 'session' && fieldDictionary.visits) {
153156
visitSelect = <div onClick={(e) => e.stopPropagation()}>
154-
<h3>for at least one of the following visits</h3>
157+
<h3>{t('for at least one of the following visits', {ns: 'dataquery'})}</h3>
155158
<VisitList options={fieldDictionary.visits}
156159
selected={selectedVisits || []}
157160
onChange={setSelectedVisits}
@@ -173,10 +176,7 @@ function AddFilterModal(props: {
173176
<div style={{
174177
color: 'white',
175178
padding: '1em',
176-
}}>This field may exist multiple times for a
177-
single {fieldDictionary.scope}. Adding a criteria
178-
based on it means that it must match for <i>at least
179-
one</i> of the data points.</div>
179+
}}>{t('This field may exist multiple times for a single {{scope}}. Adding a criteria based on it means that it must match for <i>at least one</i> of the data points.', {ns: 'dataquery', scope: fieldDictionary.scope})}</div>
180180
</div>;
181181
}
182182
}
@@ -193,17 +193,17 @@ function AddFilterModal(props: {
193193
if (!fieldname) {
194194
swal.fire({
195195
type: 'error',
196-
title: 'Invalid field',
197-
text: 'You must select a field for the criteria.',
196+
title: t('Invalid field', {ns: 'dataquery'}),
197+
text: t('You must select a field for the criteria.', {ns: 'dataquery'}),
198198
});
199199
reject();
200200
return;
201201
}
202202
if (!op) {
203203
swal.fire({
204204
type: 'error',
205-
title: 'Invalid operator',
206-
text: 'You must select an operator for the criteria.',
205+
title: t('Invalid operator', {ns: 'dataquery'}),
206+
text: t('You must select an operator for the criteria.', {ns: 'dataquery'}),
207207
});
208208
reject();
209209
return;
@@ -214,9 +214,8 @@ function AddFilterModal(props: {
214214
&& op != 'exists' && op != 'notexists') {
215215
swal.fire({
216216
type: 'error',
217-
title: 'Invalid value',
218-
text: 'You must enter a value to compare the ' +
219-
'field against.',
217+
title: t('Invalid value', {ns: 'dataquery'}),
218+
text: t('You must enter a value to compare the field against.', {ns: 'dataquery'}),
220219
});
221220
reject();
222221
return;
@@ -227,8 +226,8 @@ function AddFilterModal(props: {
227226
if (!selectedVisits || selectedVisits.length == 0) {
228227
swal.fire({
229228
type: 'error',
230-
title: 'Invalid visits',
231-
text: 'No visits selected for criteria.',
229+
title: t('Invalid visits', {ns: 'dataquery'}),
230+
text: t('No visits selected for criteria.', {ns: 'dataquery'}),
232231
});
233232
reject();
234233
return;
@@ -257,13 +256,13 @@ function AddFilterModal(props: {
257256
}
258257
);
259258
return (
260-
<Modal title="Add criteria"
259+
<Modal title={t('Add criteria', {ns: 'dataquery'})}
261260
show={true}
262261
throwWarning={true}
263262
onClose={props.closeModal}
264263
onSubmit={submitPromise}>
265264
<div style={{width: '100%', padding: '1em'}}>
266-
<h3>Field</h3>
265+
<h3>{t('Field', {ns: 'dataquery'})}</h3>
267266
<div style={{display: 'flex', width: '100%'}}>
268267
<div style={{width: '40%'}}>
269268
<FilterableSelectGroup
@@ -300,7 +299,7 @@ function AddFilterModal(props: {
300299
*/
301300
function getOperatorOptions(dict: FieldDictionary) {
302301
let options: {[operator: string]: string};
303-
302+
const {t} = useTranslation('dataquery');
304303
if (dict.type == 'integer' || dict.type == 'date' ||
305304
dict.type == 'interval' || dict.type == 'time' ||
306305
dict.type == 'decimal') {
@@ -329,9 +328,9 @@ function getOperatorOptions(dict: FieldDictionary) {
329328
options = {
330329
'eq': '=',
331330
'neq': '≠',
332-
'startsWith': 'starts with',
333-
'contains': 'contains',
334-
'endsWith': 'ends with',
331+
'startsWith': t('starts with', {ns: 'dataquery'}),
332+
'contains': t('contains', {ns: 'dataquery'}),
333+
'endsWith': t('ends with', {ns: 'dataquery'}),
335334
};
336335
} else {
337336
// fall back to == and !=, valid for any type.
@@ -344,12 +343,12 @@ function getOperatorOptions(dict: FieldDictionary) {
344343
// 1-many cardinalities have a couple more
345344
// things you can check.
346345
if (dict.cardinality == 'optional') {
347-
options['isnotnull'] = 'has data';
348-
options['isnull'] = 'has no data';
346+
options['isnotnull'] = t('has data', {ns: 'dataquery'});
347+
options['isnull'] = t('has no data', {ns: 'dataquery'});
349348
} else if (dict.cardinality == 'many') {
350-
options['exists'] = 'exists';
351-
options['notexists'] = 'does not exist';
352-
options['numberof'] = 'number of';
349+
options['exists'] = t('exists', {ns: 'dataquery'});
350+
options['notexists'] = t('does not exist', {ns: 'dataquery'});
351+
options['numberof'] = t('number of', {ns: 'dataquery'});
353352
}
354353
return options;
355354
}
@@ -368,7 +367,8 @@ function getOperatorOptions(dict: FieldDictionary) {
368367
function valueInput(fielddict: FieldDictionary,
369368
op: Operators,
370369
value: string|string[],
371-
setValue: (val: string) => void
370+
setValue: (val: string) => void,
371+
t: any
372372
) {
373373
const vs: string = value as string;
374374
switch (op) {
@@ -415,14 +415,14 @@ function valueInput(fielddict: FieldDictionary,
415415
case 'boolean':
416416
return <FilterableSelectGroup groups={
417417
{'Value': {
418-
'true': 'true',
419-
'false': ' false',
418+
'true': t('true', {ns: 'dataquery'}),
419+
'false': t('false', {ns: 'dataquery'}),
420420
},
421421
}}
422422
onChange={(_: string, value: string) => {
423423
setValue(value);
424424
}}
425-
placeholder="Select a value"
425+
placeholder={t('Select a value', {ns: 'dataquery'})}
426426
/>;
427427
case 'enumeration':
428428
const opts: {[key: string]: string} = {};
@@ -453,7 +453,7 @@ function valueInput(fielddict: FieldDictionary,
453453
onChange={(_: string, value: string) => {
454454
setValue(value);
455455
}}
456-
placeholder="Select a value"
456+
placeholder={t('Select a value', {ns: 'dataquery'})}
457457
/>;
458458
default:
459459
return <TextboxElement

modules/dataquery/jsx/definefilters.importcsvmodal.tsx

Lines changed: 19 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {useState} from 'react';
44
import Papa from 'papaparse';
55
import swal from 'sweetalert2';
66
import {FileElement} from 'jsx/Form';
7+
import {useTranslation} from 'react-i18next';
78

89
/**
910
* Render a modal window for adding a filter
@@ -17,6 +18,7 @@ function ImportCSVModal(props: {
1718
setQuery: (root: QueryGroup) => void,
1819
closeModal: () => void,
1920
}) {
21+
const {t} = useTranslation('dataquery');
2022
const [csvFile, setCSVFile] = useState<string|null>(null);
2123
const [csvHeader, setCSVHeader] = useState<boolean>(false);
2224
const [csvType, setCSVType] = useState<string>('candidate');
@@ -44,8 +46,8 @@ function ImportCSVModal(props: {
4446
console.error(value.errors);
4547
swal.fire({
4648
type: 'error',
47-
title: 'Invalid CSV',
48-
text: 'Could not parse CSV file',
49+
title: t('Invalid CSV', {ns: 'dataquery'}),
50+
text: t('Could not parse CSV file', {ns: 'dataquery'}),
4951
});
5052
}
5153

@@ -58,21 +60,17 @@ function ImportCSVModal(props: {
5860
if (value.data[i].length != expectedLength) {
5961
swal.fire({
6062
type: 'error',
61-
title: 'Invalid CSV',
62-
text: 'Expected ' + expectedLength + ' columns in CSV.'
63-
+ ' Got ' + value.data[i].length + ' on line ' +
64-
(i+1) + '.',
63+
title: t('Invalid CSV', {ns: 'dataquery'}),
64+
text: t('Expected {{expectedLength}} columns in CSV. Got {{gotLength}} on line {{line}}.', {ns: 'dataquery', expectedLength, gotLength: value.data[i].length, line: i+1}),
6565
});
6666
return;
6767
}
6868
if (idType === 'CandID') {
6969
if (candIDRegex.test(value.data[i][0]) !== true) {
7070
swal.fire({
7171
type: 'error',
72-
title: 'Invalid DCC ID',
73-
text: 'Invalid DCC ID (' + value.data[i][0]
74-
+ ') on line '
75-
+ (i+1) + '.',
72+
title: t('Invalid DCC ID', {ns: 'dataquery'}),
73+
text: t('Invalid DCC ID ({{id}}) on line {{line}}.', {ns: 'dataquery', id: value.data[i][0], line: i+1}),
7674
});
7775
return;
7876
}
@@ -125,51 +123,51 @@ function ImportCSVModal(props: {
125123
marginTop: '1em',
126124
};
127125

128-
return <Modal title="Import Population From CSV"
126+
return <Modal title={t('Import Population From CSV', {ns: 'dataquery'})}
129127
show={true}
130128
throwWarning={true}
131129
onClose={props.closeModal}
132130
onSubmit={submitPromise}>
133131
<fieldset>
134132
<div>
135133
<dl>
136-
<dt style={dtstyle}>CSV containing list of</dt>
134+
<dt style={dtstyle}>{t('CSV containing list of', {ns: 'dataquery'})}</dt>
137135
<dd>
138136
<input type="radio" name="csvtype"
139137
checked={csvType == 'candidate'}
140138
onChange={() => setCSVType('candidate')}
141-
/> Candidates
139+
/> {t('Candidates', {ns: 'dataquery'})}
142140
<input type="radio" name="csvtype"
143141
style={{marginLeft: '1.5em'}}
144142
checked={csvType == 'session'}
145143
onChange={() => setCSVType('session')}
146-
/> Sessions
144+
/> {t('Sessions', {ns: 'dataquery'})}
147145
</dd>
148-
<dt style={dtstyle}>Candidate identifier type</dt>
146+
<dt style={dtstyle}>{t('Candidate identifier type', {ns: 'dataquery'})}</dt>
149147
<dd><input type="radio" name="candidtype"
150148
checked={idType == 'CandID'}
151149
onChange={() => setIdType('CandID')}
152-
/> DCC ID
150+
/> {t('DCC ID', {ns: 'dataquery'})}
153151
<input type="radio" name="candidtype"
154152
style={{marginLeft: '1.5em'}}
155153
checked={idType == 'PSCID'}
156154
onChange={() => setIdType('PSCID')}
157-
/> PSCID
155+
/> {t('PSCID', {ns: 'dataquery'})}
158156
</dd>
159157
<dt style={dtstyle}>
160-
Does CSV contain a header line?
158+
{t('Does CSV contain a header line?', {ns: 'dataquery'})}
161159
</dt>
162160
<dd><input type="radio" name="header"
163161
checked={csvHeader == true}
164162
onChange={() => setCSVHeader(true)}
165-
/> Yes
163+
/> {t('Yes', {ns: 'dataquery'})}
166164
<input type="radio" name="header"
167165
style={{marginLeft: '1.5em'}}
168166
checked={csvHeader == false}
169167
onChange={() => setCSVHeader(false)}
170-
/> No
168+
/> {t('No', {ns: 'dataquery'})}
171169
</dd>
172-
<dt style={dtstyle}>CSV File</dt>
170+
<dt style={dtstyle}>{t('CSV File', {ns: 'dataquery'})}</dt>
173171
<dd><FileElement label='' name="csvfile"
174172
value={csvFile}
175173
onUserInput={

0 commit comments

Comments
 (0)