@openmrs/esm-form-builder-app 3.1.1-pre.2178 → 3.1.1-pre.2185
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/1208.js +1 -1
- package/dist/1208.js.map +1 -1
- package/dist/4300.js +1 -1
- package/dist/openmrs-esm-form-builder-app.js.buildmanifest.json +8 -8
- package/dist/routes.json +1 -1
- package/package.json +1 -1
- package/src/components/translation-builder/translation-builder.component.tsx +104 -54
- package/src/components/translation-builder/translation-builder.module.scss +4 -0
|
@@ -188,9 +188,9 @@
|
|
|
188
188
|
"initial": false,
|
|
189
189
|
"entry": false,
|
|
190
190
|
"recorded": false,
|
|
191
|
-
"size":
|
|
191
|
+
"size": 709847,
|
|
192
192
|
"sizes": {
|
|
193
|
-
"javascript":
|
|
193
|
+
"javascript": 709847
|
|
194
194
|
},
|
|
195
195
|
"names": [],
|
|
196
196
|
"idHints": [],
|
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
"auxiliaryFiles": [
|
|
205
205
|
"1208.js.map"
|
|
206
206
|
],
|
|
207
|
-
"hash": "
|
|
207
|
+
"hash": "561f892439c8a5d1",
|
|
208
208
|
"childrenByOrder": {}
|
|
209
209
|
},
|
|
210
210
|
{
|
|
@@ -617,9 +617,9 @@
|
|
|
617
617
|
"initial": false,
|
|
618
618
|
"entry": false,
|
|
619
619
|
"recorded": false,
|
|
620
|
-
"size":
|
|
620
|
+
"size": 13468,
|
|
621
621
|
"sizes": {
|
|
622
|
-
"javascript":
|
|
622
|
+
"javascript": 13468
|
|
623
623
|
},
|
|
624
624
|
"names": [],
|
|
625
625
|
"idHints": [],
|
|
@@ -631,7 +631,7 @@
|
|
|
631
631
|
"4300.js"
|
|
632
632
|
],
|
|
633
633
|
"auxiliaryFiles": [],
|
|
634
|
-
"hash": "
|
|
634
|
+
"hash": "7b1f86f0827b1db8",
|
|
635
635
|
"childrenByOrder": {}
|
|
636
636
|
},
|
|
637
637
|
{
|
|
@@ -1797,7 +1797,7 @@
|
|
|
1797
1797
|
"auxiliaryFiles": [
|
|
1798
1798
|
"8091.js.map"
|
|
1799
1799
|
],
|
|
1800
|
-
"hash": "
|
|
1800
|
+
"hash": "bb301aa5f424eb42",
|
|
1801
1801
|
"childrenByOrder": {}
|
|
1802
1802
|
},
|
|
1803
1803
|
{
|
|
@@ -1987,7 +1987,7 @@
|
|
|
1987
1987
|
"auxiliaryFiles": [
|
|
1988
1988
|
"main.js.map"
|
|
1989
1989
|
],
|
|
1990
|
-
"hash": "
|
|
1990
|
+
"hash": "b08048e79f21c17b",
|
|
1991
1991
|
"childrenByOrder": {}
|
|
1992
1992
|
},
|
|
1993
1993
|
{
|
package/dist/routes.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.2.0"},"pages":[{"component":"root","route":"form-builder","online":true,"offline":true,"order":1}],"extensions":[{"name":"system-administration-form-builder-card-link","slot":"system-admin-page-card-link-slot","component":"systemAdministrationFormBuilderCardLink","online":true,"offline":true}],"modals":[{"name":"new-form-modal","component":"newFormModal"},{"name":"new-page-modal","component":"newPageModal"},{"name":"delete-page-modal","component":"deletePageModal"},{"name":"new-section-modal","component":"newSectionModal"},{"name":"delete-section-modal","component":"deleteSectionModal"},{"name":"add-form-reference-modal","component":"addFormReferenceModal"},{"name":"question-modal","component":"questionModal"},{"name":"delete-question-modal","component":"deleteQuestionModal"},{"name":"edit-question-modal","component":"editQuestionModal"},{"name":"restore-draft-schema-modal","component":"restoreDraftSchemaModal"},{"name":"unpublish-form-modal","component":"unpublishFormModal"},{"name":"delete-form-modal","component":"deleteFormModal"},{"name":"edit-translation-modal","component":"editTranslationModal"}],"version":"3.1.1-pre.
|
|
1
|
+
{"$schema":"https://json.openmrs.org/routes.schema.json","backendDependencies":{"fhir2":">=1.2","webservices.rest":"^2.2.0"},"pages":[{"component":"root","route":"form-builder","online":true,"offline":true,"order":1}],"extensions":[{"name":"system-administration-form-builder-card-link","slot":"system-admin-page-card-link-slot","component":"systemAdministrationFormBuilderCardLink","online":true,"offline":true}],"modals":[{"name":"new-form-modal","component":"newFormModal"},{"name":"new-page-modal","component":"newPageModal"},{"name":"delete-page-modal","component":"deletePageModal"},{"name":"new-section-modal","component":"newSectionModal"},{"name":"delete-section-modal","component":"deleteSectionModal"},{"name":"add-form-reference-modal","component":"addFormReferenceModal"},{"name":"question-modal","component":"questionModal"},{"name":"delete-question-modal","component":"deleteQuestionModal"},{"name":"edit-question-modal","component":"editQuestionModal"},{"name":"restore-draft-schema-modal","component":"restoreDraftSchemaModal"},{"name":"unpublish-form-modal","component":"unpublishFormModal"},{"name":"delete-form-modal","component":"deleteFormModal"},{"name":"edit-translation-modal","component":"editTranslationModal"}],"version":"3.1.1-pre.2185"}
|
package/package.json
CHANGED
|
@@ -19,28 +19,26 @@ const TranslationBuilder: React.FC<TranslationBuilderProps> = ({ formSchema, onU
|
|
|
19
19
|
const [translations, setTranslations] = useState<Record<string, string>>({});
|
|
20
20
|
const [loading, setLoading] = useState(false);
|
|
21
21
|
const [error, setError] = useState<string | null>(null);
|
|
22
|
+
const [downloadError, setDownloadError] = useState<string | null>(null);
|
|
22
23
|
const [activeTab, setActiveTab] = useState<'all' | 'translated' | 'untranslated'>('all');
|
|
23
24
|
|
|
24
25
|
const langCode = selectedLanguageCode;
|
|
25
26
|
|
|
27
|
+
const fallbackStrings = useMemo(() => {
|
|
28
|
+
return formSchema ? extractTranslatableStrings(formSchema) : {};
|
|
29
|
+
}, [formSchema]);
|
|
30
|
+
|
|
26
31
|
useEffect(() => {
|
|
27
32
|
if (!formSchema) return;
|
|
28
33
|
const translationsMap = formSchema.translations as Record<string, Record<string, string>> | undefined;
|
|
29
|
-
|
|
30
34
|
const schemaTranslations = translationsMap?.[langCode];
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
} else {
|
|
34
|
-
const fallbackStrings = extractTranslatableStrings(formSchema);
|
|
35
|
-
setTranslations(fallbackStrings);
|
|
36
|
-
}
|
|
37
|
-
}, [formSchema, langCode]);
|
|
35
|
+
setTranslations(schemaTranslations ?? fallbackStrings);
|
|
36
|
+
}, [formSchema, langCode, fallbackStrings]);
|
|
38
37
|
|
|
39
38
|
const handleUpdateValue = useCallback(
|
|
40
39
|
(key: string, newValue: string) => {
|
|
41
40
|
const updatedTranslations = { ...translations, [key]: newValue };
|
|
42
41
|
setTranslations(updatedTranslations);
|
|
43
|
-
|
|
44
42
|
if (formSchema) {
|
|
45
43
|
const updatedSchema = { ...formSchema };
|
|
46
44
|
if (!updatedSchema.translations) {
|
|
@@ -70,25 +68,61 @@ const TranslationBuilder: React.FC<TranslationBuilderProps> = ({ formSchema, onU
|
|
|
70
68
|
[translations, handleUpdateValue],
|
|
71
69
|
);
|
|
72
70
|
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
71
|
+
const downloadableTranslationResource = useMemo(() => {
|
|
72
|
+
if (!formSchema) return null;
|
|
73
|
+
const schemaTranslations = formSchema.translations?.[langCode];
|
|
74
|
+
const translationsToExport = langCode === 'en' ? fallbackStrings : schemaTranslations;
|
|
75
|
+
|
|
76
|
+
if (!translationsToExport) return null;
|
|
77
|
+
|
|
78
|
+
return new Blob(
|
|
79
|
+
[
|
|
80
|
+
JSON.stringify(
|
|
81
|
+
{
|
|
82
|
+
uuid: formSchema.uuid || '',
|
|
83
|
+
form: formSchema.name,
|
|
84
|
+
description: `${langCode.toUpperCase()} Translations for '${formSchema.name}'`,
|
|
85
|
+
language: langCode,
|
|
86
|
+
translations: translationsToExport,
|
|
87
|
+
},
|
|
88
|
+
null,
|
|
89
|
+
2,
|
|
90
|
+
),
|
|
91
|
+
],
|
|
92
|
+
{ type: 'application/json' },
|
|
93
|
+
);
|
|
94
|
+
}, [formSchema, langCode, fallbackStrings]);
|
|
95
|
+
|
|
96
|
+
const isTranslated = (key: string, value: string | undefined | null): boolean => {
|
|
78
97
|
const fallback = fallbackStrings[key] ?? '';
|
|
79
98
|
return value != null && value.trim() !== '' && value.trim() !== fallback.trim();
|
|
80
99
|
};
|
|
81
100
|
|
|
82
|
-
const filteredTranslations
|
|
83
|
-
if (activeTab === 'translated')
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
if (activeTab === 'untranslated') {
|
|
87
|
-
return !isTranslated(key, value);
|
|
88
|
-
}
|
|
101
|
+
const filteredTranslations = Object.entries(translations).filter(([key, value]) => {
|
|
102
|
+
if (activeTab === 'translated') return isTranslated(key, value);
|
|
103
|
+
if (activeTab === 'untranslated') return !isTranslated(key, value);
|
|
89
104
|
return true;
|
|
90
105
|
});
|
|
91
106
|
|
|
107
|
+
const handleDownloadTranslation = useCallback(() => {
|
|
108
|
+
setDownloadError(null);
|
|
109
|
+
if (!downloadableTranslationResource) {
|
|
110
|
+
if (langCode !== 'en') {
|
|
111
|
+
setDownloadError(t('noTranslationForLang', 'No translations found for selected language.'));
|
|
112
|
+
}
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const url = URL.createObjectURL(downloadableTranslationResource);
|
|
117
|
+
const link = document.createElement('a');
|
|
118
|
+
link.href = url;
|
|
119
|
+
link.download = `${formSchema?.name}_translations_${langCode}.json`;
|
|
120
|
+
document.body.appendChild(link);
|
|
121
|
+
link.click();
|
|
122
|
+
document.body.removeChild(link);
|
|
123
|
+
URL.revokeObjectURL(url);
|
|
124
|
+
}, [downloadableTranslationResource, langCode, formSchema?.name, t]);
|
|
125
|
+
|
|
92
126
|
return (
|
|
93
127
|
<div className={styles.translationBuilderContainer}>
|
|
94
128
|
<div className={styles.translationBuilderHeader}>
|
|
@@ -124,7 +158,12 @@ const TranslationBuilder: React.FC<TranslationBuilderProps> = ({ formSchema, onU
|
|
|
124
158
|
}}
|
|
125
159
|
/>
|
|
126
160
|
|
|
127
|
-
<IconButton
|
|
161
|
+
<IconButton
|
|
162
|
+
kind="ghost"
|
|
163
|
+
label={t('downloadTranslation', 'Download translation')}
|
|
164
|
+
size="md"
|
|
165
|
+
onClick={handleDownloadTranslation}
|
|
166
|
+
>
|
|
128
167
|
<Download />
|
|
129
168
|
</IconButton>
|
|
130
169
|
</div>
|
|
@@ -135,42 +174,53 @@ const TranslationBuilder: React.FC<TranslationBuilderProps> = ({ formSchema, onU
|
|
|
135
174
|
) : error ? (
|
|
136
175
|
<InlineNotification kind="error" title={t('error', 'Error')} subtitle={error} lowContrast />
|
|
137
176
|
) : (
|
|
138
|
-
|
|
139
|
-
{
|
|
140
|
-
filteredTranslations.map(([key, value]) => (
|
|
141
|
-
<div key={key} className={styles.translationRow}>
|
|
142
|
-
<div className={styles.translationKey}>{key}</div>
|
|
143
|
-
<div className={styles.translatedKey}>{value}</div>
|
|
144
|
-
<div className={styles.inlineControls}>
|
|
145
|
-
<IconButton
|
|
146
|
-
kind="ghost"
|
|
147
|
-
label={t('editString', 'Edit string')}
|
|
148
|
-
onClick={() => {
|
|
149
|
-
handleEditClick(key);
|
|
150
|
-
}}
|
|
151
|
-
size="md"
|
|
152
|
-
className={styles.deleteButton}
|
|
153
|
-
>
|
|
154
|
-
<Edit />
|
|
155
|
-
</IconButton>
|
|
156
|
-
</div>
|
|
157
|
-
</div>
|
|
158
|
-
))
|
|
159
|
-
) : (
|
|
177
|
+
<>
|
|
178
|
+
{downloadError && (
|
|
160
179
|
<InlineNotification
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
: activeTab === 'untranslated'
|
|
166
|
-
? t('noUntranslatedStrings', 'All strings are translated.')
|
|
167
|
-
: t('noTranslations', 'No translatable strings found.')
|
|
168
|
-
}
|
|
169
|
-
hideCloseButton
|
|
180
|
+
className={styles.downloadError}
|
|
181
|
+
kind="error"
|
|
182
|
+
title={t('error', 'Error')}
|
|
183
|
+
subtitle={downloadError}
|
|
170
184
|
lowContrast
|
|
185
|
+
onClose={() => setDownloadError(null)}
|
|
171
186
|
/>
|
|
172
187
|
)}
|
|
173
|
-
|
|
188
|
+
|
|
189
|
+
<div className={styles.translationEditor}>
|
|
190
|
+
{filteredTranslations.length > 0 ? (
|
|
191
|
+
filteredTranslations.map(([key, value]) => (
|
|
192
|
+
<div key={key} className={styles.translationRow}>
|
|
193
|
+
<div className={styles.translationKey}>{key}</div>
|
|
194
|
+
<div className={styles.translatedKey}>{value}</div>
|
|
195
|
+
<div className={styles.inlineControls}>
|
|
196
|
+
<IconButton
|
|
197
|
+
kind="ghost"
|
|
198
|
+
label={t('editString', 'Edit string')}
|
|
199
|
+
onClick={() => handleEditClick(key)}
|
|
200
|
+
size="md"
|
|
201
|
+
className={styles.deleteButton}
|
|
202
|
+
>
|
|
203
|
+
<Edit />
|
|
204
|
+
</IconButton>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
))
|
|
208
|
+
) : (
|
|
209
|
+
<InlineNotification
|
|
210
|
+
kind="info"
|
|
211
|
+
subtitle={
|
|
212
|
+
activeTab === 'translated'
|
|
213
|
+
? t('noTranslatedStrings', 'No strings are translated yet.')
|
|
214
|
+
: activeTab === 'untranslated'
|
|
215
|
+
? t('noUntranslatedStrings', 'All strings are translated.')
|
|
216
|
+
: t('noTranslations', 'No translatable strings found.')
|
|
217
|
+
}
|
|
218
|
+
hideCloseButton
|
|
219
|
+
lowContrast
|
|
220
|
+
/>
|
|
221
|
+
)}
|
|
222
|
+
</div>
|
|
223
|
+
</>
|
|
174
224
|
)}
|
|
175
225
|
</div>
|
|
176
226
|
);
|