feat: add SPA, serve at /app/, update Dockerfile and README
- React + TanStack Router + shadcn/ui SPA under spa/ - serve spa/dist at /app/ with index.html fallback for client routing - Dockerfile: node build stage for SPA, copy dist into runtime image - README: document SPA, CORS_ORIGINS env var, architecture entry - vite base set to /app/, manifest.json paths fixed
This commit is contained in:
300
spa/src/locales/en.json
Normal file
300
spa/src/locales/en.json
Normal file
@@ -0,0 +1,300 @@
|
||||
{
|
||||
"common": {
|
||||
"cancel": "Cancel",
|
||||
"confirm": "Confirm",
|
||||
"delete": "Delete",
|
||||
"save": "Save",
|
||||
"saving": "Saving...",
|
||||
"back": "Back",
|
||||
"tryAgain": "Try again",
|
||||
"follow": "Follow",
|
||||
"following": "Following",
|
||||
"unfollow": "Unfollow",
|
||||
"remove": "Remove",
|
||||
"block": "Block",
|
||||
"unblock": "Unblock",
|
||||
"accept": "Accept",
|
||||
"reject": "Reject",
|
||||
"dismiss": "Dismiss",
|
||||
"continue": "Continue",
|
||||
"generate": "Generate",
|
||||
"generating": "Generating...",
|
||||
"reviews": "{{count}} reviews",
|
||||
"films": "{{count}} films",
|
||||
"filmsAvg": "{{count}} films, avg {{avg}}"
|
||||
},
|
||||
"nav": {
|
||||
"home": "Home",
|
||||
"search": "Search",
|
||||
"diary": "Diary",
|
||||
"profile": "Profile"
|
||||
},
|
||||
"auth": {
|
||||
"title": "Movies Diary",
|
||||
"loginHeading": "Log in to your account",
|
||||
"registerHeading": "Create your account",
|
||||
"email": "Email",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"loginError": "Invalid email or password",
|
||||
"registerError": "Registration failed. Try a different email.",
|
||||
"loggingIn": "Logging in...",
|
||||
"logIn": "Log in",
|
||||
"creating": "Creating...",
|
||||
"createAccount": "Create account",
|
||||
"noAccount": "Don't have an account?",
|
||||
"hasAccount": "Already have an account?"
|
||||
},
|
||||
"errors": {
|
||||
"somethingWrong": "Something went wrong",
|
||||
"unknownError": "Unknown error"
|
||||
},
|
||||
"feed": {
|
||||
"title": "Movies Diary",
|
||||
"tab": "Feed",
|
||||
"watchlist": "Watchlist",
|
||||
"queue": "Queue",
|
||||
"sortLatest": "Latest",
|
||||
"sortOldest": "Oldest",
|
||||
"sortTopRated": "Top Rated",
|
||||
"sortLowestRated": "Lowest Rated",
|
||||
"noActivity": "No activity yet",
|
||||
"noActivityDesc": "Follow people to see their reviews",
|
||||
"addToWatchlist": "Add to watchlist",
|
||||
"watchlistEmpty": "Watchlist empty",
|
||||
"watchlistEmptyDesc": "Save movies you want to watch",
|
||||
"removeFromWatchlist": "Remove from watchlist?",
|
||||
"queueEmpty": "Queue empty",
|
||||
"queueEmptyDesc": "Movies from Jellyfin/Plex appear here",
|
||||
"deleteReview": "Delete this review?"
|
||||
},
|
||||
"diary": {
|
||||
"title": "Diary",
|
||||
"noEntries": "No entries",
|
||||
"nothingLogged": "Nothing logged this month",
|
||||
"deleteReview": "Delete this review?"
|
||||
},
|
||||
"movie": {
|
||||
"ratingDistribution": "Rating Distribution",
|
||||
"community": "Community",
|
||||
"yourHistory": "Your History",
|
||||
"castCrew": "Cast & Crew",
|
||||
"saved": "Saved",
|
||||
"watchlist": "Watchlist",
|
||||
"noReviews": "No reviews yet",
|
||||
"beFirst": "Be the first to review",
|
||||
"trend": "Trend: {{trend}}",
|
||||
"noViewings": "No viewings",
|
||||
"notLogged": "You haven't logged this movie",
|
||||
"tmdbStats": "TMDB Stats",
|
||||
"budget": "Budget",
|
||||
"revenue": "Revenue",
|
||||
"tmdb": "TMDB",
|
||||
"cast": "Cast",
|
||||
"crew": "Crew",
|
||||
"keywords": "Keywords",
|
||||
"castCredits": "Cast Credits ({{count}})",
|
||||
"crewCredits": "Crew Credits ({{count}})",
|
||||
"noCredits": "No credits found"
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Search movies, people...",
|
||||
"searchPrompt": "Search for movies or people",
|
||||
"noResults": "No results",
|
||||
"noResultsDesc": "Try a different search term",
|
||||
"people": "People",
|
||||
"movies": "Movies"
|
||||
},
|
||||
"profile": {
|
||||
"title": "Profile",
|
||||
"followingFollowers": "Following & Followers",
|
||||
"yearInReview": "Year in Review",
|
||||
"recent": "Recent",
|
||||
"topRated": "Top Rated",
|
||||
"trends": "Trends",
|
||||
"movies": "Movies",
|
||||
"avg": "Avg",
|
||||
"followingStat": "Following",
|
||||
"followers": "Followers",
|
||||
"noEntries": "No entries",
|
||||
"noTrends": "No trends yet",
|
||||
"topDirectors": "Top Directors",
|
||||
"monthlyActivity": "Monthly Activity"
|
||||
},
|
||||
"social": {
|
||||
"title": "Social",
|
||||
"following": "Following",
|
||||
"followers": "Followers",
|
||||
"pending": "Pending",
|
||||
"notFollowing": "Not following anyone",
|
||||
"notFollowingDesc": "Follow users to see their reviews in your feed",
|
||||
"noFollowers": "No followers yet",
|
||||
"noFollowersOther": "No followers",
|
||||
"noPending": "No pending requests",
|
||||
"followSent": "Follow request sent to {{handle}}",
|
||||
"followError": "Could not follow that user",
|
||||
"handlePlaceholder": "@user@instance.example"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Settings",
|
||||
"editProfile": "Edit Profile",
|
||||
"editProfileDesc": "Username, bio",
|
||||
"import": "Import",
|
||||
"importDesc": "Import from CSV",
|
||||
"yearWrapUp": "Year Wrap-Up",
|
||||
"yearWrapUpDesc": "Annual summaries",
|
||||
"webhookTokens": "Webhook Tokens",
|
||||
"webhookTokensDesc": "Jellyfin, Plex",
|
||||
"blockedUsers": "Blocked Users",
|
||||
"blockedUsersDesc": "Manage blocked users",
|
||||
"blockedUsersDescAdmin": "Users & domains",
|
||||
"blockedDomains": "Blocked Domains",
|
||||
"blockedDomainsDesc": "Federation blocks",
|
||||
"logOut": "Log Out",
|
||||
"account": "Account",
|
||||
"data": "Data",
|
||||
"integrations": "Integrations",
|
||||
"socialGroup": "Social"
|
||||
},
|
||||
"editProfile": {
|
||||
"title": "Edit Profile",
|
||||
"banner": "Banner",
|
||||
"avatar": "Avatar",
|
||||
"displayName": "Display Name",
|
||||
"displayNamePlaceholder": "How you appear to others",
|
||||
"bio": "Bio",
|
||||
"bioPlaceholder": "Tell us about yourself",
|
||||
"federation": "Federation",
|
||||
"federationDesc": "ActivityPub profile settings",
|
||||
"alsoKnownAs": "Also Known As",
|
||||
"alsoKnownAsPlaceholder": "https://other-instance.example/users/you",
|
||||
"alsoKnownAsHelp": "URL of your account on another instance, for account migration",
|
||||
"profileFields": "Profile Fields",
|
||||
"profileFieldsHelp": "Key-value pairs shown on your profile (e.g. Website, Pronouns)",
|
||||
"label": "Label",
|
||||
"value": "Value",
|
||||
"addField": "Add field"
|
||||
},
|
||||
"blocked": {
|
||||
"title": "Blocked",
|
||||
"users": "Users",
|
||||
"domains": "Domains",
|
||||
"noBlockedUsers": "No blocked users",
|
||||
"noBlockedDomains": "No blocked domains",
|
||||
"domainPlaceholder": "example.com"
|
||||
},
|
||||
"webhooks": {
|
||||
"title": "Webhook Tokens",
|
||||
"noTokens": "No tokens",
|
||||
"noTokensDesc": "Generate one to get started",
|
||||
"generateToken": "Generate Token",
|
||||
"provider": "Provider",
|
||||
"jellyfin": "Jellyfin",
|
||||
"plex": "Plex",
|
||||
"labelOptional": "Label (optional)",
|
||||
"labelPlaceholder": "e.g. Living room",
|
||||
"copied": "Webhook URL copied to clipboard"
|
||||
},
|
||||
"wrapup": {
|
||||
"title": "Year Wrap-Up",
|
||||
"noWrapUps": "No wrap-ups",
|
||||
"generateWrapUp": "Generate Wrap-Up",
|
||||
"startDate": "Start Date",
|
||||
"endDate": "End Date",
|
||||
"heroSubtitle": "Your Year in Movies",
|
||||
"moviesWatched": "movies watched",
|
||||
"watchHours": "{{hours}} hours of watch time",
|
||||
"ratings": "Ratings",
|
||||
"averageRating": "average rating",
|
||||
"busiestMonth": "Busiest month: {{month}}",
|
||||
"favoriteDay": "Favorite day: {{day}}",
|
||||
"topDirectors": "Top Directors",
|
||||
"uniqueDirectors": "{{count}} unique directors",
|
||||
"topActors": "Top Actors",
|
||||
"uniqueActors": "{{count}} unique actors",
|
||||
"genres": "Genres",
|
||||
"genresExplored": "{{count}} genres explored",
|
||||
"highestRated": "Highest rated: {{genre}}",
|
||||
"lowestRated": "Lowest rated: {{genre}}",
|
||||
"highlights": "Highlights",
|
||||
"highlightHighest": "Highest Rated",
|
||||
"highlightLowest": "Lowest Rated",
|
||||
"highlightOldest": "Oldest Film",
|
||||
"highlightNewest": "Newest Film",
|
||||
"highlightLongest": "Longest",
|
||||
"highlightShortest": "Shortest",
|
||||
"highlightFirst": "First Watched",
|
||||
"highlightLast": "Last Watched",
|
||||
"rewatches": "Rewatches",
|
||||
"moviesRewatched": "movies rewatched",
|
||||
"mostRewatched": "Most rewatched:",
|
||||
"posterMosaic": "Your Year in Posters"
|
||||
},
|
||||
"logReview": {
|
||||
"title": "Log Review",
|
||||
"yourRating": "Your Rating",
|
||||
"commentPlaceholder": "Add a comment... (optional)",
|
||||
"logging": "Logging...",
|
||||
"logReview": "Log Review",
|
||||
"logged": "{{title}} logged!"
|
||||
},
|
||||
"searchOverlay": {
|
||||
"backToSearch": "Back to search",
|
||||
"addManuallyTitle": "Add movie manually",
|
||||
"addManuallyDesc": "The backend will try to match this on TMDB automatically",
|
||||
"imdbId": "IMDb / TMDB ID",
|
||||
"imdbPlaceholder": "e.g. tt0816692",
|
||||
"imdbHelp": "Exact lookup — fill just this to add by ID",
|
||||
"orSearchByTitle": "Or search by title:",
|
||||
"titleLabel": "Title",
|
||||
"titlePlaceholder": "e.g. Interstellar",
|
||||
"releaseYear": "Release year",
|
||||
"yearPlaceholder": "e.g. 2014",
|
||||
"director": "Director",
|
||||
"directorPlaceholder": "e.g. Christopher Nolan",
|
||||
"searchPlaceholder": "Search movies...",
|
||||
"noMoviesFound": "No movies found",
|
||||
"addManually": "Add manually",
|
||||
"addManuallySubtitle": "Movie not in the database yet"
|
||||
},
|
||||
"swipeToDelete": {
|
||||
"removeItem": "Remove this item?"
|
||||
},
|
||||
"import": {
|
||||
"title": "Import",
|
||||
"step": "Step {{current}} of {{total}}",
|
||||
"fieldTitle": "Title",
|
||||
"fieldReleaseYear": "Release Year",
|
||||
"fieldDirector": "Director",
|
||||
"fieldRating": "Rating",
|
||||
"fieldWatchedAt": "Watched At",
|
||||
"fieldComment": "Comment",
|
||||
"fieldExternalId": "External ID",
|
||||
"fieldSkip": "Skip",
|
||||
"scale1to5": "1–5 (keep as-is)",
|
||||
"scale1to10": "1–10 → 1–5 (×0.5)",
|
||||
"scale1to100": "1–100 → 1–5 (×0.05)",
|
||||
"scaleLetterboxd": "0–4 Letterboxd → 1–5 (×1.25)",
|
||||
"dropCsv": "Drop a CSV file or tap to browse",
|
||||
"uploading": "Uploading...",
|
||||
"preview": "Preview",
|
||||
"rowsCols": "{{rows}} rows · {{cols}} columns",
|
||||
"columnMapping": "Column Mapping",
|
||||
"ratingScale": "Rating Scale",
|
||||
"ratingScaleDesc": "How should ratings be converted to 1–5?",
|
||||
"dateFormat": "Date Format",
|
||||
"dateFormatDesc": "Leave empty for auto-detection",
|
||||
"dateFormatPlaceholder": "e.g. %Y-%m-%d",
|
||||
"applying": "Applying...",
|
||||
"importSummary": "Import Summary",
|
||||
"summaryDesc": "{{valid}} valid · {{duplicates}} duplicates · {{invalid}} invalid",
|
||||
"previewRows": "Preview ({{count}} rows)",
|
||||
"status": "Status",
|
||||
"year": "Year",
|
||||
"watched": "Watched",
|
||||
"importing": "Importing...",
|
||||
"importRows": "Import {{count}} rows",
|
||||
"importComplete": "Import complete!",
|
||||
"viewDiary": "View your diary"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user