Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,007 changes: 863 additions & 144 deletions api/package-lock.json

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions api/prisma/migrations/20251003121931_translations/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
-- AlterTable
ALTER TABLE "Goal" ADD COLUMN "translations" JSONB;

-- AlterTable
ALTER TABLE "Game" ADD COLUMN "translations" TEXT[] DEFAULT ARRAY[]::TEXT[];

/*
Warnings:

- Made the column `translations` on table `Goal` required. This step will fail if there are existing NULL values in that column.

*/
-- AlterTable
ALTER TABLE "Game" ADD COLUMN "defaultLanguage" TEXT NOT NULL DEFAULT 'English';

-- AlterTable
ALTER TABLE "Goal" ALTER COLUMN "translations" SET NOT NULL,
ALTER COLUMN "translations" SET DEFAULT '{}';
9 changes: 8 additions & 1 deletion api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ generator client {
}

generator json {
provider = "prisma-json-types-generator"
provider = "prisma-json-types-generator"
namespace = "PrismaJson"
allowAny = false
}

datasource db {
Expand All @@ -17,6 +19,9 @@ datasource db {
model Goal {
id String @id @unique @default(cuid())
goal String
// DO NOT REMOVE
/// [GoalTranslations]
translations Json @default("{}")
description String?
oldCategories String[]
categories Category[] @relation("GoalCategories")
Expand Down Expand Up @@ -56,6 +61,8 @@ model Game {
coverImage String?
variants Variant[]
goals Goal[]
defaultLanguage String @default("English")
translations String[] @default([])
owners User[] @relation("GameOwners")
moderators User[] @relation("GameModerators")
createdAt DateTime @default(now())
Expand Down
32 changes: 32 additions & 0 deletions api/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ async function main() {
slug: 'nodiff',
enableSRLv5: false,
racetimeBeta: false,
translations: ['German'],
owners: { connect: [{ id: staff.id }, { id: owner.id }] },
moderators: { connect: [{ id: mod.id }] },
usersFavorited: {
Expand All @@ -101,6 +102,7 @@ async function main() {
gameId: game1.id,
goal: `Goal ${i + 1}`,
description: `Description for Goal ${i + 1}`,
translations: {German: `Ziel ${i + 1}`},
categories: {
connect: {
gameId_name: {
Expand Down Expand Up @@ -141,6 +143,7 @@ async function main() {
gameId: game2.id,
goal: `Goal ${i + 1}`,
description: `Description for Goal ${i + 1}`,
translations: {German: `Ziel ${i + 1}`},
categories: {
connect: {
gameId_name: {
Expand Down Expand Up @@ -179,6 +182,7 @@ async function main() {
gameId: game3.id,
goal: `Goal ${i + 1}`,
description: `Description for Goal ${i + 1}`,
translations: {German: `Ziel ${i + 1}`},

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These goals have translations, but the game doesn't have a language specified at the top level

categories: {
connect: {
gameId_name: {
Expand Down Expand Up @@ -216,6 +220,7 @@ async function main() {
gameId: game4.id,
goal: `Goal ${i + 1}`,
description: `Description for Goal ${i + 1}`,
translations: {German: `Ziel ${i + 1}`},
categories: {
connect: {
gameId_name: {
Expand Down Expand Up @@ -254,6 +259,7 @@ async function main() {
gameId: game5.id,
goal: `Goal ${i + 1}`,
description: `Description for Goal ${i + 1}`,
translations: {German: `Ziel ${i + 1}`},
categories: {
connect: {
gameId_name: {
Expand Down Expand Up @@ -285,6 +291,7 @@ async function main() {
gameId: id,
goal: 'Collect 100 Coins',
description: 'Gather 100 coins from various levels.',
translations: {German: `Sammle 100 Münzen`},
categories: {
connect: ['Collecting'].map((cat) => ({
gameId_name: {
Expand All @@ -299,6 +306,7 @@ async function main() {
gameId: id,
goal: 'Defeat the Fire Dragon',
description: 'Slay the Fire Dragon in the Volcano Dungeon.',
translations: {German: `Töte den Feuerdrachen`},
categories: {
connect: ['Combat', 'Boss Battle'].map((cat) => ({
gameId_name: {
Expand All @@ -312,6 +320,7 @@ async function main() {
{
gameId: id,
goal: 'Find 3 Hidden Keys',
translations: {German: `Finde 3 versteckte Schluessel`},
description: 'Locate 3 keys hidden throughout the forest.',
categories: {
connect: ['Exploration', 'Puzzle'].map((cat) => ({
Expand All @@ -327,6 +336,7 @@ async function main() {
gameId: id,
goal: 'Solve the Ancient Temple Puzzle',
description: 'Unlock the secret chamber in the temple.',
translations: {German: `Loese das Puzzle im antiken Tempel`},
categories: {
connect: ['Puzzle'].map((cat) => ({
gameId_name: {
Expand All @@ -341,6 +351,7 @@ async function main() {
gameId: id,
goal: 'Craft a Health Potion',
description: 'Use herbs and water to craft a basic health potion.',
translations: {German: `Crafte einen Heilungstrank`},
categories: {
connect: ['Resource Management'].map((cat) => ({
gameId_name: {
Expand All @@ -355,6 +366,7 @@ async function main() {
gameId: id,
goal: 'Complete the Speedrun Trial',
description: 'Finish the speedrun course in under 3 minutes.',
translations: {German: `Schliesse die Speedrun Pruefung ab`},
categories: {
connect: ['Time Challenge'].map((cat) => ({
gameId_name: {
Expand All @@ -369,6 +381,7 @@ async function main() {
gameId: id,
goal: 'Pickpocket a Guard',
description: 'Steal a gold coin from a guard without being caught.',
translations: {German: `Stehle von einer Wache`},
categories: {
connect: ['Stealth'].map((cat) => ({
gameId_name: {
Expand All @@ -383,6 +396,7 @@ async function main() {
gameId: id,
goal: 'Reach Level 10',
description: 'Gain experience and reach level 10.',
translations: {German: `Erreiche Level 10`},
categories: {
connect: ['Story Progression'].map((cat) => ({
gameId_name: {
Expand All @@ -397,6 +411,7 @@ async function main() {
gameId: id,
goal: 'Defeat 50 Enemies',
description: 'Eliminate 50 enemies to prove your strength.',
translations: {German: `Besiege 50 Gegner`},
categories: {
connect: ['Combat'].map((cat) => ({
gameId_name: {
Expand All @@ -411,6 +426,7 @@ async function main() {
gameId: id,
goal: 'Cross the Lava Pit',
description: 'Use platforms to cross the lava pit safely.',
translations: {German: `Ueberquere die Lava Schlucht`},
categories: {
connect: ['Movement', 'Puzzle'].map((cat) => ({
gameId_name: {
Expand All @@ -425,6 +441,7 @@ async function main() {
gameId: id,
goal: 'Rescue the Lost Villager',
description: 'Find and rescue a villager trapped in the cave.',
translations: {German: `Rette den verlorenen Dorfbewohner`},
categories: {
connect: ['Exploration', 'Story Progression'].map((cat) => ({
gameId_name: {
Expand All @@ -439,6 +456,7 @@ async function main() {
gameId: id,
goal: 'Gather 10 Rare Herbs',
description: 'Collect rare herbs from the mountain region.',
translations: {German: `Sammle 10 seltene Kraeuter`},
categories: {
connect: ['Collecting', 'Resource Management'].map((cat) => ({
gameId_name: {
Expand All @@ -453,6 +471,7 @@ async function main() {
gameId: id,
goal: 'Defeat the Ice Golem',
description: 'Defeat the Ice Golem in the Frozen Cavern.',
translations: {German: `Besiege den Eis Golem`},
categories: {
connect: ['Combat', 'Boss Battle'].map((cat) => ({
gameId_name: {
Expand All @@ -467,6 +486,7 @@ async function main() {
gameId: id,
goal: 'Escape the Dungeon Maze',
description: 'Navigate and escape the maze in the dungeon.',
translations: {German: `Fliehe aus dem Labyrinth`},
categories: {
connect: ['Puzzle', 'Exploration'].map((cat) => ({
gameId_name: {
Expand All @@ -481,6 +501,7 @@ async function main() {
gameId: id,
goal: 'Solve the Color Matching Puzzle',
description: 'Match colors correctly to unlock the gate.',
translations: {German: 'Loese das Farb Puzzle'},
categories: {
connect: ['Puzzle'].map((cat) => ({
gameId_name: {
Expand All @@ -495,6 +516,7 @@ async function main() {
gameId: id,
goal: 'Survive the Night in the Forest',
description: 'Survive until morning without getting caught.',
translations: {German: 'Ueberlebe die Nacht im Wald'},
categories: {
connect: ['Stealth', 'Time Challenge'].map((cat) => ({
gameId_name: {
Expand All @@ -509,6 +531,7 @@ async function main() {
gameId: id,
goal: 'Gather 20 Crystals',
description: 'Mine 20 crystals from the underground cave.',
translations: {German: 'Sammle 20 Kristalle'},
categories: {
connect: ['Collecting'].map((cat) => ({
gameId_name: {
Expand Down Expand Up @@ -537,6 +560,7 @@ async function main() {
gameId: id,
goal: 'Repair the Broken Bridge',
description: 'Find materials and repair the bridge.',
translations: {German: 'Repariere die kaputte Bruecke'},
categories: {
connect: ['Resource Management', 'Exploration'].map((cat) => ({
gameId_name: {
Expand All @@ -551,6 +575,7 @@ async function main() {
gameId: id,
goal: 'Climb the Tower of Trials',
description: 'Reach the top of the Tower of Trials.',
translations: {German: 'Erklimme den Turm der Pruefungen'},
categories: {
connect: ['Movement', 'Story Progression'].map((cat) => ({
gameId_name: {
Expand All @@ -565,6 +590,7 @@ async function main() {
gameId: id,
goal: 'Find the Golden Sword',
description: 'Retrieve the legendary Golden Sword.',
translations: {German: 'Finde das goldene Schwert'},
categories: {
connect: ['Exploration'].map((cat) => ({
gameId_name: {
Expand All @@ -579,6 +605,7 @@ async function main() {
gameId: id,
goal: 'Complete the Puzzle Gauntlet',
description: 'Solve a series of puzzles back-to-back.',
translations: {German: 'Schliesse den Puzzle Wettbewerb ab'},
categories: {
connect: ['Puzzle'].map((cat) => ({
gameId_name: {
Expand All @@ -593,6 +620,7 @@ async function main() {
gameId: id,
goal: 'Steal a Rare Artifact',
description: 'Steal an artifact from the museum undetected.',
translations: {German: 'Stehle ein seltenes Artefakt'},
categories: {
connect: ['Stealth', 'Resource Management'].map((cat) => ({
gameId_name: {
Expand All @@ -607,6 +635,7 @@ async function main() {
gameId: id,
goal: 'Defeat the Dark Lord',
description: 'Defeat the final boss and save the kingdom.',
translations: {German: 'Toete den dunken Lord'},
categories: {
connect: ['Combat', 'Boss Battle'].map((cat) => ({
gameId_name: {
Expand All @@ -621,6 +650,7 @@ async function main() {
gameId: id,
goal: 'Find and Open 10 Treasure Chests',
description: 'Locate and open 10 treasure chests.',
translations: {German: 'Finde und oeffne 10 Schatztruhen'},
categories: {
connect: ['Collecting'].map((cat) => ({
gameId_name: {
Expand All @@ -635,6 +665,7 @@ async function main() {
gameId: id,
goal: 'Survive the Arena for 5 Rounds',
description: 'Defeat all enemies across 5 rounds in the arena.',
translations: {German: 'Ueberlebe die Arena fuer 5 Runden'},
categories: {
connect: ['Combat', 'Time Challenge'].map((cat) => ({
gameId_name: {
Expand All @@ -651,6 +682,7 @@ async function main() {
description: `Complete side quest number ${
i + 27
} for extra rewards.`,
translations: {German: `Nebenquest ${i + 27}`},
categories: {
connect: {
gameId_name: {
Expand Down
11 changes: 11 additions & 0 deletions api/src/@types/prisma-json-types/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// This file must be a module, so we include an empty export.

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if I would put this file in the @types folder. We only have it in order to override/augment types in the actual @types namespace, which this wouldn't fall under. In the variants branch i had it in a prismajson.d.ts file at the top level, but I don't think it ultimately matters where we settle on putting the file or what it's called

export {};

declare global {
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace PrismaJson {
type GoalTranslations = {
[k: string]: string;
};
}
}
1 change: 1 addition & 0 deletions api/src/core/generation/GeneratorCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export interface GeneratorGoal {
id: string;
goal: string;
description: string | null;
translations: {[k: string]: string};
categories: string[];
difficulty: number | null;
}
Expand Down
4 changes: 4 additions & 0 deletions api/src/database/games/Games.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,10 @@ export const updateRacetimeGoal = (slug: string, racetimeGoal: string) => {
return prisma.game.update({ where: { slug }, data: { racetimeGoal } });
};

export const updateDefaultLanguage = (slug: string, defaultLanguage: string) => {
return prisma.game.update({ where: { slug }, data: { defaultLanguage } });
}

export const updateSlugWords = (slug: string, slugWords: string[]) => {
return prisma.game.update({ where: { slug }, data: { slugWords } });
};
Expand Down
2 changes: 2 additions & 0 deletions api/src/database/games/Goals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const createGoal = async (
goal: string,
description?: string,
categories?: string[],
translations?: {[lang: string]: string},
difficulty?: number,
) => {
const gameId = (await gameForSlug(gameSlug))?.id;
Expand All @@ -55,6 +56,7 @@ export const createGoal = async (
})),
},
difficulty,
translations,
game: { connect: { slug: gameSlug } },
},
});
Expand Down
Loading
Loading