aboutsummaryrefslogtreecommitdiffstats
path: root/site/src/components
diff options
context:
space:
mode:
authorPinapelz <yukais@pinapelz.com>2025-10-07 17:25:43 -0700
committerPinapelz <yukais@pinapelz.com>2025-10-07 17:25:50 -0700
commitd7b5b81b5d6ec55d0847b5171c3800a8f7b5c001 (patch)
treed646d8339602599eee64910cd252de0df595bcfe /site/src/components
parent014443ef502eee0c337a5feb2aa0aeebb8d51557 (diff)
feat: add i18n translation (initial JP and EN)
Diffstat (limited to 'site/src/components')
-rw-r--r--site/src/components/GameNotes.tsx142
-rw-r--r--site/src/components/LanguageSwitcher.tsx109
-rw-r--r--site/src/components/NewsFeed.tsx14
-rw-r--r--site/src/components/TitleBar.tsx10
4 files changed, 180 insertions, 95 deletions
diff --git a/site/src/components/GameNotes.tsx b/site/src/components/GameNotes.tsx
index b9ab8c6..999bf7b 100644
--- a/site/src/components/GameNotes.tsx
+++ b/site/src/components/GameNotes.tsx
@@ -5,17 +5,16 @@ import {
AimeIntlMaintenanceInfo,
AllnetPrivateServerWarning,
} from "./NoteModals";
+import i18next from 'i18next';
export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
sdvx: (
<>
<ul className={`mt-2 ${isMoe ? "text-pink-900" : "text-white"}`}>
- <li>
- • [USA] PREMIUM GENERATOR gacha available only ONLINE (No PASELI)
- </li>
- <li>• VP/VOLTEFACTORY rewards only available in Japan</li>
- <li>• [USA] Some cover art and/or charts have been removed </li>
- <li>• Official Online play is cross-region (including Japan)</li>
+ <li>{i18next.t('gamenotes.sdvx.premium_generator')}</li>
+ <li>{i18next.t('gamenotes.sdvx.voltefactory')}</li>
+ <li>{i18next.t('gamenotes.sdvx.cover_art')}</li>
+ <li>{i18next.t('gamenotes.sdvx.crossregion')}</li>
</ul>
<div className="flex justify-center">
<EamuseMaintenancePopup isMoe={isMoe} />
@@ -23,20 +22,16 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official e-amusement service in NA available only at Round1 USA
+ {i18next.t('gamenotes.common.na_service_note')}
<br />
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
iidx: (
<>
<ul className={`mt-2 ${isMoe ? "text-pink-900" : "text-white"}`}>
- <li>
- • [USA] Certain e-amusement features such as video upload
- unavailable{" "}
- </li>
+ <li>{i18next.t('gamenotes.iidx.features')}</li>
</ul>
<div className="flex justify-center">
<EamuseMaintenancePopup isMoe={isMoe} />
@@ -44,10 +39,9 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official e-amusement service in NA available only at Round1 USA
+ {i18next.t('gamenotes.common.na_service_note')}
<br />
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
@@ -59,10 +53,9 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official e-amusement service in NA available only at Round1 USA
+ {i18next.t('gamenotes.common.na_service_note')}
<br />
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
@@ -74,10 +67,9 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official e-amusement service in NA available only at Round1 USA
+ {i18next.t('gamenotes.common.na_service_note')}
<br />
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
@@ -89,10 +81,9 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official e-amusement service in NA available only at Round1 USA
+ {i18next.t('gamenotes.common.na_service_note')}
<br />
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
@@ -104,7 +95,7 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official e-amusement service only in Japan.
+ {i18next.t('gamenotes.polaris_chord.online_note')}
</p>
</>
),
@@ -116,12 +107,11 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official e-amusement service in NA available only at Round1 USA
+ {i18next.t('gamenotes.common.na_service_note')}
<br />
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
<br />
- Note that USA GOLD cabinets follow Japanese daily maintenance schedule.
+ {i18next.t('gamenotes.ddr.maintenance_note')}
</p>
</>
),
@@ -130,14 +120,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- Online only in Japan and Asia regions. No online service in the US (only
- old versions running offline-kit)
+ {i18next.t('gamenotes.jubeat.online_note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
@@ -146,14 +134,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- Online only in Japan and Asia regions. Japan and Asia only. No online
- service in the US (only old versions running offline-kit)
+ {i18next.t('gamenotes.popn_music.online_note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
@@ -162,14 +148,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- Online only in Japan and Asia regions. Japan and Asia only. No online
- service in the US
+ {i18next.t('gamenotes.nostalgia.online_note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Online Cabinets in non-supported regions (CAN/EU/AUS) are on private
- networks which run older data
+ {i18next.t('gamenotes.common.private_network_note')}
</p>
</>
),
@@ -178,12 +162,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- This version of the game is only available in Japan
+ {i18next.t('gamenotes.common.japan_only_note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- You may be on the International version if you are outside of Japan
+ {i18next.t('gamenotes.common.international_note')}
</p>
</>
),
@@ -192,12 +176,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- This version of the game is only available in Japan
+ {i18next.t('gamenotes.common.japan_only_note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- You may be on the International version if you are outside of Japan
+ {i18next.t('gamenotes.common.international_note')}
</p>
</>
),
@@ -206,12 +190,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- Official service only in Japan. No International Version
+ {i18next.t('gamenotes.ongeki_jp.japan_only')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- You are on a private network if the cabinet is not in Japan
+ {i18next.t('gamenotes.ongeki_jp.private_network')}
</p>
<div className="flex justify-center">
<AllnetPrivateServerWarning isMoe={isMoe} />
@@ -223,32 +207,29 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- Official service only in Japan. No International Version
+ {i18next.t('gamenotes.idac.japan_only')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- You are on a private network if the cabinet is not in Japan
+ {i18next.t('gamenotes.idac.private_network')}
</p>
</>
),
chunithm_intl: (
<>
<ul className={`mt-2 ${isMoe ? "text-pink-900" : "text-white"}`}>
- <li>
- • Updates behind JP version. International and JP are completely
- seperated
- </li>
+ <li>{i18next.t('gamenotes.chunithm_intl.updates')}</li>
</ul>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- No official service in NA or EU.{" "}
+ {i18next.t('gamenotes.chunithm_intl.no_service')}{" "}
<a
className="underline"
href="https://location.am-all.net/alm/location?gm=104&lang=en"
>
- See supported regions here
+ {i18next.t('gamenotes.chunithm_intl.regions_link')}
</a>
</p>
<div className="flex justify-center">
@@ -262,29 +243,24 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<AimeIntlMaintenanceInfo isMoe={isMoe} />
</div>
<ul className={`mt-2 ${isMoe ? "text-pink-900" : "text-white"}`}>
- <li>
- • Updates behind JP version. International and JP are completely
- seperated
- </li>
- <li>
- • Certain charts are removed from USA region
- </li>
+ <li>{i18next.t('gamenotes.maimaidx_intl.updates')}</li>
+ <li>{i18next.t('gamenotes.maimaidx_intl.charts')}</li>
</ul>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Official service in USA/CAN/ASIA{" "}
+ {i18next.t('gamenotes.maimaidx_intl.service')}{" "}
<a
className="underline"
href="https://location.am-all.net/alm/location?gm=98"
>
- See supported regions here
+ {i18next.t('gamenotes.maimaidx_intl.regions_link')}
</a>
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- (No official service in EU)
+ {i18next.t('gamenotes.maimaidx_intl.no_eu')}
</p>
<div className="flex justify-center">
<AllnetPrivateServerWarning isMoe={isMoe} />
@@ -299,7 +275,7 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- Online service available only at Round1 Japan and Round1 USA locations
+ {i18next.t('gamenotes.music_diver.online_service')}
</p>
</>
),
@@ -311,7 +287,7 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-center`}
>
- Online service in USA only at Round1 locations
+ {i18next.t('gamenotes.street_fighter.online_service')}
</p>
</>
),
@@ -320,14 +296,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-white"} text-center`}
>
- WACCA PLUS is a community continuation of WACCA REVERSE after online
- services ended in 2022
+ {i18next.t('gamenotes.wacca_plus.community')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Runs on Mythos networked cabs. Not all cabinets have WACCA PLUS as these
- updates are opt-in by operators.
+ {i18next.t('gamenotes.wacca_plus.note')}
</p>
</>
),
@@ -336,19 +310,18 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-white"} text-center`}
>
- MÚSECA PLUS is a fan continuation project for MÚSECA 1+1/2.
+ {i18next.t('gamenotes.museca_plus.community')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Runs on various e-amusement private networks. Not all cabinets have
- MÚSECA PLUS as it is opt-in.
+ {i18next.t('gamenotes.museca_plus.note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
<a className="underline" href="https://museca.plus/downloads">
- You can also download it as a data_mod
+ {i18next.t('gamenotes.museca_plus.download')}
</a>
</p>
</>
@@ -358,19 +331,17 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-white"} text-center`}
>
- A continuation of the abandoned iOS version of REFLEC BEAT (REFLEC BEAT
- plus)
+ {i18next.t('gamenotes.rb_deluxe_plus.community')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Needs to be sideloaded once you get a hold of the IPA. Network features
- supported. iOS ONLY
+ {i18next.t('gamenotes.rb_deluxe_plus.note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- *Not in main feed as date data is unavailable from this source
+ {i18next.t('gamenotes.rb_deluxe_plus.feed_note')}
</p>
</>
),
@@ -379,12 +350,13 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-white"} text-center`}
>
- Information below only applies to the latest version of the game (LCD + Banapassport Reader)
+ {i18next.t('gamenotes.taiko.version_note')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- Maintenance time is 1am - 7am JST (i think?)<br/>Applies to USA cabs as well (9am - 3pm PST)
+ {i18next.t('gamenotes.taiko.maintenance')}<br/>
+ {i18next.t('gamenotes.taiko.usa_note')}
</p>
</>
),
@@ -393,12 +365,12 @@ export const GameNotes = (isMoe: boolean): Record<string, React.ReactNode> => ({
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-white"} text-center`}
>
- Singular news feed for NA, ASIA/OCE, and JPN
+ {i18next.t('gamenotes.wmmt.feed')}
</p>
<p
className={`mt-3 ${isMoe ? "text-pink-800" : "text-pink-300"} text-right`}
>
- All regions run different versions of the game
+ {i18next.t('gamenotes.wmmt.version')}
</p>
</>
),
diff --git a/site/src/components/LanguageSwitcher.tsx b/site/src/components/LanguageSwitcher.tsx
new file mode 100644
index 0000000..8cceb35
--- /dev/null
+++ b/site/src/components/LanguageSwitcher.tsx
@@ -0,0 +1,109 @@
+import { useTranslation } from 'react-i18next';
+import { useSearchParams } from 'react-router-dom';
+import { useRef, useState, useEffect } from 'react';
+
+const languages = [
+ { code: 'en', name: 'English' },
+ { code: 'ja', name: '日本語' }
+];
+
+interface LanguageSwitcherProps {
+ variant?: 'compact' | 'standard';
+}
+
+function LanguageSwitcher({ variant = 'standard' }: LanguageSwitcherProps) {
+ const { i18n } = useTranslation();
+ const [searchParams] = useSearchParams();
+ const isMoe = searchParams.has("moe");
+ const [isOpen, setIsOpen] = useState(false);
+ const dropdownRef = useRef<HTMLDivElement>(null);
+
+ const currentLanguage = languages.find(lang => lang.code === i18n.language) || languages[0];
+
+ // Close the dropdown when clicking outside
+ useEffect(() => {
+ const handleClickOutside = (event: MouseEvent) => {
+ if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
+ setIsOpen(false);
+ }
+ };
+
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, []);
+
+ return (
+ <div className="relative inline-block" ref={dropdownRef}>
+ <button
+ onClick={() => setIsOpen(!isOpen)}
+ className={`
+ flex items-center justify-between
+ transition-all duration-200 text-sm rounded
+ ${variant === 'compact' ? 'px-2 py-0.5 min-w-[80px]' : 'px-3 py-1.5 min-w-[100px]'}
+ ${isMoe
+ ? 'bg-pink-200 text-pink-800 hover:bg-pink-300'
+ : 'bg-gray-800 text-gray-300 hover:bg-gray-700 hover:text-white'
+ }
+ `}
+ aria-haspopup="true"
+ aria-expanded={isOpen}
+ >
+ <span>{currentLanguage.name}</span>
+ <span className="ml-1">
+ <svg
+ className={`h-4 w-4 transition-transform ${isOpen ? 'rotate-180' : ''}`}
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke="currentColor"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ strokeWidth={2}
+ d="M19 9l-7 7-7-7"
+ />
+ </svg>
+ </span>
+ </button>
+
+ {isOpen && (
+ <div
+ className={`
+ absolute right-0 mt-1 z-10 shadow-lg rounded-md overflow-hidden
+ ${variant === 'compact' ? 'w-24' : 'w-32'}
+ ${isMoe ? 'bg-pink-100 border border-pink-300' : 'bg-gray-800 border border-gray-700'}
+ `}
+ >
+ <div className="py-1">
+ {languages.map((lang) => (
+ <button
+ key={lang.code}
+ onClick={() => {
+ i18n.changeLanguage(lang.code);
+ setIsOpen(false);
+ }}
+ className={`
+ block w-full text-left px-4 py-2 text-sm
+ ${i18n.language === lang.code
+ ? isMoe
+ ? 'bg-pink-300 text-pink-800 font-medium'
+ : 'bg-purple-700 text-white font-medium'
+ : isMoe
+ ? 'text-pink-800 hover:bg-pink-200'
+ : 'text-gray-300 hover:bg-gray-700 hover:text-white'
+ }
+ `}
+ >
+ {lang.name}
+ </button>
+ ))}
+ </div>
+ </div>
+ )}
+ </div>
+ );
+}
+
+export default LanguageSwitcher;
diff --git a/site/src/components/NewsFeed.tsx b/site/src/components/NewsFeed.tsx
index 7cf5a08..2e08b16 100644
--- a/site/src/components/NewsFeed.tsx
+++ b/site/src/components/NewsFeed.tsx
@@ -1,6 +1,7 @@
import { useState, useEffect } from "react";
import { getGameTitle, getShortenedGameName } from "../utils.ts";
import { useSearchParams } from "react-router-dom";
+import { useTranslation } from "react-i18next";
export interface NewsData {
date: string;
@@ -24,6 +25,7 @@ interface NewsFeedProps {
}
export const NewsFeed: React.FC<NewsFeedProps> = ({ newsItems }) => {
+ const { t } = useTranslation();
const [showEnglish, setShowEnglish] = useState<Record<string, boolean>>({});
const [expanded, setExpanded] = useState<Record<string, boolean>>({});
const [currentImageIndex, setCurrentImageIndex] = useState<
@@ -168,7 +170,7 @@ export const NewsFeed: React.FC<NewsFeedProps> = ({ newsItems }) => {
onClick={() => toggleLanguage(newsId)}
className={`${isMoe ? "bg-pink-200 hover:bg-pink-300" : "bg-gray-800 hover:bg-gray-700"} text-xs py-1 px-2 rounded`}
>
- {isEnglish ? "View Original" : "View in English"}
+ {isEnglish ? t("view_in_original_text") : t("view_in_english_text")}
</button>
)}
</div>
@@ -233,13 +235,13 @@ export const NewsFeed: React.FC<NewsFeedProps> = ({ newsItems }) => {
: `${window.location.origin}${pathname === "/news" ? "" : pathname}#${newsId}`;
navigator.clipboard.writeText(url);
alert(
- "Copied Direct Link to Post (Older news are automatically culled after some time)",
+ `${t('copy_link_notif')}`
);
}}
title="Copy permalink"
className="text-xs text-blue-400 hover:underline cursor-pointer"
>
- 🔗 Copy Link to Post
+ 🔗 {`${t('copy_link_to_post')}`}
</a>
</div>
@@ -248,8 +250,7 @@ export const NewsFeed: React.FC<NewsFeedProps> = ({ newsItems }) => {
<div
className={`${isMoe ? "bg-pink-200 text-pink-800" : "bg-gray-800 text-white"} px-3 py-2 text-xs text-center`}
>
- The information above is written by AI /
- 上記の情報はAIによって生成されました。
+ {`${t('ai_summary_note')}`}
</div>
)}
@@ -258,8 +259,7 @@ export const NewsFeed: React.FC<NewsFeedProps> = ({ newsItems }) => {
<div
className={`${isMoe ? "bg-pink-200 text-pink-800" : "bg-gray-800 text-white"} px-3 py-2 text-xs text-center`}
>
- The information above is machine translated and may contain
- inaccuracies
+ {`${t('machine_tl_note')}`}
</div>
)}
diff --git a/site/src/components/TitleBar.tsx b/site/src/components/TitleBar.tsx
index 2229a45..3822980 100644
--- a/site/src/components/TitleBar.tsx
+++ b/site/src/components/TitleBar.tsx
@@ -5,12 +5,15 @@ import {
useNavigate,
useLocation,
} from "react-router-dom";
+import LanguageSwitcher from "./LanguageSwitcher";
+import { useTranslation } from "react-i18next";
const TitleBar: React.FC = () => {
const [searchParams] = useSearchParams();
const navigate = useNavigate();
const location = useLocation();
const isMoe = searchParams.has("moe");
+ const { t } = useTranslation();
const toggleTheme = () => {
const params = new URLSearchParams(searchParams);
@@ -56,7 +59,7 @@ const TitleBar: React.FC = () => {
onClick={toggleTheme}
className={`text-sm ${isMoe ? "bg-pink-100 text-pink-800 hover:bg-pink-200 hover:text-pink-600" : "bg-gray-800 text-gray-300 hover:bg-gray-700 hover:text-white"} font-medium px-3 py-1 rounded`}
>
- {isMoe ? "🌙 Dark" : "🌸 Light"}
+ {isMoe ? "🌙 "+t('dark_theme_text') : "🌸 "+t("light_theme_text")}
</button>
<img
src="/rasis.webp"
@@ -81,14 +84,15 @@ const TitleBar: React.FC = () => {
to={`/${isMoe ? "?moe" : ""}`}
className={`${isMoe ? "text-pink-800 hover:text-pink-600" : "text-gray-300 hover:text-white"} font-medium text-sm sm:text-base`}
>
- Main News Feed
+ {t('news_feed')}
</Link>
<Link
to={`/games${isMoe ? "?moe" : ""}`}
className={`${isMoe ? "text-pink-800 hover:text-pink-600" : "text-gray-300 hover:text-white"} font-medium text-sm sm:text-base`}
>
- Game Selector
+ {t('game_selector')}
</Link>
+ <LanguageSwitcher variant="compact" />
</div>
</div>
</div>
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage