diff --git a/frontend/src/components/Calendar/CalendarBase/CalendarTodayButton.tsx b/frontend/src/components/Calendar/CalendarBase/CalendarTodayButton.tsx index 2e25ac4a4e..17ec57815b 100644 --- a/frontend/src/components/Calendar/CalendarBase/CalendarTodayButton.tsx +++ b/frontend/src/components/Calendar/CalendarBase/CalendarTodayButton.tsx @@ -1,3 +1,4 @@ +import { useTranslation } from 'react-i18next' import { Box } from '@chakra-ui/react' import Button from '~components/Button' @@ -8,16 +9,20 @@ import { useCalendarStyles } from './CalendarStyleProvider' export const CalendarTodayButton = (): JSX.Element => { const styles = useCalendarStyles() const { handleTodayClick, colorScheme } = useCalendar() + const { t } = useTranslation('translation', { + keyPrefix: 'features.publicForm.components.fields.calendar', + }) + return ( ) diff --git a/frontend/src/components/DatePicker/DatePickerContext.tsx b/frontend/src/components/DatePicker/DatePickerContext.tsx index 03ccd5165f..4652aa1736 100644 --- a/frontend/src/components/DatePicker/DatePickerContext.tsx +++ b/frontend/src/components/DatePicker/DatePickerContext.tsx @@ -10,6 +10,7 @@ import React, { useMemo, useRef, } from 'react' +import { useTranslation } from 'react-i18next' import { CSSObject, FormControlProps, @@ -101,6 +102,9 @@ const useProvideDatePicker = ({ const inputRef = useRef(null) const isMobile = useIsMobile() + const { t } = useTranslation('translation', { + keyPrefix: 'features.publicForm.components.fields.datePicker', + }) const disclosureProps = useDisclosure({ onClose: () => { @@ -161,16 +165,18 @@ const useProvideDatePicker = ({ ) const calendarButtonAria = useMemo(() => { - let ariaLabel = 'Select from date picker. ' + let ariaLabel = t('selectFromDatePicker') if (internalValue) { if (isValid(internalValue)) { - ariaLabel += `Selected date is ${internalValue.toLocaleDateString()}.` + ariaLabel += t('selectedDateIs', { + date: internalValue.toLocaleDateString(), + }) } else { - ariaLabel += 'The current selected date is invalid.' + ariaLabel += t('invalidDate') } } return ariaLabel - }, [internalValue]) + }, [internalValue, t]) const handleDateChange = useCallback( (date: Date | null) => { diff --git a/frontend/src/components/Dropdown/MultiSelect/MultiSelectProvider.tsx b/frontend/src/components/Dropdown/MultiSelect/MultiSelectProvider.tsx index fc8473ad51..36f59994dd 100644 --- a/frontend/src/components/Dropdown/MultiSelect/MultiSelectProvider.tsx +++ b/frontend/src/components/Dropdown/MultiSelect/MultiSelectProvider.tsx @@ -1,4 +1,5 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react' +import { useTranslation } from 'react-i18next' import { VirtuosoHandle } from 'react-virtuoso' import { FormControlOptions, @@ -73,9 +74,9 @@ export const MultiSelectProvider = ({ onBlur, name, filter = defaultFilter, - nothingFoundLabel = 'No matching results', + nothingFoundLabel, placeholder: placeholderProp, - clearButtonLabel = 'Clear selection', + clearButtonLabel, isSearchable = true, defaultIsOpen, isInvalid: isInvalidProp, @@ -92,6 +93,7 @@ export const MultiSelectProvider = ({ }: MultiSelectProviderProps): JSX.Element => { const { items, getItemByValue } = useItems({ rawItems }) const [isFocused, setIsFocused] = useState(false) + const { t } = useTranslation() // Inject for components to manipulate const inputRef = useRef(null) @@ -171,8 +173,19 @@ export const MultiSelectProvider = ({ const dynamicPlaceholder = useMemo(() => { if (placeholderProp === null || selectedItems.length > 0) return '' - return placeholderProp ?? 'Select options' - }, [placeholderProp, selectedItems.length]) + return ( + placeholderProp ?? + t('features.publicForm.components.fields.dropdown.selectOptions') + ) + }, [placeholderProp, selectedItems.length, t]) + + const nothingFoundLabelTranslated = + nothingFoundLabel ?? + t('features.publicForm.components.fields.dropdown.nothingFound') + + const clearButtonLabelTranslated = + clearButtonLabel ?? + t('features.publicForm.components.fields.dropdown.clearSelection') const { toggleMenu, @@ -313,11 +326,11 @@ export const MultiSelectProvider = ({ selectItem, highlightedIndex, items: filteredItems, - nothingFoundLabel, + nothingFoundLabel: nothingFoundLabelTranslated, inputValue, isSearchable, name, - clearButtonLabel, + clearButtonLabel: clearButtonLabelTranslated, placeholder: dynamicPlaceholder, styles, isFocused, diff --git a/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx b/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx index 5746e64cba..3404f077d9 100644 --- a/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx +++ b/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx @@ -53,7 +53,7 @@ export const SingleSelectProvider = ({ name, filter = defaultFilter, placeholder: placeholderProp, - clearButtonLabel = 'Clear selection', + clearButtonLabel, isClearable = true, isSearchable = true, initialIsOpen, @@ -94,6 +94,10 @@ export const SingleSelectProvider = ({ 'features.publicForm.components.fields.dropdown.nothingFound', ) + const clearButtonLabelTranslated = + clearButtonLabel ?? + t('features.publicForm.components.fields.dropdown.clearSelection') + const getFilteredItems = useCallback( (filterValue?: string) => filterValue ? filter(items, filterValue) : items, @@ -274,7 +278,7 @@ export const SingleSelectProvider = ({ isReadOnly, isRequired, name, - clearButtonLabel, + clearButtonLabel: clearButtonLabelTranslated, placeholder, styles, isFocused, diff --git a/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx b/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx index 755b65c081..d37057d6cf 100644 --- a/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx +++ b/frontend/src/features/admin-form/common/components/PreviewFormBanner/PreviewFormBanner.tsx @@ -57,7 +57,10 @@ const textProps: TextProps = { export const PreviewFormBanner = ({ isTemplate, }: PreviewFormBannerProps): JSX.Element => { - const { t } = useTranslation() + const { t } = useTranslation('translation', { + keyPrefix: 'features.adminForm.previewFormBanner', + }) + const { t: tCommon } = useTranslation() const { formId, isPaymentEnabled } = usePublicFormContext() const { data: { secretEnv } = {} } = useEnv() const { @@ -99,7 +102,7 @@ export const PreviewFormBanner = ({ mr={{ base: '0.5rem', md: '1rem' }} /> - {isTemplate ? 'Template Preview' : 'Form Preview'} + {isTemplate ? t('templatePreview') : t('formPreview')} {isTemplate ? ( @@ -111,35 +114,35 @@ export const PreviewFormBanner = ({ > - Back to FormSG + {t('backToFormSG')} } /> ) : ( )} @@ -165,7 +168,7 @@ export const PreviewFormBanner = ({ isFullWidth={true} {...mobileDrawerButtonProps} > - Use this template + {t('useTemplate')} @@ -184,27 +187,20 @@ export const PreviewFormBanner = ({ {secretEnv === 'production' ? ( - To test your payment form, replicate this form on our{' '} + {t('paymentWarning.production.prefix')} - testing platform. + {t('paymentWarning.production.linkText')} ) : ( - - You will not be able to make a test payment, or view submitted - answers or attachments in Form Preview mode. Open your form to - make a test payment or form submission. - + {t('paymentWarning.nonProduction')} )} )} {!isPaymentEnabled && ( {!(secretEnv === 'production') && ( - - You will not be able to view submitted answers or attachments in - Form Preview mode. Open your form to test a form submission. - + {t('previewWarning.withoutPayment')} )} )} diff --git a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderAcceptDeny.tsx b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderAcceptDeny.tsx index fde66a59d1..2de2a021c9 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderAcceptDeny.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderAcceptDeny.tsx @@ -1,3 +1,4 @@ +import { useTranslation } from 'react-i18next' import { Flex, Portal, Text } from '@chakra-ui/react' import { NextAndBackButtonGroup } from '~components/Button' @@ -12,20 +13,22 @@ const MagicFormBuilderAcceptDeny = ({ onAccept: () => void onDeny: () => void }) => { + const { t } = useTranslation('translation', { + keyPrefix: 'features.adminForm.magicFormBuilder.acceptDeny', + }) + return isOpen ? ( - - The created fields have been saved. -
- Keep them? + + {t('message')}
diff --git a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderButton.tsx b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderButton.tsx index e5ac5a0f6a..3efb43a0b6 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderButton.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderButton.tsx @@ -1,3 +1,4 @@ +import { useTranslation } from 'react-i18next' import { BiSolidMagicWand } from 'react-icons/bi' import Button from '~components/Button' @@ -7,6 +8,10 @@ const MagicFormBuilderButton = ({ }: { onClick: () => void }): JSX.Element => { + const { t } = useTranslation('translation', { + keyPrefix: 'features.adminForm.magicFormBuilder.button', + }) + return ( ) } diff --git a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderPromptModal.tsx b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderPromptModal.tsx index db3df4aaee..84b774b643 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderPromptModal.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/MagicFormBuilder/components/MagicFormBuilderPromptModal.tsx @@ -9,6 +9,7 @@ import { UseFormSetError, UseFormSetValue, } from 'react-hook-form' +import { useTranslation } from 'react-i18next' import { BiSolidMagicWand } from 'react-icons/bi' import { Box, @@ -75,9 +76,13 @@ const PromptSelectorBar = ({ }[] onClick: (prompt: string) => void }) => { + const { t } = useTranslation('translation', { + keyPrefix: 'features.adminForm.magicFormBuilder.promptModal.textTab', + }) + return ( - Need inspiration? Try one of these: + {t('inspirationLabel')} errors: FieldErrors }) => { + const { t } = useTranslation('translation', { + keyPrefix: 'features.adminForm.magicFormBuilder.promptModal.textTab', + }) + return ( <> - - I want to create a form that collects... - + {t('promptLabel')}