Finalize first i18n implementation

This commit is contained in:
Sam Becker 2025-05-10 16:31:57 -05:00
parent 927b4b85b5
commit cfcff69b95
17 changed files with 126 additions and 47 deletions

View File

@ -26,6 +26,7 @@ import IconFavs from '@/components/icons/IconFavs';
import IconEdit from '@/components/icons/IconEdit'; import IconEdit from '@/components/icons/IconEdit';
import { photoNeedsToBeSynced } from '@/photo/sync'; import { photoNeedsToBeSynced } from '@/photo/sync';
import { KEY_COMMANDS } from '@/photo/key-commands'; import { KEY_COMMANDS } from '@/photo/key-commands';
import { APP_TEXT } from '@/app/config';
export default function AdminPhotoMenu({ export default function AdminPhotoMenu({
photo, photo,
@ -48,7 +49,7 @@ export default function AdminPhotoMenu({
const sectionMain = useMemo(() => { const sectionMain = useMemo(() => {
const items: ComponentProps<typeof MoreMenuItem>[] = [{ const items: ComponentProps<typeof MoreMenuItem>[] = [{
label: 'Edit', label: APP_TEXT.admin.edit,
icon: <IconEdit icon: <IconEdit
size={15} size={15}
className="translate-x-[0.5px]" className="translate-x-[0.5px]"
@ -58,7 +59,7 @@ export default function AdminPhotoMenu({
}]; }];
if (includeFavorite) { if (includeFavorite) {
items.push({ items.push({
label: isFav ? 'Unfavorite' : 'Favorite', label: isFav ? APP_TEXT.admin.unfavorite : APP_TEXT.admin.favorite,
icon: <IconFavs icon: <IconFavs
size={14} size={14}
className="translate-x-[-1px] translate-y-[0.5px]" className="translate-x-[-1px] translate-y-[0.5px]"
@ -76,7 +77,7 @@ export default function AdminPhotoMenu({
}); });
} }
items.push({ items.push({
label: 'Download', label: APP_TEXT.admin.download,
icon: <MdOutlineFileDownload icon: <MdOutlineFileDownload
size={17} size={17}
className="translate-x-[-1px]" className="translate-x-[-1px]"
@ -86,9 +87,9 @@ export default function AdminPhotoMenu({
...showKeyCommands && { keyCommand: KEY_COMMANDS.download }, ...showKeyCommands && { keyCommand: KEY_COMMANDS.download },
}); });
items.push({ items.push({
label: 'Sync', label: APP_TEXT.admin.sync,
labelComplex: <span className="inline-flex items-center gap-2"> labelComplex: <span className="inline-flex items-center gap-2">
<span>Sync</span> <span>{APP_TEXT.admin.sync}</span>
{photoNeedsToBeSynced(photo) && {photoNeedsToBeSynced(photo) &&
<InsightsIndicatorDot <InsightsIndicatorDot
colorOverride="blue" colorOverride="blue"
@ -115,7 +116,7 @@ export default function AdminPhotoMenu({
]); ]);
const sectionDelete: ComponentProps<typeof MoreMenuItem>[] = useMemo(() => [{ const sectionDelete: ComponentProps<typeof MoreMenuItem>[] = useMemo(() => [{
label: 'Delete', label: APP_TEXT.admin.delete,
icon: <BiTrash icon: <BiTrash
size={15} size={15}
className="translate-x-[-1px]" className="translate-x-[-1px]"

View File

@ -9,6 +9,7 @@ import {
absolutePathForCamera, absolutePathForCamera,
absolutePathForCameraImage, absolutePathForCameraImage,
} from '@/app/paths'; } from '@/app/paths';
import { APP_TEXT } from '@/app/config';
// Meta functions moved to separate file to avoid // Meta functions moved to separate file to avoid
// dependencies (camelcase-keys) found in photo/index.ts // dependencies (camelcase-keys) found in photo/index.ts
@ -19,8 +20,9 @@ export const titleForCamera = (
photos: Photo[], photos: Photo[],
explicitCount?: number, explicitCount?: number,
) => [ ) => [
'Shot on', APP_TEXT.category.cameraShare(
formatCameraText(cameraFromPhoto(photos[0], camera)), formatCameraText(cameraFromPhoto(photos[0], camera)),
),
photoQuantityText(explicitCount ?? photos.length), photoQuantityText(explicitCount ?? photos.length),
].join(' '); ].join(' ');
@ -28,10 +30,9 @@ export const shareTextForCamera = (
camera: Camera, camera: Camera,
photos: Photo[], photos: Photo[],
) => ) =>
[ APP_TEXT.category.cameraShare(
'Photos shot on',
formatCameraText(cameraFromPhoto(photos[0], camera)), formatCameraText(cameraFromPhoto(photos[0], camera)),
].join(' '); );
export const descriptionForCameraPhotos = ( export const descriptionForCameraPhotos = (
photos: Photo[], photos: Photo[],

View File

@ -3,6 +3,7 @@ import LoaderButton from './primitives/LoaderButton';
import clsx from 'clsx/lite'; import clsx from 'clsx/lite';
import { toastSuccess } from '@/toast'; import { toastSuccess } from '@/toast';
import { ComponentProps } from 'react'; import { ComponentProps } from 'react';
import { APP_TEXT } from '@/app/config';
export default function CopyButton({ export default function CopyButton({
label, label,
@ -29,7 +30,7 @@ export default function CopyButton({
onClick={text onClick={text
? () => { ? () => {
navigator.clipboard.writeText(text); navigator.clipboard.writeText(text);
toastSuccess(`${label} copied to clipboard`); toastSuccess(APP_TEXT.misc.copyPhrase(label));
} }
: undefined} : undefined}
styleAs="link" styleAs="link"

View File

@ -9,6 +9,7 @@ import { FiUploadCloud } from 'react-icons/fi';
import { MAX_IMAGE_SIZE } from '@/platforms/next-image'; import { MAX_IMAGE_SIZE } from '@/platforms/next-image';
import ProgressButton from './primitives/ProgressButton'; import ProgressButton from './primitives/ProgressButton';
import { useAppState } from '@/state/AppState'; import { useAppState } from '@/state/AppState';
import { APP_TEXT } from '@/app/config';
export default function ImageInput({ export default function ImageInput({
ref: inputRefExternal, ref: inputRefExternal,
@ -84,9 +85,13 @@ export default function ImageInput({
> >
{isUploading {isUploading
? filesLength > 1 ? filesLength > 1
? `Uploading ${fileUploadIndex + 1} of ${filesLength}` ? APP_TEXT.utility.paginate(
: 'Uploading' fileUploadIndex + 1,
: 'Upload Photos'} filesLength,
APP_TEXT.admin.uploading,
)
: APP_TEXT.admin.uploading
: APP_TEXT.admin.uploadPhotos}
</ProgressButton>} </ProgressButton>}
<input <input
ref={inputRef} ref={inputRef}

View File

@ -19,6 +19,7 @@ import {
} from '@/utility/string'; } from '@/utility/string';
import { AnnotatedTag } from '@/photo/form'; import { AnnotatedTag } from '@/photo/form';
import PhotoFilmIcon from './PhotoFilmIcon'; import PhotoFilmIcon from './PhotoFilmIcon';
import { APP_TEXT } from '@/app/config';
export type FilmWithCount = { export type FilmWithCount = {
film: string film: string
@ -67,7 +68,7 @@ export const titleForFilm = (
export const shareTextForFilm = ( export const shareTextForFilm = (
film: string, film: string,
) => ) =>
`Photos shot on ${labelForFilm(film).large}`; APP_TEXT.category.filmShare(labelForFilm(film).large);
export const descriptionForFilmPhotos = ( export const descriptionForFilmPhotos = (
photos: Photo[], photos: Photo[],

View File

@ -8,6 +8,7 @@ import {
absolutePathForFocalLength, absolutePathForFocalLength,
absolutePathForFocalLengthImage, absolutePathForFocalLengthImage,
} from '@/app/paths'; } from '@/app/paths';
import { APP_TEXT } from '@/app/config';
export type FocalLengths = { export type FocalLengths = {
focal: number focal: number
@ -31,12 +32,12 @@ export const titleForFocalLength = (
photos: Photo[], photos: Photo[],
explicitCount?: number, explicitCount?: number,
) => [ ) => [
`${formatFocalLength(focal)} Focal Length`, APP_TEXT.category.focalLengthTitle(formatFocalLengthSafe(focal)),
photoQuantityText(explicitCount ?? photos.length), photoQuantityText(explicitCount ?? photos.length),
].join(' '); ].join(' ');
export const shareTextFocalLength = (focal: number) => export const shareTextFocalLength = (focal: number) =>
`Photos shot at ${formatFocalLength(focal)}`; APP_TEXT.category.focalLengthShare(formatFocalLengthSafe(focal));
export const descriptionForFocalLengthPhotos = ( export const descriptionForFocalLengthPhotos = (
photos: Photo[], photos: Photo[],

View File

@ -1,4 +1,5 @@
import { I18NDeepPartial } from '..'; import { I18NDeepPartial } from '..';
import { ptBR } from 'date-fns/locale';
const TEXT: I18NDeepPartial = { const TEXT: I18NDeepPartial = {
photo: { photo: {
@ -7,21 +8,30 @@ const TEXT: I18NDeepPartial = {
taken: 'Capturado', taken: 'Capturado',
created: 'Criado', created: 'Criado',
updated: 'Atualizado', updated: 'Atualizado',
copied: 'Link para foto copiado',
}, },
category: { category: {
camera: 'Câmera', camera: 'Câmera',
cameraPlural: 'Câmeras', cameraPlural: 'Câmeras',
cameraTitle: (camera: string) => `Tirado com ${camera}`,
cameraShare: (camera: string) => `Fotos tiradas com ${camera}`,
lens: 'Lente', lens: 'Lente',
lensPlural: 'Lentes', lensPlural: 'Lentes',
tag: 'Tag', tag: 'Tag',
tagPlural: 'Tags', tagPlural: 'Tags',
tagged: 'Marcado', taggedPhotos: 'Fotos Marcadas',
taggedPhrase: (tag: string) => `Fotos marcadas com '${tag}'`,
taggedFavs: 'Fotos Favoritas',
recipe: 'Receita', recipe: 'Receita',
recipePlural: 'Receitas', recipePlural: 'Receitas',
recipeShare: (recipe: string) => `Fotos da receita ${recipe}`,
film: 'Filme', film: 'Filme',
filmPlural: 'Filmes', filmPlural: 'Filmes',
filmShare: (film: string) => `Fotos tiradas com ${film}`,
focalLength: 'Distância Focal', focalLength: 'Distância Focal',
focalLengthPlural: 'Distâncias Focais', focalLengthPlural: 'Distâncias Focais',
focalLengthTitle: (focal: string) => `Distância Focal ${focal}`,
focalLengthShare: (focal: string) => `Fotos tiradas em ${focal}`,
}, },
nav: { nav: {
home: 'Início', home: 'Início',
@ -62,6 +72,7 @@ const TEXT: I18NDeepPartial = {
uploadPhotos: 'Enviar Fotos', uploadPhotos: 'Enviar Fotos',
upload: 'Enviar', upload: 'Enviar',
uploadPlural: 'Envios', uploadPlural: 'Envios',
uploading: 'Enviando',
updates: 'Atualizações', updates: 'Atualizações',
managePhotos: 'Gerenciar Fotos', managePhotos: 'Gerenciar Fotos',
manageCameras: 'Gerenciar Câmeras', manageCameras: 'Gerenciar Câmeras',
@ -73,10 +84,29 @@ const TEXT: I18NDeepPartial = {
batchExitEdit: 'Sair da Edição em Lote', batchExitEdit: 'Sair da Edição em Lote',
appInsights: 'Insights do App', appInsights: 'Insights do App',
appConfig: 'Configuração do App', appConfig: 'Configuração do App',
edit: 'Editar',
favorite: 'Favoritar',
unfavorite: 'Remover dos Favoritos',
download: 'Baixar',
sync: 'Sincronizar',
delete: 'Excluir',
deleteConfirm: (photoTitle: string) =>
`Tem certeza que deseja excluir "${photoTitle}"?`,
}, },
misc: { misc: {
repo: 'Feito com', repo: 'Feito com',
copyPhrase: (label: string) => `${label} copiado`,
}, },
utility: {
paginate: (
index: number,
count: number,
action?: string,
) => action
? `${action} ${index} de ${count}`
: `${index} de ${count}`,
},
dateLocale: ptBR,
}; };
export default TEXT; export default TEXT;

View File

@ -1,3 +1,5 @@
import { enUS } from 'date-fns/locale';
const TEXT = { const TEXT = {
photo: { photo: {
photo: 'Photo', photo: 'Photo',
@ -5,21 +7,30 @@ const TEXT = {
taken: 'Taken', taken: 'Taken',
created: 'Created', created: 'Created',
updated: 'Updated', updated: 'Updated',
copied: 'Link to photo copied',
}, },
category: { category: {
camera: 'Camera', camera: 'Camera',
cameraPlural: 'Cameras', cameraPlural: 'Cameras',
cameraTitle: (camera: string) => `Shot on ${camera}`,
cameraShare: (camera: string) => `Photos shot on ${camera}`,
lens: 'Lens', lens: 'Lens',
lensPlural: 'Lenses', lensPlural: 'Lenses',
tag: 'Tag', tag: 'Tag',
tagPlural: 'Tags', tagPlural: 'Tags',
tagged: 'Tagged Photos', taggedPhotos: 'Tagged Photos',
taggedPhrase: (tag: string) => `Photos tagged '${tag}'`,
taggedFavs: 'Favorite Photos',
recipe: 'Recipe', recipe: 'Recipe',
recipePlural: 'Recipes', recipePlural: 'Recipes',
recipeShare: (recipe: string) => `${recipe} recipe photos`,
film: 'Film', film: 'Film',
filmPlural: 'Films', filmPlural: 'Films',
filmShare: (film: string) => `Photos shot on ${film}`,
focalLength: 'Focal Length', focalLength: 'Focal Length',
focalLengthPlural: 'Focal Lengths', focalLengthPlural: 'Focal Lengths',
focalLengthTitle: (focal: string) => `Focal Length ${focal}`,
focalLengthShare: (focal: string) => `Photos shot at ${focal}`,
}, },
nav: { nav: {
home: 'Home', home: 'Home',
@ -60,6 +71,7 @@ const TEXT = {
uploadPhotos: 'Upload Photos', uploadPhotos: 'Upload Photos',
upload: 'Upload', upload: 'Upload',
uploadPlural: 'Uploads', uploadPlural: 'Uploads',
uploading: 'Uploading',
updates: 'Updates', updates: 'Updates',
managePhotos: 'Manage Photos', managePhotos: 'Manage Photos',
manageCameras: 'Manage Cameras', manageCameras: 'Manage Cameras',
@ -71,17 +83,29 @@ const TEXT = {
batchExitEdit: 'Exit Batch Edit', batchExitEdit: 'Exit Batch Edit',
appInsights: 'App Insights', appInsights: 'App Insights',
appConfig: 'App Configuration', appConfig: 'App Configuration',
edit: 'Edit',
favorite: 'Favorite',
unfavorite: 'Unfavorite',
download: 'Download',
sync: 'Sync',
delete: 'Delete',
deleteConfirm: (photoTitle: string) =>
`Are you sure you want to delete "${photoTitle}?"`,
}, },
misc: { misc: {
repo: 'Made with', repo: 'Made with',
copyPhrase: (label: string) => `${label} copied`,
}, },
paginate: ( utility: {
index: number, paginate: (
count: number, index: number,
verb?: string, count: number,
) => verb action?: string,
? `${verb} ${index} of ${count}` ) => action
: `${index} of ${count}`, ? `${action} ${index} of ${count}`
: `${index} of ${count}`,
},
dateLocale: enUS,
}; };
export default TEXT; export default TEXT;

View File

@ -9,6 +9,7 @@ import {
absolutePathForLens, absolutePathForLens,
absolutePathForLensImage, absolutePathForLensImage,
} from '@/app/paths'; } from '@/app/paths';
import { APP_TEXT } from '@/app/config';
// Meta functions moved to separate file to avoid // Meta functions moved to separate file to avoid
// dependencies (camelcase-keys) found in photo/index.ts // dependencies (camelcase-keys) found in photo/index.ts
@ -19,7 +20,7 @@ export const titleForLens = (
photos: Photo[], photos: Photo[],
explicitCount?: number, explicitCount?: number,
) => [ ) => [
'Lens:', `${APP_TEXT.category.lens}:`,
formatLensText(lensFromPhoto(photos[0], lens)), formatLensText(lensFromPhoto(photos[0], lens)),
photoQuantityText(explicitCount ?? photos.length), photoQuantityText(explicitCount ?? photos.length),
].join(' '); ].join(' ');
@ -29,7 +30,7 @@ export const shareTextForLens = (
photos: Photo[], photos: Photo[],
) => ) =>
[ [
'Lens:', `${APP_TEXT.category.lens}:`,
formatLensText(lensFromPhoto(photos[0], lens)), formatLensText(lensFromPhoto(photos[0], lens)),
].join(' '); ].join(' ');

View File

@ -155,9 +155,13 @@ export default function PhotoHeader({
}} />} }} />}
</> </>
: <ResponsiveText : <ResponsiveText
shortText={APP_TEXT.paginate(paginationIndex, paginationCount)} shortText={APP_TEXT.utility.paginate(
paginationIndex,
paginationCount,
entityVerb,
)}
> >
{APP_TEXT.paginate( {APP_TEXT.utility.paginate(
paginationIndex, paginationIndex,
paginationCount, paginationCount,
entityVerb)} entityVerb)}

View File

@ -172,7 +172,7 @@ export const photoStatsAsString = (photo: Photo) => [
].join(' '); ].join(' ');
export const descriptionForPhoto = (photo: Photo) => export const descriptionForPhoto = (photo: Photo) =>
photo.takenAtNaiveFormatted?.toUpperCase(); formatDate({ date: photo.takenAt }).toLocaleUpperCase();
export const getPreviousPhoto = (photo: Photo, photos: Photo[]) => { export const getPreviousPhoto = (photo: Photo, photos: Photo[]) => {
const index = photos.findIndex(p => p.id === photo.id); const index = photos.findIndex(p => p.id === photo.id);
@ -251,7 +251,7 @@ export const photoQuantityText = (
: `${count} ${photoLabelForCount(count, capitalize)}`; : `${count} ${photoLabelForCount(count, capitalize)}`;
export const deleteConfirmationTextForPhoto = (photo: Photo) => export const deleteConfirmationTextForPhoto = (photo: Photo) =>
`Are you sure you want to delete "${titleForPhoto(photo)}?"`; APP_TEXT.admin.deleteConfirm(titleForPhoto(photo));
export type PhotoDateRange = { start: string, end: string }; export type PhotoDateRange = { start: string, end: string };
@ -265,9 +265,10 @@ export const descriptionForPhotoSet = (
dateBased dateBased
? dateRangeForPhotos(photos, explicitDateRange).description.toUpperCase() ? dateRangeForPhotos(photos, explicitDateRange).description.toUpperCase()
: [ : [
explicitCount ?? photos.length, explicitCount ?? photos.length, (
descriptor, descriptor ||
photoLabelForCount(explicitCount ?? photos.length, false), photoLabelForCount(explicitCount ?? photos.length, false)
),
].join(' '); ].join(' ');
const sortPhotosByDateNonDestructively = ( const sortPhotosByDateNonDestructively = (

View File

@ -19,6 +19,7 @@ import { TbChecklist } from 'react-icons/tb';
import CopyButton from '@/components/CopyButton'; import CopyButton from '@/components/CopyButton';
import { labelForFilm } from '@/film'; import { labelForFilm } from '@/film';
import PhotoRecipe from './PhotoRecipe'; import PhotoRecipe from './PhotoRecipe';
import { APP_TEXT } from '@/app/config';
export default function PhotoRecipeOverlay({ export default function PhotoRecipeOverlay({
ref, ref,
@ -138,7 +139,7 @@ export default function PhotoRecipeOverlay({
'text-black/40 active:text-black/75', 'text-black/40 active:text-black/75',
'hover:text-black/40', 'hover:text-black/40',
)} )}
tooltip="Copy recipe text" tooltip={APP_TEXT.tooltip.recipeCopy}
tooltipColor="frosted" tooltipColor="frosted"
/> />
<span> <span>

View File

@ -8,6 +8,7 @@ import {
} from '@/utility/string'; } from '@/utility/string';
import { FujifilmRecipe } from '@/platforms/fujifilm/recipe'; import { FujifilmRecipe } from '@/platforms/fujifilm/recipe';
import { labelForFilm } from '@/film'; import { labelForFilm } from '@/film';
import { APP_TEXT } from '@/app/config';
export type RecipeWithCount = { export type RecipeWithCount = {
recipe: string recipe: string
@ -32,12 +33,12 @@ export const titleForRecipe = (
photos:Photo[] = [], photos:Photo[] = [],
explicitCount?: number, explicitCount?: number,
) => [ ) => [
`Recipe: ${formatRecipe(recipe)}`, `${APP_TEXT.category.recipe}: ${formatRecipe(recipe)}`,
photoQuantityText(explicitCount ?? photos.length), photoQuantityText(explicitCount ?? photos.length),
].join(' '); ].join(' ');
export const shareTextForRecipe = (recipe: string) => export const shareTextForRecipe = (recipe: string) =>
`${formatRecipe(recipe)} recipe photos`; APP_TEXT.category.recipeShare(formatRecipe(recipe));
export const descriptionForRecipePhotos = ( export const descriptionForRecipePhotos = (
photos: Photo[] = [], photos: Photo[] = [],

View File

@ -8,7 +8,7 @@ import { ReactNode, useEffect } from 'react';
import { shortenUrl } from '@/utility/url'; import { shortenUrl } from '@/utility/url';
import { toastSuccess } from '@/toast'; import { toastSuccess } from '@/toast';
import { PiXLogo } from 'react-icons/pi'; import { PiXLogo } from 'react-icons/pi';
import { SHOW_SOCIAL } from '@/app/config'; import { APP_TEXT, SHOW_SOCIAL } from '@/app/config';
import { generateXPostText } from '@/utility/social'; import { generateXPostText } from '@/utility/social';
import { useAppState } from '@/state/AppState'; import { useAppState } from '@/state/AppState';
import useOnPathChange from '@/utility/useOnPathChange'; import useOnPathChange from '@/utility/useOnPathChange';
@ -96,7 +96,7 @@ export default function ShareModal({
<BiCopy size={18} />, <BiCopy size={18} />,
() => { () => {
navigator.clipboard.writeText(pathShare); navigator.clipboard.writeText(pathShare);
toastSuccess('Link to photo copied'); toastSuccess(APP_TEXT.photo.copied);
}, },
true, true,
)} )}

View File

@ -26,7 +26,7 @@ export default function TagHeader({
entity={isTagFavs(tag) entity={isTagFavs(tag)
? <FavsTag contrast="high" /> ? <FavsTag contrast="high" />
: <PhotoTag tag={tag} contrast="high" />} : <PhotoTag tag={tag} contrast="high" />}
entityVerb={APP_TEXT.category.tagged} entityVerb={APP_TEXT.category.taggedPhotos}
entityDescription={descriptionForTaggedPhotos(photos, undefined, count)} entityDescription={descriptionForTaggedPhotos(photos, undefined, count)}
photos={photos} photos={photos}
selectedPhoto={selectedPhoto} selectedPhoto={selectedPhoto}

View File

@ -16,6 +16,7 @@ import {
formatCountDescriptive, formatCountDescriptive,
} from '@/utility/string'; } from '@/utility/string';
import { sortCategoryByCount } from '@/category'; import { sortCategoryByCount } from '@/category';
import { APP_TEXT } from '@/app/config';
// Reserved tags // Reserved tags
export const TAG_FAVS = 'favs'; export const TAG_FAVS = 'favs';
@ -48,7 +49,9 @@ export const titleForTag = (
].join(' '); ].join(' ');
export const shareTextForTag = (tag: string) => export const shareTextForTag = (tag: string) =>
isTagFavs(tag) ? 'Favorite photos' : `Photos tagged '${formatTag(tag)}'`; isTagFavs(tag)
? APP_TEXT.category.taggedFavs
: APP_TEXT.category.taggedPhrase(formatTag(tag));
export const sortTagsArray = ( export const sortTagsArray = (
tags: string[], tags: string[],
@ -95,7 +98,7 @@ export const descriptionForTaggedPhotos = (
) => ) =>
descriptionForPhotoSet( descriptionForPhotoSet(
photos, photos,
'tagged', APP_TEXT.category.taggedPhotos,
dateBased, dateBased,
explicitCount, explicitCount,
explicitDateRange, explicitDateRange,
@ -139,5 +142,6 @@ export const convertTagsForForm = (tags: Tags = []) =>
.map(({ tag, count }) => ({ .map(({ tag, count }) => ({
value: tag, value: tag,
annotation: formatCount(count), annotation: formatCount(count),
annotationAria: formatCountDescriptive(count, 'tagged'), annotationAria:
formatCountDescriptive(count, APP_TEXT.category.taggedPhotos),
})); }));

View File

@ -1,6 +1,7 @@
import { parseISO, parse, format } from 'date-fns'; import { parseISO, parse, format } from 'date-fns';
import { formatInTimeZone } from 'date-fns-tz'; import { formatInTimeZone } from 'date-fns-tz';
import { Timezone } from './timezone'; import { Timezone } from './timezone';
import { APP_TEXT } from '@/app/config';
const DATE_STRING_FORMAT_TINY = 'dd MMM yy'; const DATE_STRING_FORMAT_TINY = 'dd MMM yy';
const DATE_STRING_FORMAT_TINY_PLACEHOLDER = '00 000 00'; const DATE_STRING_FORMAT_TINY_PLACEHOLDER = '00 000 00';
@ -65,8 +66,10 @@ export const formatDate = ({
return showPlaceholder return showPlaceholder
? placeholderString ? placeholderString
: timezone : timezone
? formatInTimeZone(date, timezone, formatString) ? formatInTimeZone(
: format(date, formatString); date, timezone, formatString, { locale: APP_TEXT.dateLocale },
)
: format(date, formatString, { locale: APP_TEXT.dateLocale });
}; };
export const formatDateFromPostgresString = (date: string, length?: Length) => export const formatDateFromPostgresString = (date: string, length?: Length) =>