Refine i18n

This commit is contained in:
Sam Becker 2025-05-10 17:17:18 -05:00
parent 6ab7b2089f
commit c3e34ea629
15 changed files with 55 additions and 37 deletions

View File

@ -5,6 +5,7 @@ import { clsx } from 'clsx/lite';
import { redirect } from 'next/navigation'; import { redirect } from 'next/navigation';
import LinkWithStatus from '@/components/LinkWithStatus'; import LinkWithStatus from '@/components/LinkWithStatus';
import { IoArrowBack } from 'react-icons/io5'; import { IoArrowBack } from 'react-icons/io5';
import { APP_TEXT } from '@/app/config';
export default async function SignInPage() { export default async function SignInPage() {
const session = await auth(); const session = await auth();
@ -27,7 +28,7 @@ export default async function SignInPage() {
)} )}
> >
<IoArrowBack className="translate-y-[1px]" /> <IoArrowBack className="translate-y-[1px]" />
Home {APP_TEXT.nav.home}
</LinkWithStatus> </LinkWithStatus>
</div> </div>
); );

View File

@ -4,6 +4,7 @@ import { useAppState } from '@/state/AppState';
import SignInForm from '@/auth/SignInForm'; import SignInForm from '@/auth/SignInForm';
import clsx from 'clsx/lite'; import clsx from 'clsx/lite';
import PhotoUploadWithStatus from '@/photo/PhotoUploadWithStatus'; import PhotoUploadWithStatus from '@/photo/PhotoUploadWithStatus';
import { APP_TEXT } from '@/app/config';
export default function SignInOrUploadClient({ export default function SignInOrUploadClient({
shouldResize, shouldResize,
@ -21,10 +22,10 @@ export default function SignInOrUploadClient({
)}> )}>
<div> <div>
{isCheckingAuth {isCheckingAuth
? 'Loading ...' ? APP_TEXT.misc.loading
: isUserSignedIn : isUserSignedIn
? 'Add your first photo' ? APP_TEXT.onboarding.setupFirstPhoto
: 'Sign in to upload photos'} : APP_TEXT.onboarding.setupSignIn}
</div> </div>
{!isCheckingAuth && isUserSignedIn === false && {!isCheckingAuth && isUserSignedIn === false &&
<div className="flex justify-center my-2 sm:my-4"> <div className="flex justify-center my-2 sm:my-4">

View File

@ -1,11 +1,9 @@
import { Photo, PhotoDateRange } from '@/photo'; import { Photo, PhotoDateRange } from '@/photo';
import { absolutePathForCameraImage, pathForCamera } from '@/app/paths'; import { absolutePathForCameraImage, pathForCamera } from '@/app/paths';
import OGTile from '@/components/OGTile'; import OGTile, { OGLoadingState } from '@/components/OGTile';
import { Camera } from '.'; import { Camera } from '.';
import { descriptionForCameraPhotos, titleForCamera } from './meta'; import { descriptionForCameraPhotos, titleForCamera } from './meta';
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
export default function CameraOGTile({ export default function CameraOGTile({
camera, camera,
photos, photos,

View File

@ -20,7 +20,7 @@ export const titleForCamera = (
photos: Photo[], photos: Photo[],
explicitCount?: number, explicitCount?: number,
) => [ ) => [
APP_TEXT.category.cameraShare( APP_TEXT.category.cameraTitle(
formatCameraText(cameraFromPhoto(photos[0], camera)), formatCameraText(cameraFromPhoto(photos[0], camera)),
), ),
photoQuantityText(explicitCount ?? photos.length), photoQuantityText(explicitCount ?? photos.length),

View File

@ -1,3 +1,4 @@
import { APP_TEXT } from '@/app/config';
import { toastWaiting } from '@/toast'; import { toastWaiting } from '@/toast';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useCallback, useEffect, useRef, useTransition } from 'react'; import { useCallback, useEffect, useRef, useTransition } from 'react';
@ -6,7 +7,7 @@ import { toast } from 'sonner';
export default function useNavigateOrRunActionWithToast({ export default function useNavigateOrRunActionWithToast({
pathOrAction, pathOrAction,
toastMessage = 'Loading...', toastMessage = APP_TEXT.misc.loading,
dismissDelay = 1500, dismissDelay = 1500,
}: { }: {
pathOrAction?: string | (() => Promise<any> | undefined) pathOrAction?: string | (() => Promise<any> | undefined)

View File

@ -3,11 +3,9 @@ import {
absolutePathForFilmImage, absolutePathForFilmImage,
pathForFilm, pathForFilm,
} from '@/app/paths'; } from '@/app/paths';
import OGTile from '@/components/OGTile'; import OGTile, { OGLoadingState } from '@/components/OGTile';
import { descriptionForFilmPhotos, titleForFilm } from '.'; import { descriptionForFilmPhotos, titleForFilm } from '.';
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
export default function FilmOGTile({ export default function FilmOGTile({
film, film,
photos, photos,

View File

@ -3,11 +3,9 @@ import {
absolutePathForFocalLengthImage, absolutePathForFocalLengthImage,
pathForFocalLength, pathForFocalLength,
} from '@/app/paths'; } from '@/app/paths';
import OGTile from '@/components/OGTile'; import OGTile, { OGLoadingState } from '@/components/OGTile';
import { descriptionForFocalLengthPhotos, titleForFocalLength } from '.'; import { descriptionForFocalLengthPhotos, titleForFocalLength } from '.';
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
export default function FocalLengthOGTile({ export default function FocalLengthOGTile({
focal, focal,
photos, photos,

View File

@ -57,7 +57,7 @@ const TEXT: I18NDeepPartial = {
}, },
theme: { theme: {
theme: 'Tema', theme: 'Tema',
system: 'Usar Sistema', system: 'Sistema',
light: 'Modo Claro', light: 'Modo Claro',
dark: 'Modo Escuro', dark: 'Modo Escuro',
}, },
@ -93,7 +93,18 @@ const TEXT: I18NDeepPartial = {
deleteConfirm: (photoTitle: string) => deleteConfirm: (photoTitle: string) =>
`Tem certeza que deseja excluir "${photoTitle}"?`, `Tem certeza que deseja excluir "${photoTitle}"?`,
}, },
onboarding: {
setupComplete: 'Configuração Concluída!',
setupIncomplete: 'Finalizar Configuração',
setupSignIn: 'Entre para enviar fotos',
setupFirstPhoto: 'Adicione sua primeira foto',
// eslint-disable-next-line max-len
setupConfig: 'Altere o nome do site e outras configurações editando as variáveis de ambiente referenciadas em',
},
misc: { misc: {
loading: 'Carregando ...',
finishing: 'Finalizando ...',
uploading: 'Enviando',
repo: 'Feito com', repo: 'Feito com',
copyPhrase: (label: string) => `${label} copiado`, copyPhrase: (label: string) => `${label} copiado`,
}, },

View File

@ -56,7 +56,7 @@ const TEXT = {
}, },
theme: { theme: {
theme: 'Theme', theme: 'Theme',
system: 'Use System', system: 'System',
light: 'Light Mode', light: 'Light Mode',
dark: 'Dark Mode', dark: 'Dark Mode',
}, },
@ -92,7 +92,18 @@ const TEXT = {
deleteConfirm: (photoTitle: string) => deleteConfirm: (photoTitle: string) =>
`Are you sure you want to delete "${photoTitle}?"`, `Are you sure you want to delete "${photoTitle}?"`,
}, },
onboarding: {
setupComplete: 'Setup Complete!',
setupIncomplete: 'Finish Setup',
setupSignIn: 'Sign in to upload photos',
setupFirstPhoto: 'Add your first photo',
// eslint-disable-next-line max-len
setupConfig: 'Change the site name and other configuration by editing environment variables referenced in',
},
misc: { misc: {
loading: 'Loading ...',
finishing: 'Finishing ...',
uploading: 'Uploading',
repo: 'Made with', repo: 'Made with',
copyPhrase: (label: string) => `${label} copied`, copyPhrase: (label: string) => `${label} copied`,
}, },

View File

@ -1,11 +1,9 @@
import { Photo, PhotoDateRange } from '@/photo'; import { Photo, PhotoDateRange } from '@/photo';
import { absolutePathForLensImage, pathForLens } from '@/app/paths'; import { absolutePathForLensImage, pathForLens } from '@/app/paths';
import OGTile from '@/components/OGTile'; import OGTile, { OGLoadingState } from '@/components/OGTile';
import { Lens } from '.'; import { Lens } from '.';
import { titleForLens, descriptionForLensPhotos } from './meta'; import { titleForLens, descriptionForLensPhotos } from './meta';
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
export default function LensOGTile({ export default function LensOGTile({
lens, lens,
photos, photos,

View File

@ -5,9 +5,7 @@ import {
} from '@/photo'; } from '@/photo';
import { PhotoSetCategory } from '../category'; import { PhotoSetCategory } from '../category';
import { absolutePathForPhotoImage, pathForPhoto } from '@/app/paths'; import { absolutePathForPhotoImage, pathForPhoto } from '@/app/paths';
import OGTile from '@/components/OGTile'; import OGTile, { OGLoadingState } from '@/components/OGTile';
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
export default function PhotoOGTile({ export default function PhotoOGTile({
photo, photo,

View File

@ -11,6 +11,7 @@ import { useRef } from 'react';
import { useEffect } from 'react'; import { useEffect } from 'react';
import Spinner from '@/components/Spinner'; import Spinner from '@/components/Spinner';
import ResponsiveText from '@/components/primitives/ResponsiveText'; import ResponsiveText from '@/components/primitives/ResponsiveText';
import { APP_TEXT } from '@/app/config';
export default function PhotoUploadWithStatus({ export default function PhotoUploadWithStatus({
inputRef, inputRef,
@ -72,10 +73,11 @@ export default function PhotoUploadWithStatus({
} }
}; };
}, [resetUploadState]); }, [resetUploadState]);
const isFinishing = isPending && shouldResetUploadStateAfterPending.current; const isFinishing = isPending && shouldResetUploadStateAfterPending.current;
const uploadStatusText = filesLength > 1 const uploadStatusText = filesLength > 1
? `${fileUploadIndex + 1} of ${filesLength}` ? APP_TEXT.utility.paginate(fileUploadIndex + 1, filesLength)
: undefined; : undefined;
return ( return (
@ -158,19 +160,19 @@ export default function PhotoUploadWithStatus({
{isUploading {isUploading
? isFinishing ? isFinishing
? <> ? <>
Finishing ... {APP_TEXT.misc.finishing}
</> </>
: <> : <>
{!showButton && uploadStatusText {!showButton && uploadStatusText
? <> ? <>
<ResponsiveText shortText={uploadStatusText}> <ResponsiveText shortText={uploadStatusText}>
Uploading {uploadStatusText} {APP_TEXT.misc.uploading} {uploadStatusText}
</ResponsiveText> </ResponsiveText>
{': '} {': '}
{fileUploadName} {fileUploadName}
</> </>
: <ResponsiveText shortText={fileUploadName}> : <ResponsiveText shortText={fileUploadName}>
Uploading {fileUploadName} {APP_TEXT.misc.uploading} {fileUploadName}
</ResponsiveText>} </ResponsiveText>}
</> </>
: !showButton && <>Initializing</>} : !showButton && <>Initializing</>}

View File

@ -1,6 +1,10 @@
import Container from '@/components/Container'; import Container from '@/components/Container';
import AppGrid from '@/components/AppGrid'; import AppGrid from '@/components/AppGrid';
import { IS_SITE_READY, PRESERVE_ORIGINAL_UPLOADS } from '@/app/config'; import {
APP_TEXT,
IS_SITE_READY,
PRESERVE_ORIGINAL_UPLOADS,
} from '@/app/config';
import AdminAppConfiguration from '@/admin/AdminAppConfiguration'; import AdminAppConfiguration from '@/admin/AdminAppConfiguration';
import { clsx } from 'clsx/lite'; import { clsx } from 'clsx/lite';
import { HiOutlinePhotograph } from 'react-icons/hi'; import { HiOutlinePhotograph } from 'react-icons/hi';
@ -29,7 +33,9 @@ export default function PhotosEmptyState() {
'font-bold text-2xl', 'font-bold text-2xl',
'text-gray-700 dark:text-gray-200', 'text-gray-700 dark:text-gray-200',
)}> )}>
{!IS_SITE_READY ? 'Finish Setup' : 'Setup Complete!'} {!IS_SITE_READY
? APP_TEXT.onboarding.setupIncomplete
: APP_TEXT.onboarding.setupComplete}
</div> </div>
{!IS_SITE_READY {!IS_SITE_READY
? <AdminAppConfiguration simplifiedView /> ? <AdminAppConfiguration simplifiedView />
@ -43,8 +49,7 @@ export default function PhotosEmptyState() {
}} }}
/> />
<div> <div>
Change this site&apos;s name and other configuration {APP_TEXT.onboarding.setupConfig}
by editing environment variables referenced in
{' '} {' '}
<Link <Link
href={PATH_ADMIN_CONFIGURATION} href={PATH_ADMIN_CONFIGURATION}

View File

@ -1,10 +1,8 @@
import { Photo, PhotoDateRange } from '@/photo'; import { Photo, PhotoDateRange } from '@/photo';
import { absolutePathForRecipeImage, pathForRecipe } from '@/app/paths'; import { absolutePathForRecipeImage, pathForRecipe } from '@/app/paths';
import OGTile from '@/components/OGTile'; import OGTile, { OGLoadingState } from '@/components/OGTile';
import { descriptionForRecipePhotos, titleForRecipe } from '.'; import { descriptionForRecipePhotos, titleForRecipe } from '.';
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
export default function RecipeOGTile({ export default function RecipeOGTile({
recipe, recipe,
photos, photos,

View File

@ -1,10 +1,8 @@
import { Photo, PhotoDateRange } from '@/photo'; import { Photo, PhotoDateRange } from '@/photo';
import { absolutePathForTagImage, pathForTag } from '@/app/paths'; import { absolutePathForTagImage, pathForTag } from '@/app/paths';
import OGTile from '@/components/OGTile'; import OGTile, { OGLoadingState } from '@/components/OGTile';
import { descriptionForTaggedPhotos, titleForTag } from '.'; import { descriptionForTaggedPhotos, titleForTag } from '.';
export type OGLoadingState = 'unloaded' | 'loading' | 'loaded' | 'failed';
export default function TagOGTile({ export default function TagOGTile({
tag, tag,
photos, photos,