ronantakizawa/codereview-bench huggingface dataset:
Repository: sunflower-farmers/sunflower-farmers
File: src/features/game/types/withdrawables.ts (TypeScript)

Code before:
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Baby Cow": {
      tradeAt: SEASONS["Better Together"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Baby Sheep": {
      tradeAt: SEASONS["Better Together"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Black Hole Flower": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Sleepy Chicken": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Astronaut Cow": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Astronaut Sheep": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
  };


Review comment (bug):
```suggestion
    "Black Hole Flower": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
    "Sleepy Chicken": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
    "Astronaut Cow": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
    "Astronaut Sheep": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
```
The Withdrawal dates are wrong on the FE, the dates are coded correctly on the BE

Code after:
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Baby Cow": {
      tradeAt: SEASONS["Better Together"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Baby Sheep": {
      tradeAt: SEASONS["Better Together"].endDate,
      withdrawAt: new Date("2025-12-03T00:00:00Z"),
    },
    "Black Hole Flower": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
    "Sleepy Chicken": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
    "Astronaut Cow": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
    "Astronaut Sheep": {
      tradeAt: SEASONS["Paw Prints"].endDate,
      withdrawAt: new Date("2026-03-04T00:00:00Z"),
    },
  };
Repository: sunflower-farmers/sunflower-farmers
File: src/features/game/types/pets.ts (TypeScript)

Code before:
  now?: number;
}) {
  const petsOfType = Object.values(nftPets).filter(
    (pet) => pet.traits?.type === petType,
  );

  const isPetOfTypeFed = petsOfType.some((pet) => {
    if (pet.id === id) return false;
    const lastFedAt = pet.requests.fedAt;
    const todayDate = new Date(now).toISOString().split("T")[0];
    const lastFedAtDate = new Date(lastFedAt).toISOString().split("T")[0];
    return lastFedAtDate === todayDate;
  });

  return isPetOfTypeFed;
}

type PetNFTRevealConfig = {
  revealAt: Date;
  startId: number;
  endId: number;
};

const PET_NFT_REVEAL_CONFIG: PetNFTRevealConfig[] = [
  {
    revealAt: new Date("2025-11-11T00:00:00.000Z"),
    startId: 1,
    endId: 1000,
  },
  {
    revealAt: new Date("2025-11-11T00:00:00.000Z"),
    startId: 2501,
    endId: 3000,
  },
];

export function isPetNFTAllocated(petId: number) {
  return PET_NFT_REVEAL_CONFIG.some(
    (config) => petId >= config.startId && petId <= config.endId,
  );
}

export function isPetNFTRevealed(petId: number, createdAt: number) {
  return (
    isPetNFTAllocated(petId) &&
    PET_NFT_REVEAL_CONFIG.some(
      (config) => createdAt >= config.revealAt.getTime(),
    )
  );
}


Review comment (suggestion):
```suggestion
    revealAt: new Date("2025-11-11T00:00:00.000Z"),
```


Code after:
  now?: number;
}) {
  const petsOfType = Object.values(nftPets).filter(
    (pet) => pet.traits?.type === petType,
  );

  const isPetOfTypeFed = petsOfType.some((pet) => {
    if (pet.id === id) return false;
    const lastFedAt = pet.requests.fedAt;
    const todayDate = new Date(now).toISOString().split("T")[0];
    const lastFedAtDate = new Date(lastFedAt).toISOString().split("T")[0];
    return lastFedAtDate === todayDate;
  });

  return isPetOfTypeFed;
}

type PetNFTRevealConfig = {
  revealAt: Date;
  startId: number;
  endId: number;
};

const PET_NFT_REVEAL_CONFIG: PetNFTRevealConfig[] = [
  {
    revealAt: new Date("2025-11-11T00:00:00.000Z"),
    startId: 1,
    endId: 1000,
  },
  {
    revealAt: new Date("2025-11-11T00:00:00.000Z"),
    startId: 2501,
    endId: 3000,
  },
];

