diff --git a/locales/rn/en.json b/locales/rn/en.json index c711f846..439b081f 100644 --- a/locales/rn/en.json +++ b/locales/rn/en.json @@ -415,7 +415,7 @@ "files": { "delete_cascade_hint": "Folders are deleted along with everything inside them. This can't be undone.", "delete_item_title": "Delete this item?", - "delete_items_title": "Delete {count} items?", + "delete_items_title": "{count, plural, one {Delete # item?} other {Delete # items?}}", "done": "Done", "folder_empty": "This folder is empty", "invalid_name": "Invalid name", @@ -424,7 +424,7 @@ "open_error": "Could not open the file", "open_with": "Open with…", "preview_too_large": "This file is too large to preview.", - "selected_count": "{count} selected", + "selected_count": "{count, plural, one {# selected} other {# selected}}", "share_add_people": "Add people", "share_empty": "Not shared with anyone yet", "share_error": "Failed to update sharing", @@ -438,7 +438,8 @@ "share_unavailable": "Sharing is not available on this device", "shared_with": "Shared with", "sharing_access": "Sharing & access", - "upload_unavailable": "The file picker is not installed in this build. Rebuild the app to enable uploads." + "upload_unavailable": "The file picker is not installed in this build. Rebuild the app to enable uploads.", + "uploading_progress": "Uploading {current}/{total} · {name}" }, "identities": { "badge": { diff --git a/src/screens/FilesScreen.tsx b/src/screens/FilesScreen.tsx index eb297636..4d83da7d 100644 --- a/src/screens/FilesScreen.tsx +++ b/src/screens/FilesScreen.tsx @@ -61,7 +61,7 @@ import { useSettingsStore, type FilesViewMode, type FilesSortKey, type FilesSortDir, } from '../stores/settings-store'; import { useAuthStore } from '../stores/auth-store'; -import { useLocaleStore } from '../stores/locale-store'; +import { useLocaleStore, type TranslateFn } from '../stores/locale-store'; import Dialog from '../components/Dialog'; import ShareSheet from '../components/files/ShareSheet'; import { FilePreviewModal, canPreviewInApp } from '../components/files/FilePreviewModal'; @@ -71,13 +71,7 @@ interface FileRow extends FileNode { displayName: string; } -type Translate = (key: string, fallback?: string) => string; - -// The locale strings use `{name}`-style placeholders; the RN `t` does no -// interpolation, so substitute here. -function fill(text: string, vars: Record): string { - return text.replace(/\{(\w+)\}/g, (_, k: string) => (k in vars ? String(vars[k]) : `{${k}}`)); -} +type Translate = TranslateFn; const IMAGE_EXTS = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp']; @@ -591,7 +585,7 @@ export default function FilesScreen() { if (maxSize > 0 && size != null && size > maxSize) { Alert.alert( t('files.upload_error', 'Failed to upload file'), - fill(t('files.file_too_large', '"{name}" exceeds the maximum file size ({max})'), { + t('files.file_too_large', '"{name}" exceeds the maximum file size ({max})', { name: asset.name, max: formatFileSize(maxSize), }), @@ -683,7 +677,7 @@ export default function FilesScreen() { - {fill(t('files.selected_count', '{count} selected'), { count: selection.size })} + {t('files.selected_count', '{count, plural, one {# selected} other {# selected}}', { count: selection.size })} - {t('files.uploading', 'Uploading...')} {uploadProgress.current}/{uploadProgress.total} · {uploadProgress.name} + {t('files.uploading_progress', 'Uploading {current}/{total} · {name}', { + current: uploadProgress.current, + total: uploadProgress.total, + name: uploadProgress.name, + })} @@ -881,7 +879,7 @@ export default function FilesScreen() { {item.isShared && item.accountName ? ( - {fill(t('files.shared_by', 'Shared by {name}'), { name: item.accountName })} + {t('files.shared_by', 'Shared by {name}', { name: item.accountName })} ) : null} {item.size != null && !isDir ? ( @@ -940,7 +938,7 @@ export default function FilesScreen() { {item.isShared && item.accountName ? ( - {fill(t('files.shared_by', 'Shared by {name}'), { name: item.accountName })} + {t('files.shared_by', 'Shared by {name}', { name: item.accountName })} ) : item.size != null && !isDir ? ( @@ -1120,7 +1118,7 @@ export default function FilesScreen() { visible={confirmDelete != null} title={ confirmDelete && confirmDelete.rows.length > 1 - ? fill(t('files.delete_items_title', 'Delete {count} items?'), { count: confirmDelete.rows.length }) + ? t('files.delete_items_title', '{count, plural, one {Delete # item?} other {Delete # items?}}', { count: confirmDelete.rows.length }) : t('files.delete_item_title', 'Delete this item?') } message={t('files.delete_cascade_hint', "Folders are deleted along with everything inside them. This can't be undone.")}