diff --git a/src/admin/AdminAppMenu.tsx b/src/admin/AdminAppMenu.tsx index 4cd251eb..81985988 100644 --- a/src/admin/AdminAppMenu.tsx +++ b/src/admin/AdminAppMenu.tsx @@ -29,6 +29,7 @@ import IconBroom from '@/components/icons/IconBroom'; import InsightsIndicatorDot from './insights/InsightsIndicatorDot'; import MoreMenuItem from '@/components/more/MoreMenuItem'; import Spinner from '@/components/Spinner'; +import { APP_TEXT } from '@/app/config'; export default function AdminAppMenu({ active, @@ -65,7 +66,7 @@ export default function AdminAppMenu({ const sectionUpload: ComponentProps[] = useMemo(() => ([{ - label: 'Upload Photos', + label: APP_TEXT.admin.uploadPhotos, icon: {photosCountNeedSync} @@ -110,7 +111,7 @@ export default function AdminAppMenu({ } if (photosCountTotal) { items.push({ - label: 'Manage Photos', + label: APP_TEXT.admin.managePhotos, ...photosCountTotal && { annotation: `${photosCountTotal}`, }, @@ -123,7 +124,7 @@ export default function AdminAppMenu({ } if (tagsCount) { items.push({ - label: 'Manage Tags', + label: APP_TEXT.admin.manageTags, annotation: `${tagsCount}`, icon: [] = useMemo(() => ([{ - label: 'Sign Out', + label: APP_TEXT.auth.signOut, icon: , action: () => signOutAction().then(clearAuthStateAndRedirectIfNecessary), }]), [clearAuthStateAndRedirectIfNecessary]); diff --git a/src/admin/AdminNav.tsx b/src/admin/AdminNav.tsx index 671b1fd6..9fbe9260 100644 --- a/src/admin/AdminNav.tsx +++ b/src/admin/AdminNav.tsx @@ -12,6 +12,7 @@ import { PATH_ADMIN_UPLOADS, } from '@/app/paths'; import AdminNavClient from './AdminNavClient'; +import { APP_TEXT } from '@/app/config'; export default async function AdminNav() { const [ @@ -41,28 +42,28 @@ export default async function AdminNav() { // Photos const items = [{ - label: 'Photos', + label: APP_TEXT.photo.photoPlural, href: PATH_ADMIN_PHOTOS, count: countPhotos, }]; // Uploads if (countUploads > 0) { items.push({ - label: 'Uploads', + label: APP_TEXT.admin.uploadPlural, href: PATH_ADMIN_UPLOADS, count: countUploads, }); } // Tags if (countTags > 0) { items.push({ - label: 'Tags', + label: APP_TEXT.category.tagPlural, href: PATH_ADMIN_TAGS, count: countTags, }); } // Recipes if (countRecipes > 0) { items.push({ - label: 'Recipes', + label: APP_TEXT.category.recipePlural, href: PATH_ADMIN_RECIPES, count: countRecipes, }); } diff --git a/src/app/Footer.tsx b/src/app/Footer.tsx index c2cc5ede..fef82514 100644 --- a/src/app/Footer.tsx +++ b/src/app/Footer.tsx @@ -60,7 +60,7 @@ export default function Footer() { : SHOW_REPO_LINK ? : - {APP_TEXT.footer.admin} + {APP_TEXT.nav.admin} }
diff --git a/src/app/ThemeSwitcher.tsx b/src/app/ThemeSwitcher.tsx index d0975cc3..8ab1d881 100644 --- a/src/app/ThemeSwitcher.tsx +++ b/src/app/ThemeSwitcher.tsx @@ -26,19 +26,19 @@ export default function ThemeSwitcher () { icon={} onClick={() => setTheme('system')} active={theme === 'system'} - tooltip={{ content: APP_TEXT.footer.system }} + tooltip={{ content: APP_TEXT.theme.system }} /> } onClick={() => setTheme('light')} active={theme === 'light'} - tooltip={{ content: APP_TEXT.footer.light }} + tooltip={{ content: APP_TEXT.theme.light }} /> } onClick={() => setTheme('dark')} active={theme === 'dark'} - tooltip={{ content: APP_TEXT.footer.dark }} + tooltip={{ content: APP_TEXT.theme.dark }} /> ); diff --git a/src/cmdk/CommandKClient.tsx b/src/cmdk/CommandKClient.tsx index 4c261ecf..a91bd02f 100644 --- a/src/cmdk/CommandKClient.tsx +++ b/src/cmdk/CommandKClient.tsx @@ -375,21 +375,21 @@ export default function CommandKClient({ , [tagsIncludingHidden, cameras, lenses, recipes, films, focalLengths]); const clientSections: CommandKSection[] = [{ - heading: 'Theme', + heading: APP_TEXT.theme.theme, accessory: , items: [{ - label: 'Use System', + label: APP_TEXT.theme.system, annotation: , action: () => setTheme('system'), }, { - label: 'Light Mode', + label: APP_TEXT.theme.light, annotation: , action: () => setTheme('light'), }, { - label: 'Dark Mode', + label: APP_TEXT.theme.dark, annotation: , action: () => setTheme('dark'), }], @@ -440,12 +440,16 @@ export default function CommandKClient({ } const pageFeed: CommandKItem = { - label: GRID_HOMEPAGE_ENABLED ? 'Feed' : 'Feed (Home)', + label: GRID_HOMEPAGE_ENABLED + ? APP_TEXT.nav.feed + : `${APP_TEXT.nav.feed} (${APP_TEXT.nav.home})`, path: PATH_FEED_INFERRED, }; const pageGrid: CommandKItem = { - label: GRID_HOMEPAGE_ENABLED ? 'Grid (Home)' : 'Grid', + label: GRID_HOMEPAGE_ENABLED + ? `${APP_TEXT.nav.grid} (${APP_TEXT.nav.home})` + : APP_TEXT.nav.grid, path: PATH_GRID_INFERRED, }; @@ -467,40 +471,40 @@ export default function CommandKClient({ if (isUserSignedIn) { adminSection.items.push({ - label: 'Upload Photos', + label: APP_TEXT.admin.uploadPhotos, annotation: , action: startUpload, }); if (uploadsCount) { adminSection.items.push({ - label: `Uploads (${uploadsCount})`, + label: `${APP_TEXT.admin.uploadPlural} (${uploadsCount})`, annotation: , path: PATH_ADMIN_UPLOADS, }); } adminSection.items.push({ - label: `Manage Photos (${photosCountTotal})`, + label: `${APP_TEXT.admin.managePhotos} (${photosCountTotal})`, annotation: , path: PATH_ADMIN_PHOTOS, }); if (tagsCount) { adminSection.items.push({ - label: `Manage Tags (${tagsCount})`, + label: `${APP_TEXT.admin.manageTags} (${tagsCount})`, annotation: , path: PATH_ADMIN_TAGS, }); } if (recipesCount) { adminSection.items.push({ - label: `Manage Recipes (${recipesCount})`, + label: `${APP_TEXT.admin.manageRecipes} (${recipesCount})`, annotation: , path: PATH_ADMIN_RECIPES, }); } adminSection.items.push({ label: selectedPhotoIds === undefined - ? 'Batch Edit Photos ...' - : 'Exit Batch Edit', + ? APP_TEXT.admin.batchEdit + : APP_TEXT.admin.batchExitEdit, annotation: , path: selectedPhotoIds === undefined ? PATH_GRID_INFERRED @@ -510,7 +514,7 @@ export default function CommandKClient({ : () => setSelectedPhotoIds?.(undefined), }, { label: - App Insights + {APP_TEXT.admin.appInsights} {insightsIndicatorStatus && } , @@ -518,7 +522,7 @@ export default function CommandKClient({ annotation: , path: PATH_ADMIN_INSIGHTS, }, { - label: 'App Config', + label: APP_TEXT.admin.appConfig, annotation: , path: PATH_ADMIN_CONFIGURATION, }); @@ -534,14 +538,14 @@ export default function CommandKClient({ }); } adminSection.items.push({ - label: 'Sign Out', + label: APP_TEXT.auth.signOut, action: () => signOutAction() .then(clearAuthStateAndRedirectIfNecessary) .then(() => setIsOpen?.(false)), }); } else { adminSection.items.push({ - label: 'Sign In', + label: APP_TEXT.auth.signIn, path: PATH_SIGN_IN, }); } diff --git a/src/components/RepoLink.tsx b/src/components/RepoLink.tsx index c0770f36..70816368 100644 --- a/src/components/RepoLink.tsx +++ b/src/components/RepoLink.tsx @@ -7,7 +7,7 @@ export default function RepoLink() { return ( - {APP_TEXT.footer.repo} + {APP_TEXT.misc.repo} verb + ? `${verb} ${index} of ${count}` + : `${index} of ${count}`, }; export default TEXT; diff --git a/src/photo/PhotoDate.tsx b/src/photo/PhotoDate.tsx index d79bf16b..62219264 100644 --- a/src/photo/PhotoDate.tsx +++ b/src/photo/PhotoDate.tsx @@ -2,6 +2,7 @@ import ResponsiveDate from '@/components/ResponsiveDate'; import { Photo } from '.'; import { useMemo } from 'react'; import { Timezone } from '@/utility/timezone'; +import { APP_TEXT } from '@/app/config'; export default function PhotoDate({ photo, @@ -33,11 +34,11 @@ export default function PhotoDate({ const getTitleLabel = () => { switch (dateType) { case 'takenAt': - return 'TAKEN'; + return APP_TEXT.photo.taken; case 'createdAt': - return 'CREATED'; + return APP_TEXT.photo.created; case 'updatedAt': - return 'UPDATED'; + return APP_TEXT.photo.updated; } }; @@ -45,7 +46,7 @@ export default function PhotoDate({ diff --git a/src/photo/PhotoHeader.tsx b/src/photo/PhotoHeader.tsx index b2215fca..f3199671 100644 --- a/src/photo/PhotoHeader.tsx +++ b/src/photo/PhotoHeader.tsx @@ -23,7 +23,7 @@ export default function PhotoHeader({ photos, selectedPhoto, entity, - entityVerb = APP_TEXT.core.photo.toLocaleUpperCase(), + entityVerb = APP_TEXT.photo.photo.toLocaleUpperCase(), entityDescription, indexNumber, count, @@ -51,9 +51,8 @@ export default function PhotoHeader({ ? photos.findIndex(photo => photo.id === selectedPhoto.id) : undefined; - const paginationLabel = - (indexNumber || (selectedPhotoIndex ?? 0 + 1)) + ' of ' + - (count ?? photos.length); + const paginationIndex = indexNumber || (selectedPhotoIndex ?? 0 + 1); + const paginationCount = count ?? photos.length; const headerType = selectedPhotoIndex === undefined ? 'photo-set' @@ -155,8 +154,13 @@ export default function PhotoHeader({ dim: true, }} />} - : - {entityVerb} {paginationLabel} + : + {APP_TEXT.paginate( + paginationIndex, + paginationCount, + entityVerb)} } }
diff --git a/src/photo/index.ts b/src/photo/index.ts index e822feab..c12b4a76 100644 --- a/src/photo/index.ts +++ b/src/photo/index.ts @@ -2,6 +2,7 @@ import { formatFocalLength } from '@/focal'; import { getNextImageUrlForRequest } from '@/platforms/next-image'; import { photoHasFilmData } from '@/film'; import { + APP_TEXT, HIGH_DENSITY_GRID, IS_PREVIEW, SHOW_EXIF_DATA, @@ -17,7 +18,7 @@ import { formatExposureCompensation, formatExposureTime, } from '@/utility/exif-format'; -import { parameterize } from '@/utility/string'; +import { capitalize, parameterize } from '@/utility/string'; import camelcaseKeys from 'camelcase-keys'; import { isBefore } from 'date-fns'; import type { Metadata } from 'next'; @@ -231,10 +232,14 @@ export const titleForPhoto = ( export const altTextForPhoto = (photo: Photo) => photo.semanticDescription || titleForPhoto(photo); -export const photoLabelForCount = (count: number, capitalize = true) => - capitalize - ? count === 1 ? 'Photo' : 'Photos' - : count === 1 ? 'photo' : 'photos'; +export const photoLabelForCount = (count: number, _capitalize = true) => { + const label = count === 1 + ? APP_TEXT.photo.photo + : APP_TEXT.photo.photoPlural; + return _capitalize + ? capitalize(label) + : label; +}; export const photoQuantityText = ( count: number, diff --git a/src/tag/TagHeader.tsx b/src/tag/TagHeader.tsx index e1e91dfb..635ac246 100644 --- a/src/tag/TagHeader.tsx +++ b/src/tag/TagHeader.tsx @@ -3,7 +3,7 @@ import PhotoTag from './PhotoTag'; import { descriptionForTaggedPhotos, isTagFavs } from '.'; import PhotoHeader from '@/photo/PhotoHeader'; import FavsTag from './FavsTag'; -import { AI_TEXT_GENERATION_ENABLED } from '@/app/config'; +import { AI_TEXT_GENERATION_ENABLED, APP_TEXT } from '@/app/config'; export default function TagHeader({ tag, @@ -26,7 +26,7 @@ export default function TagHeader({ entity={isTagFavs(tag) ? : } - entityVerb="Tagged" + entityVerb={APP_TEXT.category.tagged} entityDescription={descriptionForTaggedPhotos(photos, undefined, count)} photos={photos} selectedPhoto={selectedPhoto}