export function isPetNFTRevealed(petId: number, createdAt: number) {
  return PET_NFT_REVEAL_CONFIG.some(
    (config) =>
      petId >= config.startId &&
      petId <= config.endId &&
      createdAt >= config.revealAt.getTime(),
  );
}
Repository: sunflower-farmers/sunflower-farmers
File: src/features/island/collectibles/MovableComponent.tsx (TypeScript)

Code before:

  const isSelected = movingItem?.id === id && movingItem?.name === name;

  const selectedCollectible = useSelector(
    gameService,
    getSelectedCollectible(name, id, location),
  );
  const hasRenewAccess = useSelector(gameService, (state) =>
    hasFeatureAccess(state.context.state, "RENEW_PET_SHRINES"),
  );

  const isShrine = name in PET_SHRINES || name === "Obsidian Shrine";

  const now = useNow({ live: isShrine });

  const removeAction =
    !isMobile &&
    getRemoveAction(name, now, hasRenewAccess, selectedCollectible);

  const hasRemovalAction = !!removeAction;

  const hasFlipAction = !isMobile && isCollectible(name);

  const flip = () => {
    if (isCollectible(name)) {
      landscapingMachine.send("FLIP", { id, name, location });
    }
  };

  const isFlipped = useSelector(gameService, (state) => {
    if (!isCollectible(name)) return false;
    const collectibles =
      location === "home"
        ? state.context.state.home.collectibles
        : state.context.state.collectibles;
    return (
      collectibles[name]?.find((collectible) => collectible.id === id)
        ?.flipped ?? false
    );
  });

  const remove = () => {
    if (!removeAction) {
      return;
    }

    if (showRemoveConfirmation) {
      landscapingMachine.send("REMOVE", {
        event: removeAction,
        id: id,
        name: name,

Review comment (suggestion):
```suggestion
    const overlaps = getOverlappingCollectibles({
      state: gameService.getSnapshot().context.state,
      x: coordinatesX,
      y: coordinatesY,
      location,
      current: { id, name },
    });
```

Code after:
  );

  const isSelected = movingItem?.id === id && movingItem?.name === name;

  const selectedCollectible = useSelector(
    gameService,
    getSelectedCollectible(name, id, location),
  );
  const hasRenewAccess = useSelector(gameService, (state) =>
    hasFeatureAccess(state.context.state, "RENEW_PET_SHRINES"),
  );

  const isShrine = name in PET_SHRINES || name === "Obsidian Shrine";

  const now = useNow({ live: isShrine });

  const removeAction =
    !isMobile &&
    getRemoveAction(name, now, hasRenewAccess, selectedCollectible);

  const hasRemovalAction = !!removeAction;

  const hasFlipAction = !isMobile && isCollectible(name);

  const flip = () => {
    if (isCollectible(name)) {
      landscapingMachine.send("FLIP", { id, name, location });
    }
  };

  const isFlipped = useSelector(gameService, (state) => {
    if (!isCollectible(name)) return false;
    const collectibles =
      location === "home"
        ? state.context.state.home.collectibles
        : state.context.state.collectibles;
    return (
      collectibles[name]?.find((collectible) => collectible.id === id)
        ?.flipped ?? false
    );
  });

  const remove = () => {
    if (!removeAction) {
      return;
    }

    if (showRemoveConfirmation) {
      landscapingMachine.send("REMOVE", {
        event: removeAction,
        id: id,
Repository: sunflower-farmers/sunflower-farmers
File: src/features/island/buildings/components/building/firePit/FirePit.tsx (TypeScript)

Code before:
      gameAnalytics.trackMilestone({
        event: "Tutorial:Cooked:Completed",
      });
    }
  };

  const handleCollect = () => {
    gameService?.send({
      type: "recipes.collected",
      building: "Fire Pit",
      buildingId,
    });
  };

  const handleClick = () => {
    if (!isBuilt) return;

    if (!cooking && readyRecipes.length > 0) {
      handleCollect();
    } else {
      bakeryAudio();
      setShowModal(true);
    }
  };

  const showHelper = rhubarbCount.gte(3) && experience === 0 && !cooking;

  return (
    <>
      <BuildingImageWrapper
        name="Fire Pit"
        onClick={handleClick}
        ready={readyRecipes?.length > 0}
      >
        <img
          src={FIRE_PIT_VARIANTS[getCurrentBiome(island)][season]}
          className={classNames("absolute bottom-0 pointer-events-none", {
            "opacity-100": !cooking,
            "opacity-80": cooking,
          })}
          style={{
            width: `${PIXEL_SCALE * 47}px`,
            height: `${PIXEL_SCALE * 33}px`,
          }}
        />
        {cooking && (
          <img
            src={ITEM_DETAILS[cooking.name].image}
            className={classNames("absolute z-30 pointer-events-none")}
            onLoad={(e) => {
              const img = e.currentTarget;

Review comment (refactor):
```suggestion
  const showHelper = rhubarbCount.gte(3) && experience === 0 && !rhubarbTartCooked && !cooking;
```

Small suggestion, non blocking. After I cooked my first rhubarb tart the arrow showed to cook another, as I still had 5 in my inventory. This suggestion is to hide the arrow if the player has cooked a rhubarb tart already.

Code after:
      gameAnalytics.trackMilestone({
        event: "Tutorial:Cooked:Completed",
      });
    }
  };

  const handleCollect = () => {
    gameService?.send({
      type: "recipes.collected",
      building: "Fire Pit",
      buildingId,
    });
  };

  const handleClick = () => {
    if (!isBuilt) return;

    if (!cooking && readyRecipes.length > 0) {
      handleCollect();
    } else {
      bakeryAudio();
      setShowModal(true);
    }
  };

  const showHelper =
    rhubarbCount.gte(3) && experience === 0 && !rhubarbTartCooked && !cooking;

  return (
    <>
      <BuildingImageWrapper
        name="Fire Pit"
        onClick={handleClick}
        ready={readyRecipes?.length > 0}
      >
        <img
          src={FIRE_PIT_VARIANTS[getCurrentBiome(island)][season]}
          className={classNames("absolute bottom-0 pointer-events-none", {
            "opacity-100": !cooking,
            "opacity-80": cooking,
          })}
          style={{
            width: `${PIXEL_SCALE * 47}px`,
            height: `${PIXEL_SCALE * 33}px`,
          }}
        />
        {cooking && (
          <img
            src={ITEM_DETAILS[cooking.name].image}
            className={classNames("absolute z-30 pointer-events-none")}
            onLoad={(e) => {
Repository: sunflower-farmers/sunflower-farmers
File: src/features/game/events/landExpansion/completeNPCChore.ts (TypeScript)

Code before:
      ).add(amount);
    });

    if (chore.reward.coins) {
      draft.coins += chore.reward.coins;
    }

    // Increase NPC friendship points
    if (!draft.npcs) {
      draft.npcs = {};
    }
    if (!draft.npcs[npcName]) {
      draft.npcs[npcName] = { deliveryCount: 0 };
    }
    if (!draft.npcs[npcName].friendship) {
      draft.npcs[npcName].friendship = { points: 0, updatedAt: createdAt };
    }

    draft.npcs[npcName].friendship.points += 1;
    draft.npcs[npcName].friendship.updatedAt = createdAt;

    draft.farmActivity = trackFarmActivity(
      "Chore Completed",
      draft.farmActivity,
    );

    const ticket = getChapterTicket(createdAt);
    const amount = items[ticket] ?? 0;

    if (amount > 0) {
      const chapter = getCurrentChapter(createdAt);
      const pointsAwarded = getChapterTaskPoints({
        task: "chore",
        points: amount,
      });
      const previousPoints =
        draft.farmActivity[`${chapter} Points Earned`] ?? 0;
      const nextPoints = previousPoints + pointsAwarded;
      const chapterTrack = CHAPTER_TRACKS[chapter];

      if (chapterTrack) {
        const daysSinceStart =
          (createdAt - CHAPTERS[chapter].startDate.getTime()) /
          (24 * 60 * 60 * 1000);

        gameAnalytics.trackTracksPoints({
          chapter,
          source: "chore",
          points: pointsAwarded,
        });


Review comment (suggestion):
This logic appears to be repeated with just a couple different parameters. Could we turn this into a re-useable function?

```ts
function handleChapterAnalytics({ task: "chore" | "delivery" | "bounty", points: number }) {...}
```

Code after:
    }

    // Increase NPC friendship points
    if (!draft.npcs) {
      draft.npcs = {};
    }
    if (!draft.npcs[npcName]) {
      draft.npcs[npcName] = { deliveryCount: 0 };
    }
    if (!draft.npcs[npcName].friendship) {
      draft.npcs[npcName].friendship = { points: 0, updatedAt: createdAt };
    }

    draft.npcs[npcName].friendship.points += 1;
    draft.npcs[npcName].friendship.updatedAt = createdAt;

    draft.farmActivity = trackFarmActivity(
      "Chore Completed",
      draft.farmActivity,
    );

    const ticket = getChapterTicket(createdAt);
    const amount = items[ticket] ?? 0;

    if (amount > 0) {
      const chapter = getCurrentChapter(createdAt);
      const pointsAwarded = getChapterTaskPoints({
        task: "chore",
        points: amount,
      });
      handleChapterAnalytics({
        task: "chore",
        points: amount,
        farmActivity: draft.farmActivity,
        createdAt,
      });

      draft.farmActivity = trackFarmActivity(
        `${ticket} Collected`,
        draft.farmActivity,
        new Decimal(amount),
      );

      draft.farmActivity = trackFarmActivity(
        `${chapter} Points Earned`,
        draft.farmActivity,
        new Decimal(pointsAwarded),
      );
    }

    return draft;
Repository: sunflower-farmers/sunflower-farmers
File: src/features/island/fisherman/WaterTrapModal.tsx (TypeScript)

Code before:
        : null;
    } catch {
      return null;
    }
  },
  set(key: string, value: string): void {
    try {
      if (typeof window !== "undefined") localStorage.setItem(key, value);
    } catch {
      // Safari private mode, quota exceeded, etc.
    }
  },
  remove(key: string): void {
    try {
      if (typeof window !== "undefined") localStorage.removeItem(key);
    } catch {
      // Safari private mode, etc.
    }
  },
};

const getStoredTrap = (
  canUseMarinerPot: boolean,
): WaterTrapName | undefined => {
  const stored = safeLocalStorage.get<WaterTrapName>(LAST_TRAP_KEY);
  if (!stored || !(stored in WATER_TRAP)) return undefined;
  if (stored === "Mariner Pot" && !canUseMarinerPot) return undefined;

  return stored;
};

const getStoredChum = (
  trap: WaterTrapName | undefined,
  state: GameState,
): CrustaceanChum | undefined => {
  if (!trap) return undefined;

  const stored = safeLocalStorage.get<CrustaceanChum>(LAST_CHUM_KEY);
  if (!stored) return undefined;

  const items = {
    ...getBasketItems(state.inventory),
    ...getChestItems(state),
  };
  const isValid =
    WATER_TRAP[trap].chums.includes(stored) && (items[stored]?.gte(1) ?? false);

  return isValid ? stored : undefined;
};

interface Props {

Review comment (suggestion):
instead of undefined can we set "Crab Pot" as deafult here?

<img width="558" height="246" alt="Image" src="https://github.com/user-attachments/assets/21328bbe-1693-45d9-9045-c5e03f0f1083" />

Code after:
        : null;
    } catch {
      return null;
    }
  },
  set(key: string, value: string): void {
    try {
      if (typeof window !== "undefined") localStorage.setItem(key, value);
    } catch {
      // Safari private mode, quota exceeded, etc.
    }
  },
  remove(key: string): void {
    try {
      if (typeof window !== "undefined") localStorage.removeItem(key);
    } catch {
      // Safari private mode, etc.
    }
  },
};

const getStoredTrap = (canUseMarinerPot: boolean): WaterTrapName => {
  const stored = safeLocalStorage.get<WaterTrapName>(LAST_TRAP_KEY);
  if (!stored || !(stored in WATER_TRAP)) return "Crab Pot";
  if (stored === "Mariner Pot" && !canUseMarinerPot) return "Crab Pot";

  return stored;
};

const getStoredChum = (
  trap: WaterTrapName | undefined,
  state: GameState,
): CrustaceanChum | undefined => {
  if (!trap) return undefined;

  const stored = safeLocalStorage.get<CrustaceanChum>(LAST_CHUM_KEY);
  if (!stored) return undefined;

  const items = {
    ...getBasketItems(state.inventory),
    ...getChestItems(state),
  };
  const isValid =
    WATER_TRAP[trap].chums.includes(stored) && (items[stored]?.gte(1) ?? false);

  return isValid ? stored : undefined;
};

interface Props {
  waterTrap?: WaterTrap;
  onPlace: (trapType: WaterTrapName, chum?: CrustaceanChum) => void;
Repository: sunflower-farmers/sunflower-farmers
File: src/features/auth/lib/authMachine.ts (TypeScript)

Code before:
export interface Context {
  user: Authentication;
  errorCode?: ErrorCode;
  transactionId?: string;
  visitingFarmId?: number;
  showPWAInstallPrompt?: boolean;
}

type StartEvent = Farm & {
  type: "START_GAME";
};

type ReturnEvent = {
  type: "RETURN";
};

type PWAInstallPromptShown = {
  type: "PWA_INSTALL_PROMPT_SHOWN";
};

type CreateFarmEvent = {
  type: "CREATE_FARM";
  donation?: number;
  captcha?: string;
  hasEnoughMatic?: boolean;
  equipment?: BumpkinParts;
};

type LoadFarmEvent = {
  type: "LOAD_FARM";
};

type ConnectedWalletEvent = {
  type: "CONNECTED";
  address: string;
  signature: string;
};

type ClaimFarmEvent = {
  type: "CLAIM";
  id: number;
};

export type BlockchainEvent =
  | StartEvent
  | ReturnEvent
  | CreateFarmEvent
  | LoadFarmEvent
  | ConnectedWalletEvent
  | PWAInstallPromptShown
  | {

Review comment (suggestion):
Is there a case where we now call create farm with an undefined `equipment` in the front-end? Consider making this required.

Code after:
export interface Context {
  user: Authentication;
  errorCode?: ErrorCode;
  transactionId?: string;
  visitingFarmId?: number;
  showPWAInstallPrompt?: boolean;
}

type StartEvent = Farm & {
  type: "START_GAME";
};

type ReturnEvent = {
  type: "RETURN";
};

type PWAInstallPromptShown = {
  type: "PWA_INSTALL_PROMPT_SHOWN";
};

export type CreateFarmEvent = {
  type: "CREATE_FARM";
  donation?: number;
  captcha?: string;
  hasEnoughMatic?: boolean;
  equipment: BumpkinParts;
};

type LoadFarmEvent = {
  type: "LOAD_FARM";
};

type ConnectedWalletEvent = {
  type: "CONNECTED";
  address: string;
  signature: string;
};

type ClaimFarmEvent = {
  type: "CLAIM";
  id: number;
};

export type BlockchainEvent =
  | StartEvent
  | ReturnEvent
  | CreateFarmEvent
  | LoadFarmEvent
  | ConnectedWalletEvent
  | PWAInstallPromptShown
  | {
Repository: sunner/ChatALL
File: src/bots/Bot.js (JavaScript)

Code before:
import i18n from "@/i18n";
import store from "@/store";

export default class Bot {
  static _logoPackedPaths = null;
  static _isAvailable = false;

  static _brandId = "bot"; // Brand id of the bot, should be unique. Used in i18n.
  static _className = "Bot"; // Class name of the bot
  static _model = ""; // Model of the bot (eg. "text-davinci-002-render-sha")
  static _logoFolderName = "bots"; // Folder name for the logo. Leave it empty if the logo is in public/bots/
  static _logoFilename = "default-logo.svg"; // Place it in public/bots/
  static _loginUrl = "undefined";
  static _userAgent = ""; // Empty string means using the default user agent
  static _lock = null; // AsyncLock for prompt requests. `new AsyncLock()` in the subclass as needed.
  static _settingsComponent = ""; // Vue component filename for settings
  static _outputFormat = "markdown"; // "markdown" or "html"

  constructor() {}

  static getInstance() {
    return new this();
  }

  getLogo() {
    return `${this.constructor._logoFolderName}/${this.constructor._logoFilename}`;
  }

  getBrandName() {
    const c = this.constructor;
    return i18n.global.t(`${c._brandId}.name`);
  }

  getModelName() {
    const c = this.constructor;
    const model = c._model.replace(/[^a-zA-Z0-9-_]/g, "");

Review comment (suggestion):
I can't understand this design.

1. `bots` is a fixed folder name in the code. It need not be override by subclasses. For avoiding "magic number" problem, it could be defined as a global const, but not class member
2. The comment is not true. If leave it empty, all logos would be placed in /public/


Code after:
import i18n from "@/i18n";
import store from "@/store";

export default class Bot {
  static _logoPackedPaths = null;
  static _isAvailable = false;

  static _brandId = "bot"; // Brand id of the bot, should be unique. Used in i18n.
  static _className = "Bot"; // Class name of the bot
  static _model = ""; // Model of the bot (eg. "text-davinci-002-render-sha")
  static _logoFolderName = "bots"; // Folder name for the logo. Leave it empty if the logo is in public/bots/
  static _logoFilename = "default-logo.svg"; // Place it in public/bots/
  static _loginUrl = "undefined";
  static _userAgent = ""; // Empty string means using the default user agent
  static _lock = null; // AsyncLock for prompt requests. `new AsyncLock()` in the subclass as needed.
  static _settingsComponent = ""; // Vue component filename for settings
  static _outputFormat = "markdown"; // "markdown" or "html"

  constructor() {}

  static getInstance() {
    return new this();
  }

  getLogo() {
    return `bots/${this.constructor._logoFilename}`;
  }

  getBrandName() {
    const c = this.constructor;
    return i18n.global.t(`${c._brandId}.name`);
  }

  getModelName() {
    const c = this.constructor;
    const model = c._model.replace(/[^a-zA-Z0-9-_]/g, "");
Repository: sunner/ChatALL
File: src/i18n/index.js (JavaScript)

Code before:
import { createI18n } from "vue-i18n";

// Import stored language
import store from "../store";
var lang = store.state.lang;
if (lang == "auto") {
  lang = navigator.language || navigator.userLanguage || "en";
  lang = lang.substr(0, 2); // Only use the first two characters (e.g. "en")
}

// Import translation files here
import enMessages from "./locales/en.json";
import zhMessages from "./locales/zh.json";
import deMessages from "./locales/de.json";
import ruMessages from "./locales/ru.json";
import viMessages from "./locales/vi.json";
import frMessages from "./locales/fr.json";
import itMessages from "./locales/it.json";
import koMessages from "./locales/ko.json";
import koMessages from "./locales/es.json";

const messages = {
  en: enMessages,
  zh: zhMessages,
  de: deMessages,
  ru: ruMessages,
  vi: viMessages,
  it: itMessages,
  fr: frMessages,
  ko: koMessages,
  es: esMessages,  
};

const i18n = createI18n({
  legacy: false, // Vuetify does not support the legacy mode of vue-i18n
  locale: lang,
  fallbackLocale: "en",
  messages,
});

export default i18n;


Review comment (suggestion):
```suggestion
import esMessages from "./locales/es.json";
```

Code after:
import { createI18n } from "vue-i18n";

// Import stored language
import store from "../store";
var lang = store.state.lang;
if (lang == "auto") {
  lang = navigator.language || navigator.userLanguage || "en";
  lang = lang.substr(0, 2); // Only use the first two characters (e.g. "en")
}

// Import translation files here
import enMessages from "./locales/en.json";
import zhMessages from "./locales/zh.json";
import deMessages from "./locales/de.json";
import ruMessages from "./locales/ru.json";
import viMessages from "./locales/vi.json";
import frMessages from "./locales/fr.json";
import itMessages from "./locales/it.json";
import koMessages from "./locales/ko.json";
import esMessages from "./locales/es.json";

const messages = {
  en: enMessages,
  zh: zhMessages,
  de: deMessages,
  ru: ruMessages,
  vi: viMessages,
  it: itMessages,
  fr: frMessages,
  ko: koMessages,
  es: esMessages,  
};

const i18n = createI18n({
  legacy: false, // Vuetify does not support the legacy mode of vue-i18n
  locale: lang,
  fallbackLocale: "en",
  messages,
});

export default i18n;