diff --git a/frontend/src/components/Checkbox/Checkbox.tsx b/frontend/src/components/Checkbox/Checkbox.tsx index 8b8af34858..ef260d1c71 100644 --- a/frontend/src/components/Checkbox/Checkbox.tsx +++ b/frontend/src/components/Checkbox/Checkbox.tsx @@ -11,14 +11,10 @@ import { useMultiStyleConfig, } from '@chakra-ui/react' -import { Language } from '~shared/types' - import { BxCheckAnimated } from '~/assets/icons' import { CHECKBOX_THEME_KEY } from '~/theme/components/Checkbox' import { FieldColorScheme } from '~/theme/foundations/colours' -import { OTHERS_TRANSLATED_LABEL } from '~constants/fixedTranslations' - import Input, { InputProps } from '../Input' import { CheckboxOthersContext, useCheckboxOthers } from './useCheckboxOthers' @@ -94,7 +90,7 @@ const OthersWrapper = ({ * Wrapper for the checkbox part of the Others option. */ const OthersCheckbox = forwardRef((props, ref) => { - const { t, i18n } = useTranslation() + const { t } = useTranslation() const { checkboxRef, inputRef } = useCheckboxOthers() // Passing all props for cleanliness but size and colorScheme are the most relevant const styles = useMultiStyleConfig(CHECKBOX_THEME_KEY, props) @@ -109,9 +105,6 @@ const OthersCheckbox = forwardRef((props, ref) => { props.onChange?.(e) } - const othersLabel = - OTHERS_TRANSLATED_LABEL[(i18n.language as Language) ?? Language.ENGLISH] - return ( ((props, ref) => { {...props} onChange={handleCheckboxChange} > - {othersLabel ?? t('features.adminForm.sidebar.fields.radio.others')} + {t('features.publicForm.components.fields.option.others')} ) }) diff --git a/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx b/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx index 3bde7e5277..6f895e7a7d 100644 --- a/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx +++ b/frontend/src/components/Dropdown/SingleSelect/SingleSelectProvider.tsx @@ -8,13 +8,7 @@ import { } from '@chakra-ui/react' import { useCombobox, UseComboboxProps } from 'downshift' -import { Language } from '~shared/types' - import { ThemeColorScheme } from '~theme/foundations/colours' -import { - DEFAULT_PLACEHOLDER_TRANSLATIONS, - NOTHING_FOUND_LABEL_TRANSLATIONS, -} from '~constants/fixedTranslations' import { VIRTUAL_LIST_MAX_HEIGHT } from '../constants' import { useItems } from '../hooks/useItems' @@ -57,7 +51,6 @@ export const SingleSelectProvider = ({ onChange, name, filter = defaultFilter, - nothingFoundLabel: nothingFoundLabelProp = 'No matching results', placeholder: placeholderProp, clearButtonLabel = 'Clear selection', isClearable = true, @@ -76,9 +69,7 @@ export const SingleSelectProvider = ({ }: SingleSelectProviderProps): JSX.Element => { const { items, getItemByValue } = useItems({ rawItems }) const [isFocused, setIsFocused] = useState(false) - const { t, i18n } = useTranslation() - - const selectedLanguage = i18n.language as Language + const { t } = useTranslation() const { isInvalid, isDisabled, isReadOnly, isRequired } = useFormControlProps( { @@ -93,21 +84,13 @@ export const SingleSelectProvider = ({ if (placeholderProp === null) return '' return ( placeholderProp ?? - DEFAULT_PLACEHOLDER_TRANSLATIONS[selectedLanguage] ?? - t('features.common.dropdown.placeholder') + t('features.publicForm.components.fields.dropdown.placeholder') ) - }, [placeholderProp, selectedLanguage, t]) + }, [placeholderProp, t]) - const nothingFoundLabel = useMemo(() => { - // Check if the nothingFoundLabel equals to the default label. If yes, return - // the label in the correct translation. - if ( - nothingFoundLabelProp === - NOTHING_FOUND_LABEL_TRANSLATIONS[Language.ENGLISH] - ) - return NOTHING_FOUND_LABEL_TRANSLATIONS[selectedLanguage] - return nothingFoundLabelProp - }, [nothingFoundLabelProp, selectedLanguage]) + const nothingFoundLabel = t( + 'features.publicForm.components.fields.dropdown.nothingFound', + ) const getFilteredItems = useCallback( (filterValue?: string) => diff --git a/frontend/src/components/Field/Attachment/Attachment.tsx b/frontend/src/components/Field/Attachment/Attachment.tsx index 5ccf06eda1..fdca54a483 100644 --- a/frontend/src/components/Field/Attachment/Attachment.tsx +++ b/frontend/src/components/Field/Attachment/Attachment.tsx @@ -14,11 +14,9 @@ import imageCompression from 'browser-image-compression' import omit from 'lodash/omit' import { MB } from '~shared/constants/file' -import { Language } from '~shared/types' import { ATTACHMENT_THEME_KEY } from '~theme/components/Field/Attachment' import { ThemeColorScheme } from '~theme/foundations/colours' -import { MAXIMUM_FILE_LABEL_TRANSLATIONS } from '~constants/fixedTranslations' import { downloadFile } from './utils/downloadFile' import { AttachmentStylesProvider } from './AttachmentContext' @@ -125,7 +123,7 @@ export const Attachment = forwardRef( }, ref, ) => { - const { t, i18n } = useTranslation() + const { t } = useTranslation() // Merge given props with any form control props, if they exist. const inputProps = useFormControl(props) // id to set on the rendered max size FormFieldMessage component. @@ -150,14 +148,14 @@ export const Attachment = forwardRef( case 'file-invalid-type': { const fileExt = getFileExtension(rejectedFiles[0].file.name) errorMessage = t( - `features.adminForm.sidebar.fields.imageAttachment.error.fileInvalidType`, + `features.publicForm.components.fields.attachment.error.fileInvalidType`, { fileExt }, ) break } case 'too-many-files': { errorMessage = t( - `features.adminForm.sidebar.fields.imageAttachment.error.tooManyFiles`, + `features.publicForm.components.fields.attachment.error.tooManyFiles`, ) break } @@ -180,7 +178,7 @@ export const Attachment = forwardRef( const stringOfInvalidExtensions = invalidFilesInZip.join(', ') return onError?.( t( - 'features.adminForm.sidebar.fields.imageAttachment.error.zipFileInvalidType', + 'features.publicForm.components.fields.attachment.error.zipFileInvalidType', { stringOfInvalidExtensions }, ), ) @@ -188,7 +186,7 @@ export const Attachment = forwardRef( } catch { return onError?.( t( - 'features.adminForm.sidebar.fields.imageAttachment.error.zipParsing', + 'features.publicForm.components.fields.attachment.error.zipParsing', ), ) } @@ -226,7 +224,7 @@ export const Attachment = forwardRef( return { code: 'file-too-large', message: t( - 'features.adminForm.sidebar.fields.imageAttachment.error.fileTooLarge', + 'features.publicForm.components.fields.attachment.error.fileTooLarge', { readableMaxSize }, ), } @@ -235,7 +233,7 @@ export const Attachment = forwardRef( return { code: 'file-empty', message: t( - 'features.adminForm.sidebar.fields.imageAttachment.error.zipParsing', + 'features.publicForm.components.fields.attachment.error.zipParsing', ), } } @@ -301,8 +299,6 @@ export const Attachment = forwardRef( }) }, [getInputProps, inputProps, name]) - const selectedLanguage = i18n.language as Language - return ( @@ -339,14 +335,12 @@ export const Attachment = forwardRef( textStyle="body-2" aria-hidden > - {MAXIMUM_FILE_LABEL_TRANSLATIONS[selectedLanguage] - ? `${MAXIMUM_FILE_LABEL_TRANSLATIONS[selectedLanguage]} ${readableMaxSize}` - : t( - 'features.adminForm.sidebar.fields.imageAttachment.maxFileSize', - { - readableMaxSize, - }, - )} + {t( + 'features.publicForm.components.fields.attachment.maxFileSize', + { + readableMaxSize, + }, + )} ) : null} diff --git a/frontend/src/components/Field/Attachment/AttachmentDropzone.tsx b/frontend/src/components/Field/Attachment/AttachmentDropzone.tsx index cae8781b27..f1042b2581 100644 --- a/frontend/src/components/Field/Attachment/AttachmentDropzone.tsx +++ b/frontend/src/components/Field/Attachment/AttachmentDropzone.tsx @@ -37,10 +37,10 @@ export const AttachmentDropzone = ({ {t( - 'features.adminForm.sidebar.fields.imageAttachment.fileUploaderLink', + 'features.publicForm.components.fields.attachment.fileUploaderLink', )} - {t('features.adminForm.sidebar.fields.imageAttachment.dragAndDrop')} + {t('features.publicForm.components.fields.attachment.dragAndDrop')} )} diff --git a/frontend/src/components/Field/Attachment/AttachmentFileInfo.tsx b/frontend/src/components/Field/Attachment/AttachmentFileInfo.tsx index 919023f03b..1519dbed05 100644 --- a/frontend/src/components/Field/Attachment/AttachmentFileInfo.tsx +++ b/frontend/src/components/Field/Attachment/AttachmentFileInfo.tsx @@ -57,7 +57,7 @@ export const AttachmentFileInfo = ({ variant="clear" colorScheme="danger" aria-label={t( - 'features.adminForm.sidebar.fields.imageAttachment.ariaLabelRemove', + 'features.publicForm.components.fields.attachment.ariaLabelRemove', )} icon={} onClick={handleRemoveFile} diff --git a/frontend/src/components/Radio/Radio.tsx b/frontend/src/components/Radio/Radio.tsx index d0bf979f3f..c199704ca8 100644 --- a/frontend/src/components/Radio/Radio.tsx +++ b/frontend/src/components/Radio/Radio.tsx @@ -46,13 +46,9 @@ import { } from '@chakra-ui/react' import { callAll, split } from '@chakra-ui/utils' -import { Language } from '~shared/types' - import { RADIO_THEME_KEY } from '~/theme/components/Radio' import { FieldColorScheme } from '~/theme/foundations/colours' -import { OTHERS_TRANSLATED_LABEL } from '~constants/fixedTranslations' - import Input, { InputProps } from '../Input' import { RadioGroup } from './RadioGroup' @@ -256,7 +252,7 @@ export const Radio = forwardRef( * Wrapper for the radio part of the Others option. */ const OthersRadio = forwardRef((props, ref) => { - const { t, i18n } = useTranslation() + const { t } = useTranslation() const { othersRadioRef, othersInputRef } = useRadioGroupWithOthers() const { value: valueProp } = props const styles = useMultiStyleConfig(RADIO_THEME_KEY, { @@ -273,11 +269,6 @@ const OthersRadio = forwardRef((props, ref) => { isChecked = group.value === valueProp } - const selectedLanguage = i18n.language as Language - const othersLabel = useMemo(() => { - return OTHERS_TRANSLATED_LABEL[selectedLanguage ?? Language.ENGLISH] - }, [selectedLanguage]) - useEffect(() => { if (isChecked) { othersInputRef.current?.focus() @@ -292,7 +283,7 @@ const OthersRadio = forwardRef((props, ref) => { // Required should apply to radio group rather than individual radio. isRequired={false} > - {othersLabel ?? t('features.adminForm.sidebar.fields.radio.others')} + {t('features.publicForm.components.fields.option.others')} ) }) diff --git a/frontend/src/constants/fixedTranslations.ts b/frontend/src/constants/fixedTranslations.ts deleted file mode 100644 index 822674bf3d..0000000000 --- a/frontend/src/constants/fixedTranslations.ts +++ /dev/null @@ -1,67 +0,0 @@ -import simplur from 'simplur' - -import { Language } from '~shared/types' - -export const OTHERS_TRANSLATED_LABEL: Record = { - [Language.ENGLISH]: 'Others', - [Language.CHINESE]: '其他', - [Language.MALAY]: 'Lain-lain', - [Language.TAMIL]: 'மற்றவை', -} - -export const DEFAULT_PLACEHOLDER_TRANSLATIONS: Record = { - [Language.ENGLISH]: 'Select an option', - [Language.CHINESE]: '请选择一个选项', - [Language.MALAY]: 'Pilih satu pilihan', - [Language.TAMIL]: 'ஒரு விருப்பத்தை தேர்வு செய்யவும்', -} - -export const NOTHING_FOUND_LABEL_TRANSLATIONS: Record = { - [Language.ENGLISH]: 'No matching results', - [Language.CHINESE]: '没有匹配结果', - [Language.MALAY]: 'Tiada hasil yang sepadan', - [Language.TAMIL]: 'முடிவுகள் எதுவும் பொருந்தவில்லை', -} - -export const MAXIMUM_FILE_LABEL_TRANSLATIONS: Record = { - [Language.ENGLISH]: 'Maximum file size:', - [Language.CHINESE]: '文件限制:不超过', - [Language.MALAY]: 'Saiz fail maksimum:', - [Language.TAMIL]: 'கோப்பின் அதிகபட்ச அளவு:', -} - -export const ADD_ANOTHER_ROW_LABEL_TRANSLATIONS: Record = { - [Language.ENGLISH]: 'Add another row', - [Language.CHINESE]: '添加另一行', - [Language.MALAY]: 'Tambah satu lagi baris', - [Language.TAMIL]: 'மற்றொரு வரிசையைச் சேர்க்கவும்', -} - -export function getTranslationsForTableFieldRows({ - maxRows, - currentRows, - selectedLanguage, -}: { - maxRows: number | '' - currentRows: number - selectedLanguage: Language -}) { - switch (selectedLanguage) { - case Language.CHINESE: - return maxRows - ? `${currentRows} 行,最多 ${maxRows} 行` - : `${currentRows} 行` - case Language.MALAY: - return maxRows - ? `${currentRows} daripada maksimum ${maxRows} baris` - : `${currentRows} baris` - case Language.TAMIL: - return maxRows - ? `அதிகபட்சம் ${currentRows} வரிசைகளுக்கு ${maxRows}` - : `வரிசைகளுக்கு ${currentRows}` - default: - return maxRows - ? simplur`${currentRows} out of max ${maxRows} row[|s]` - : simplur`${currentRows} row[|s]` - } -} diff --git a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox/EditCheckbox.tsx b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox/EditCheckbox.tsx index 22ba191a9b..2717cc3859 100644 --- a/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox/EditCheckbox.tsx +++ b/frontend/src/features/admin-form/create/builder-and-design/BuilderAndDesignDrawer/EditFieldDrawer/edit-fieldtype/EditCheckbox/EditCheckbox.tsx @@ -234,7 +234,7 @@ export const EditCheckbox = ({ field }: EditCheckboxProps): JSX.Element => { { = { yes: 'Ya', no: 'Tidak', }, + option: { + others: 'Lain-lain', + }, + dropdown: { + placeholder: 'Pilih satu pilihan', + nothingFound: 'Tiada hasil yang sepadan', + }, + attachment: { + maxFileSize: 'Saiz fail maksimum: {readableMaxSize}', + }, email: { validation: { domainDisallowed: diff --git a/frontend/src/i18n/locales/features/public-form/fields/ta-sg.ts b/frontend/src/i18n/locales/features/public-form/fields/ta-sg.ts index bc89956f19..61a2d36983 100644 --- a/frontend/src/i18n/locales/features/public-form/fields/ta-sg.ts +++ b/frontend/src/i18n/locales/features/public-form/fields/ta-sg.ts @@ -7,6 +7,16 @@ export const taSG: PartialDeep = { yes: 'ஆம்', no: 'இல்லை', }, + option: { + others: 'மற்றவை', + }, + dropdown: { + placeholder: 'ஒரு விருப்பத்தை தேர்வு செய்யவும்', + nothingFound: 'முடிவுகள் எதுவும் பொருந்தவில்லை', + }, + attachment: { + maxFileSize: 'கோப்பின் அதிகபட்ச அளவு: {readableMaxSize}', + }, email: { validation: { domainDisallowed: diff --git a/frontend/src/i18n/locales/features/public-form/fields/zh-sg.ts b/frontend/src/i18n/locales/features/public-form/fields/zh-sg.ts index fcda0c0eac..2817c80298 100644 --- a/frontend/src/i18n/locales/features/public-form/fields/zh-sg.ts +++ b/frontend/src/i18n/locales/features/public-form/fields/zh-sg.ts @@ -7,6 +7,16 @@ export const zhSG: PartialDeep = { yes: '是', no: '否', }, + option: { + others: '其他', + }, + dropdown: { + placeholder: '请选择一个选项', + nothingFound: '没有匹配结果', + }, + attachment: { + maxFileSize: '文件限制:不超过 {readableMaxSize}', + }, email: { validation: { domainDisallowed: '输入的电子邮箱不在允许域名之列', diff --git a/frontend/src/i18n/locales/features/public-form/ms-sg.ts b/frontend/src/i18n/locales/features/public-form/ms-sg.ts index 5e12affd2f..425c97b116 100644 --- a/frontend/src/i18n/locales/features/public-form/ms-sg.ts +++ b/frontend/src/i18n/locales/features/public-form/ms-sg.ts @@ -1,7 +1,9 @@ import { msSG as fields } from './fields' +import { msSG as table } from './table' export const msSG = { components: { fields, + table, }, } diff --git a/frontend/src/i18n/locales/features/public-form/ta-sg.ts b/frontend/src/i18n/locales/features/public-form/ta-sg.ts index 418f70de47..80127d1882 100644 --- a/frontend/src/i18n/locales/features/public-form/ta-sg.ts +++ b/frontend/src/i18n/locales/features/public-form/ta-sg.ts @@ -1,7 +1,9 @@ import { taSG as fields } from './fields' +import { taSG as table } from './table' export const taSG = { components: { fields, + table, }, } diff --git a/frontend/src/i18n/locales/features/public-form/table/index.ts b/frontend/src/i18n/locales/features/public-form/table/index.ts index b5be5d0e9d..2c965f59fb 100644 --- a/frontend/src/i18n/locales/features/public-form/table/index.ts +++ b/frontend/src/i18n/locales/features/public-form/table/index.ts @@ -7,3 +7,7 @@ export interface Table { row: string rowMax: string } + +export * from './ms-sg' +export * from './ta-sg' +export * from './zh-sg' diff --git a/frontend/src/i18n/locales/features/public-form/table/ms-sg.ts b/frontend/src/i18n/locales/features/public-form/table/ms-sg.ts new file mode 100644 index 0000000000..d7f0a35a80 --- /dev/null +++ b/frontend/src/i18n/locales/features/public-form/table/ms-sg.ts @@ -0,0 +1,7 @@ +import { Table } from '.' + +export const msSG: Partial = { + addAnotherRow: 'Tambah satu lagi baris', + row: '{count} baris', + rowMax: '{currentRows} daripada maksimum {count} baris', +} diff --git a/frontend/src/i18n/locales/features/public-form/table/ta-sg.ts b/frontend/src/i18n/locales/features/public-form/table/ta-sg.ts new file mode 100644 index 0000000000..067e12c199 --- /dev/null +++ b/frontend/src/i18n/locales/features/public-form/table/ta-sg.ts @@ -0,0 +1,7 @@ +import { Table } from '.' + +export const taSG: Partial
= { + addAnotherRow: 'மற்றொரு வரிசையைச் சேர்க்கவும்', + row: 'வரிசைகளுக்கு {count}', + rowMax: 'அதிகபட்சம் {currentRows} வரிசைகளுக்கு {count}', +} diff --git a/frontend/src/i18n/locales/features/public-form/table/zh-sg.ts b/frontend/src/i18n/locales/features/public-form/table/zh-sg.ts new file mode 100644 index 0000000000..2339f399b2 --- /dev/null +++ b/frontend/src/i18n/locales/features/public-form/table/zh-sg.ts @@ -0,0 +1,7 @@ +import { Table } from '.' + +export const zhSG: Partial
= { + addAnotherRow: '添加另一行', + row: '{count} 行', + rowMax: '{currentRows} 行,最多 {count} 行', +} diff --git a/frontend/src/i18n/locales/features/public-form/zh-sg.ts b/frontend/src/i18n/locales/features/public-form/zh-sg.ts index be9f8d233e..e640398344 100644 --- a/frontend/src/i18n/locales/features/public-form/zh-sg.ts +++ b/frontend/src/i18n/locales/features/public-form/zh-sg.ts @@ -1,7 +1,9 @@ import { zhSG as fields } from './fields' +import { zhSG as table } from './table' export const zhSG = { components: { fields, + table, }, } diff --git a/frontend/src/templates/Field/Table/AddRowFooter.tsx b/frontend/src/templates/Field/Table/AddRowFooter.tsx index 682810679d..d0546bc4e8 100644 --- a/frontend/src/templates/Field/Table/AddRowFooter.tsx +++ b/frontend/src/templates/Field/Table/AddRowFooter.tsx @@ -3,12 +3,6 @@ import { useTranslation } from 'react-i18next' import { BiPlus } from 'react-icons/bi' import { Box, Stack, Text, VisuallyHidden } from '@chakra-ui/react' -import { Language } from '~shared/types' - -import { - ADD_ANOTHER_ROW_LABEL_TRANSLATIONS, - getTranslationsForTableFieldRows, -} from '~constants/fixedTranslations' import Button from '~components/Button' interface AddRowFooterProps { @@ -24,33 +18,24 @@ export const AddRowFooter = ({ maxRows, handleAddRow: handleAddRowProp, }: AddRowFooterProps): JSX.Element => { - const { t, i18n } = useTranslation() + const { t } = useTranslation() // State to decide whether to announce row changes to screen readers const [hasAddedRows, setHasAddedRows] = useState(false) - - const selectedLanguage = i18n.language as Language - const maxRowDescription = - getTranslationsForTableFieldRows({ - maxRows, - currentRows, - selectedLanguage, - }) ?? Number.isInteger(maxRows) - ? t('features.publicForm.components.table.rowMax', { - currentRows, - count: Number(maxRows), - }) - : t('features.publicForm.components.table.row', { - count: currentRows, - }) + const maxRowDescription = Number.isInteger(maxRows) + ? t('features.publicForm.components.table.rowMax', { + currentRows, + count: Number(maxRows), + }) + : t('features.publicForm.components.table.row', { + count: currentRows, + }) const handleAddRow = useCallback(() => { handleAddRowProp() setHasAddedRows(true) }, [handleAddRowProp]) - const addRowLabel = ADD_ANOTHER_ROW_LABEL_TRANSLATIONS[selectedLanguage] - return ( - {addRowLabel ?? t('features.publicForm.components.table.addAnotherRow')} + {t('features.publicForm.components.table.addAnotherRow')} {t('features.publicForm.components.table.addAnotherRowAria')}