feat(i18n): internationalize games page and tutorial content

- Add full translations for /games page (6 languages)
  - Created translation files: en, de, ja, hi, es, la
  - Internationalized all sections: hero, arcade, champions, dashboard, CTA
  - Implemented message interpolation for dynamic content

- Internationalize tutorial step content
  - Added step content translations to all tutorial locale files
  - Updated tutorialConverter.ts to accept and use translations
  - Modified homepage to pass tutorial translations to converter
  - Tutorial now displays in user's selected language

All translations follow established i18n patterns with co-located messages
and server-side loading for FOUC prevention.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-11-01 17:27:46 -05:00
parent 8ea7771139
commit 4253964af1
16 changed files with 1105 additions and 47 deletions

View File

@ -2,6 +2,7 @@
import Link from 'next/link'
import { useRouter } from 'next/navigation'
import { useTranslations } from 'next-intl'
import React from 'react'
import { PageWithNav } from '@/components/PageWithNav'
import { css } from '../../../styled-system/css'
@ -10,6 +11,7 @@ import { useGameMode } from '../../contexts/GameModeContext'
import { useUserProfile } from '../../contexts/UserProfileContext'
function GamesPageContent() {
const t = useTranslations('games')
const { profile } = useUserProfile()
const { gameMode, getAllPlayers } = useGameMode()
const { enterFullscreen } = useFullscreen()
@ -78,7 +80,7 @@ function GamesPageContent() {
display: 'inline-block',
})}
>
🕹 Soroban Arcade
{t('hero.title')}
</h1>
{/* Floating score indicators */}
@ -105,7 +107,7 @@ function GamesPageContent() {
boxShadow: '0 4px 15px rgba(251, 191, 36, 0.3)',
})}
>
+100 XP
{t('hero.xpBadge')}
</div>
<div
className={css({
@ -123,7 +125,7 @@ function GamesPageContent() {
boxShadow: '0 3px 10px rgba(239, 68, 68, 0.3)',
})}
>
STREAK!
{t('hero.streakBadge')}
</div>
</div>
</div>
@ -138,7 +140,7 @@ function GamesPageContent() {
mb: '6',
})}
>
Level up your mental math powers in the most fun way possible!
{t('hero.subtitle')}
</p>
{/* Playful stats */}
@ -172,7 +174,7 @@ function GamesPageContent() {
color: 'gray.700',
})}
>
Challenge Your Brain
{t('hero.features.challenge')}
</span>
</div>
<div
@ -196,7 +198,7 @@ function GamesPageContent() {
color: 'gray.700',
})}
>
Build Speed
{t('hero.features.speed')}
</span>
</div>
<div
@ -220,7 +222,7 @@ function GamesPageContent() {
color: 'gray.700',
})}
>
Unlock Achievements
{t('hero.features.achievements')}
</span>
</div>
</div>
@ -272,7 +274,7 @@ function GamesPageContent() {
mb: '4',
})}
>
🏟 Ready for the Arena?
{t('enterArcade.title')}
</h2>
<p
@ -284,7 +286,7 @@ function GamesPageContent() {
mx: 'auto',
})}
>
Select your champions, choose your battles, and dive into full-screen arcade action!
{t('enterArcade.description')}
</p>
<button
@ -348,7 +350,9 @@ function GamesPageContent() {
})} button-glow`}
/>
<span className={css({ position: 'relative', zIndex: 1 })}>🚀 ENTER ARCADE</span>
<span className={css({ position: 'relative', zIndex: 1 })}>
{t('enterArcade.button')}
</span>
</button>
<p
@ -358,7 +362,7 @@ function GamesPageContent() {
mt: '4',
})}
>
Full-screen experience with immersive gameplay
{t('enterArcade.subtitle')}
</p>
</div>
</div>
@ -384,7 +388,7 @@ function GamesPageContent() {
mb: '2',
})}
>
🏆 Your Arcade Champions
{t('champions.title')}
</h2>
<p
className={css({
@ -392,7 +396,7 @@ function GamesPageContent() {
fontSize: 'lg',
})}
>
Track your progress and achievements!
{t('champions.subtitle')}
</p>
</div>
@ -551,7 +555,7 @@ function GamesPageContent() {
})}
style={{ color: theme.statColor }}
>
GAMES PLAYED
{t('champions.stats.gamesPlayed')}
</div>
</div>
@ -581,7 +585,7 @@ function GamesPageContent() {
fontWeight: 'semibold',
})}
>
VICTORIES
{t('champions.stats.victories')}
</div>
</div>
</div>
@ -607,7 +611,9 @@ function GamesPageContent() {
})}
style={{ color: theme.levelColor }}
>
Level {Math.floor(profile.gamesPlayed / 5) + 1}
{t('champions.stats.level', {
level: Math.floor(profile.gamesPlayed / 5) + 1,
})}
</span>
<span
className={css({
@ -615,7 +621,10 @@ function GamesPageContent() {
})}
style={{ color: theme.levelColor }}
>
{profile.gamesPlayed % 5}/5 XP
{t('champions.stats.xp', {
current: profile.gamesPlayed % 5,
total: 5,
})}
</span>
</div>
<div
@ -726,7 +735,7 @@ function GamesPageContent() {
mb: '2',
})}
>
🥊 Head-to-Head
{t('dashboard.headToHead.title')}
</h3>
<p
className={css({
@ -734,7 +743,7 @@ function GamesPageContent() {
color: 'gray.600',
})}
>
Battle Record
{t('dashboard.headToHead.subtitle')}
</p>
</div>
@ -777,7 +786,7 @@ function GamesPageContent() {
})}
style={{ color: player.color }}
>
WINS
{t('dashboard.headToHead.wins')}
</div>
</div>
@ -795,7 +804,7 @@ function GamesPageContent() {
fontWeight: 'semibold',
})}
>
VS
{t('dashboard.headToHead.vs')}
</div>
</div>
)}
@ -810,7 +819,7 @@ function GamesPageContent() {
color: 'gray.600',
})}
>
Last played: Memory Lightning
{t('dashboard.headToHead.lastPlayed')}
</div>
</div>
@ -845,7 +854,7 @@ function GamesPageContent() {
mb: '2',
})}
>
🏆 Recent Achievements
{t('dashboard.achievements.title')}
</h3>
<p
className={css({
@ -853,7 +862,7 @@ function GamesPageContent() {
color: 'gray.600',
})}
>
Latest unlocks
{t('dashboard.achievements.subtitle')}
</p>
</div>
@ -892,7 +901,9 @@ function GamesPageContent() {
})}
style={{ color: idx === 0 ? '#92400e' : '#581c87' }}
>
{idx === 0 ? '🔥 First Win!' : '⚡ Speed Demon'}
{idx === 0
? t('dashboard.achievements.firstWin.title')
: t('dashboard.achievements.speedDemon.title')}
</div>
<div
className={css({
@ -900,7 +911,9 @@ function GamesPageContent() {
})}
style={{ color: idx === 0 ? '#a16207' : '#6b21a8' }}
>
{idx === 0 ? 'Victory in Battle Arena' : 'Sub-5 second memory'}
{idx === 0
? t('dashboard.achievements.firstWin.description')
: t('dashboard.achievements.speedDemon.description')}
</div>
</div>
</div>
@ -939,7 +952,7 @@ function GamesPageContent() {
mb: '2',
})}
>
Active Challenges
{t('dashboard.challenges.title')}
</h3>
<p
className={css({
@ -947,7 +960,7 @@ function GamesPageContent() {
color: 'gray.600',
})}
>
Friendly competition
{t('dashboard.challenges.subtitle')}
</p>
</div>
@ -978,7 +991,7 @@ function GamesPageContent() {
fontWeight: 'semibold',
})}
>
challenges
{t('dashboard.challenges.challengesText')}
</span>
<span className={css({ fontSize: 'lg' })}>{allPlayers[1].emoji}</span>
</div>
@ -989,7 +1002,7 @@ function GamesPageContent() {
fontWeight: 'medium',
})}
>
"Beat my Memory Lightning score!"
"{t('dashboard.challenges.exampleChallenge')}"
</div>
<div
className={css({
@ -998,7 +1011,7 @@ function GamesPageContent() {
mt: '1',
})}
>
Current best: 850 points
{t('dashboard.challenges.currentBest', { score: 850 })}
</div>
</div>
)}
@ -1023,7 +1036,7 @@ function GamesPageContent() {
},
})}
>
🎯 Create New Challenge
{t('dashboard.challenges.createButton')}
</button>
</div>
</div>
@ -1047,7 +1060,7 @@ function GamesPageContent() {
mb: '4',
})}
>
🚀 Ready to Begin Your Journey?
{t('callToAction.title')}
</h2>
<p
className={css({
@ -1055,7 +1068,7 @@ function GamesPageContent() {
mb: '6',
})}
>
Start with our interactive guide and unlock the secrets of the ancient calculator!
{t('callToAction.description')}
</p>
<Link
href="/guide"
@ -1072,7 +1085,7 @@ function GamesPageContent() {
_hover: { bg: 'blue.700', transform: 'translateY(-1px)' },
})}
>
Start Learning
{t('callToAction.button')}
</Link>
</div>
</div>

View File

@ -76,8 +76,9 @@ function MiniAbacus({
export default function HomePage() {
const t = useTranslations('home')
const tutorialT = useTranslations('tutorial')
const [selectedSkillIndex, setSelectedSkillIndex] = useState(1) // Default to "Friends techniques"
const fullTutorial = getTutorialForEditor()
const fullTutorial = getTutorialForEditor(tutorialT.raw(''))
// Create different tutorials for each skill level
const skillTutorials = [

View File

@ -0,0 +1,65 @@
{
"games": {
"hero": {
"title": "🕹️ Soroban Spielhalle",
"subtitle": "Verbessern Sie Ihre mentalen Mathematikfähigkeiten auf die unterhaltsamste Weise!",
"xpBadge": "+100 EP",
"streakBadge": "SERIE!",
"features": {
"challenge": "🎯 Fordern Sie Ihr Gehirn heraus",
"speed": "⚡ Geschwindigkeit aufbauen",
"achievements": "🏆 Erfolge freischalten"
}
},
"enterArcade": {
"title": "🏟️ Bereit für die Arena?",
"description": "Wählen Sie Ihre Champions, wählen Sie Ihre Kämpfe und tauchen Sie ein in Vollbild-Action!",
"button": "🚀 SPIELHALLE BETRETEN",
"subtitle": "Vollbild-Erlebnis mit immersivem Gameplay"
},
"champions": {
"title": "🏆 Ihre Spielhallen-Champions",
"subtitle": "Verfolgen Sie Ihren Fortschritt und Ihre Erfolge!",
"stats": {
"gamesPlayed": "GESPIELTE SPIELE",
"victories": "SIEGE",
"level": "Stufe {level}",
"xp": "{current}/{total} EP"
}
},
"dashboard": {
"headToHead": {
"title": "🥊 Kopf-an-Kopf",
"subtitle": "Kampfbilanz",
"vs": "GEGEN",
"wins": "SIEGE",
"lastPlayed": "Zuletzt gespielt: Memory Blitz ⚡"
},
"achievements": {
"title": "🏆 Neueste Erfolge",
"subtitle": "Neueste Freischaltungen",
"firstWin": {
"title": "🔥 Erster Sieg!",
"description": "Sieg in der Kampfarena"
},
"speedDemon": {
"title": "⚡ Geschwindigkeitsdämon",
"description": "Unter 5 Sekunden Gedächtnis"
}
},
"challenges": {
"title": "⚔️ Aktive Herausforderungen",
"subtitle": "Freundschaftlicher Wettbewerb",
"challengesText": "fordert heraus",
"exampleChallenge": "Schlagen Sie meinen Memory Blitz-Rekord!",
"currentBest": "Aktueller Bestwert: {score} Punkte",
"createButton": "🎯 Neue Herausforderung erstellen"
}
},
"callToAction": {
"title": "🚀 Bereit, Ihre Reise zu beginnen?",
"description": "Beginnen Sie mit unserem interaktiven Leitfaden und enthüllen Sie die Geheimnisse des antiken Rechners!",
"button": "Lernen beginnen →"
}
}
}

View File

@ -0,0 +1,65 @@
{
"games": {
"hero": {
"title": "🕹️ Soroban Arcade",
"subtitle": "Level up your mental math powers in the most fun way possible!",
"xpBadge": "+100 XP",
"streakBadge": "STREAK!",
"features": {
"challenge": "🎯 Challenge Your Brain",
"speed": "⚡ Build Speed",
"achievements": "🏆 Unlock Achievements"
}
},
"enterArcade": {
"title": "🏟️ Ready for the Arena?",
"description": "Select your champions, choose your battles, and dive into full-screen arcade action!",
"button": "🚀 ENTER ARCADE",
"subtitle": "Full-screen experience with immersive gameplay"
},
"champions": {
"title": "🏆 Your Arcade Champions",
"subtitle": "Track your progress and achievements!",
"stats": {
"gamesPlayed": "GAMES PLAYED",
"victories": "VICTORIES",
"level": "Level {level}",
"xp": "{current}/{total} XP"
}
},
"dashboard": {
"headToHead": {
"title": "🥊 Head-to-Head",
"subtitle": "Battle Record",
"vs": "VS",
"wins": "WINS",
"lastPlayed": "Last played: Memory Lightning ⚡"
},
"achievements": {
"title": "🏆 Recent Achievements",
"subtitle": "Latest unlocks",
"firstWin": {
"title": "🔥 First Win!",
"description": "Victory in Battle Arena"
},
"speedDemon": {
"title": "⚡ Speed Demon",
"description": "Sub-5 second memory"
}
},
"challenges": {
"title": "⚔️ Active Challenges",
"subtitle": "Friendly competition",
"challengesText": "challenges",
"exampleChallenge": "Beat my Memory Lightning score!",
"currentBest": "Current best: {score} points",
"createButton": "🎯 Create New Challenge"
}
},
"callToAction": {
"title": "🚀 Ready to Begin Your Journey?",
"description": "Start with our interactive guide and unlock the secrets of the ancient calculator!",
"button": "Start Learning →"
}
}
}

View File

@ -0,0 +1,65 @@
{
"games": {
"hero": {
"title": "🕹️ Arcade Soroban",
"subtitle": "¡Mejora tus poderes de cálculo mental de la manera más divertida posible!",
"xpBadge": "+100 EXP",
"streakBadge": "¡RACHA!",
"features": {
"challenge": "🎯 Desafía tu cerebro",
"speed": "⚡ Aumenta la velocidad",
"achievements": "🏆 Desbloquea logros"
}
},
"enterArcade": {
"title": "🏟️ ¿Listo para la arena?",
"description": "¡Selecciona tus campeones, elige tus batallas y sumérgete en la acción arcade de pantalla completa!",
"button": "🚀 ENTRAR AL ARCADE",
"subtitle": "Experiencia de pantalla completa con juego inmersivo"
},
"champions": {
"title": "🏆 Tus campeones del arcade",
"subtitle": "¡Rastrea tu progreso y logros!",
"stats": {
"gamesPlayed": "JUEGOS JUGADOS",
"victories": "VICTORIAS",
"level": "Nivel {level}",
"xp": "{current}/{total} EXP"
}
},
"dashboard": {
"headToHead": {
"title": "🥊 Cara a cara",
"subtitle": "Récord de batallas",
"vs": "VS",
"wins": "VICTORIAS",
"lastPlayed": "Último juego: Relámpago de memoria ⚡"
},
"achievements": {
"title": "🏆 Logros recientes",
"subtitle": "Últimos desbloqueados",
"firstWin": {
"title": "🔥 ¡Primera victoria!",
"description": "Victoria en la arena de batalla"
},
"speedDemon": {
"title": "⚡ Demonio de velocidad",
"description": "Memoria de menos de 5 segundos"
}
},
"challenges": {
"title": "⚔️ Desafíos activos",
"subtitle": "Competencia amistosa",
"challengesText": "desafía",
"exampleChallenge": "¡Supera mi puntuación de Relámpago de memoria!",
"currentBest": "Mejor actual: {score} puntos",
"createButton": "🎯 Crear nuevo desafío"
}
},
"callToAction": {
"title": "🚀 ¿Listo para comenzar tu viaje?",
"description": "¡Comienza con nuestra guía interactiva y desbloquea los secretos de la calculadora antigua!",
"button": "Comenzar a aprender →"
}
}
}

View File

@ -0,0 +1,65 @@
{
"games": {
"hero": {
"title": "🕹️ सोरोबान आर्केड",
"subtitle": "सबसे मज़ेदार तरीके से अपनी मानसिक गणित शक्तियों को बढ़ाएं!",
"xpBadge": "+100 एक्सपी",
"streakBadge": "स्ट्रीक!",
"features": {
"challenge": "🎯 अपने दिमाग को चुनौती दें",
"speed": "⚡ गति बढ़ाएं",
"achievements": "🏆 उपलब्धियां अनलॉक करें"
}
},
"enterArcade": {
"title": "🏟️ एरीना के लिए तैयार हैं?",
"description": "अपने चैंपियंस चुनें, अपनी लड़ाई चुनें, और पूर्ण-स्क्रीन आर्केड एक्शन में गोता लगाएं!",
"button": "🚀 आर्केड में प्रवेश करें",
"subtitle": "इमर्सिव गेमप्ले के साथ पूर्ण-स्क्रीन अनुभव"
},
"champions": {
"title": "🏆 आपके आर्केड चैंपियंस",
"subtitle": "अपनी प्रगति और उपलब्धियों को ट्रैक करें!",
"stats": {
"gamesPlayed": "खेले गए गेम",
"victories": "जीत",
"level": "स्तर {level}",
"xp": "{current}/{total} एक्सपी"
}
},
"dashboard": {
"headToHead": {
"title": "🥊 आमने-सामने",
"subtitle": "लड़ाई का रिकॉर्ड",
"vs": "बनाम",
"wins": "जीत",
"lastPlayed": "आखिरी खेल: मेमोरी लाइटनिंग ⚡"
},
"achievements": {
"title": "🏆 हाल की उपलब्धियां",
"subtitle": "नवीनतम अनलॉक",
"firstWin": {
"title": "🔥 पहली जीत!",
"description": "बैटल एरीना में जीत"
},
"speedDemon": {
"title": "⚡ स्पीड डेमन",
"description": "5 सेकंड से कम याददाश्त"
}
},
"challenges": {
"title": "⚔️ सक्रिय चुनौतियां",
"subtitle": "मैत्रीपूर्ण प्रतियोगिता",
"challengesText": "चुनौती देते हैं",
"exampleChallenge": "मेरी मेमोरी लाइटनिंग स्कोर को हराओ!",
"currentBest": "वर्तमान सर्वश्रेष्ठ: {score} अंक",
"createButton": "🎯 नई चुनौती बनाएं"
}
},
"callToAction": {
"title": "🚀 अपनी यात्रा शुरू करने के लिए तैयार हैं?",
"description": "हमारी इंटरैक्टिव गाइड से शुरू करें और प्राचीन कैलकुलेटर के रहस्यों को खोलें!",
"button": "सीखना शुरू करें →"
}
}
}

View File

@ -0,0 +1,65 @@
{
"games": {
"hero": {
"title": "🕹️ そろばんアーケード",
"subtitle": "最も楽しい方法で暗算力をレベルアップしましょう!",
"xpBadge": "+100 経験値",
"streakBadge": "連勝!",
"features": {
"challenge": "🎯 脳に挑戦",
"speed": "⚡ スピードを磨く",
"achievements": "🏆 実績を解除"
}
},
"enterArcade": {
"title": "🏟️ アリーナの準備はできましたか?",
"description": "チャンピオンを選び、戦いを選び、フルスクリーンアクションに飛び込もう!",
"button": "🚀 アーケードに入る",
"subtitle": "没入型ゲームプレイのフルスクリーン体験"
},
"champions": {
"title": "🏆 あなたのアーケードチャンピオン",
"subtitle": "進捗と実績を追跡しましょう!",
"stats": {
"gamesPlayed": "プレイしたゲーム",
"victories": "勝利",
"level": "レベル {level}",
"xp": "{current}/{total} 経験値"
}
},
"dashboard": {
"headToHead": {
"title": "🥊 一騎打ち",
"subtitle": "対戦記録",
"vs": "対",
"wins": "勝利",
"lastPlayed": "最後のプレイ: メモリーライトニング ⚡"
},
"achievements": {
"title": "🏆 最近の実績",
"subtitle": "最新の解除",
"firstWin": {
"title": "🔥 初勝利!",
"description": "バトルアリーナでの勝利"
},
"speedDemon": {
"title": "⚡ スピード魔神",
"description": "5秒以下の記憶"
}
},
"challenges": {
"title": "⚔️ アクティブなチャレンジ",
"subtitle": "友好的な競争",
"challengesText": "が挑戦",
"exampleChallenge": "私のメモリーライトニングスコアを破れ!",
"currentBest": "現在のベスト: {score}ポイント",
"createButton": "🎯 新しいチャレンジを作成"
}
},
"callToAction": {
"title": "🚀 旅を始める準備はできましたか?",
"description": "インタラクティブガイドから始めて、古代の計算機の秘密を解き明かしましょう!",
"button": "学習を開始 →"
}
}
}

View File

@ -0,0 +1,65 @@
{
"games": {
"hero": {
"title": "🕹️ Porticus Sorobani",
"subtitle": "Eleva potentias calculationis mentalis modo iucundissimo!",
"xpBadge": "+100 EP",
"streakBadge": "SERIES!",
"features": {
"challenge": "🎯 Provoca Mentem Tuam",
"speed": "⚡ Celerita Aedifica",
"achievements": "🏆 Res Gestas Resera"
}
},
"enterArcade": {
"title": "🏟️ Paratus es ad Arenam?",
"description": "Elige campiones tuos, certamina tua elige, et immergere in actionem porticis pleni visus!",
"button": "🚀 INTRA PORTICUM",
"subtitle": "Experientia pleni visus cum ludo immersivo"
},
"champions": {
"title": "🏆 Campiones Tui Porticis",
"subtitle": "Sequere progressum et res gestas tuas!",
"stats": {
"gamesPlayed": "LUDI ACTI",
"victories": "VICTORIAE",
"level": "Gradus {level}",
"xp": "{current}/{total} EP"
}
},
"dashboard": {
"headToHead": {
"title": "🥊 Caput ad Caput",
"subtitle": "Acta Certaminum",
"vs": "CONTRA",
"wins": "VICTORIAE",
"lastPlayed": "Ultimum lusum: Memoria Fulminis ⚡"
},
"achievements": {
"title": "🏆 Res Gestae Recentes",
"subtitle": "Novissime reserata",
"firstWin": {
"title": "🔥 Prima Victoria!",
"description": "Victoria in Arena Pugnae"
},
"speedDemon": {
"title": "⚡ Daemon Celeritatis",
"description": "Memoria sub 5 secundis"
}
},
"challenges": {
"title": "⚔️ Provocationes Activae",
"subtitle": "Contentio amica",
"challengesText": "provocat",
"exampleChallenge": "Supera puncta mea Memoriae Fulminis!",
"currentBest": "Optimum nunc: {score} puncta",
"createButton": "🎯 Crea Provocationem Novam"
}
},
"callToAction": {
"title": "🚀 Paratus Incipere Iter Tuum?",
"description": "Incipe cum duce nostro interactivo et resera arcana calculatoris antiqui!",
"button": "Incipe Discere →"
}
}
}

View File

@ -91,6 +91,113 @@
},
"formula": "{original} wird zu {expanded}",
"devWarning": "⚠ Zusammenfassung/Wächter stimmen nicht überein: {issues}"
},
"steps": {
"basic-1": {
"title": "Grundlegende Addition: 0 + 1",
"description": "Beginne, indem du deine erste Erdperle hinzufügst",
"actionDescription": "Klicke auf die erste Erdperle, um sie nach oben zu bewegen",
"tooltip": {
"content": "Erdperlen hinzufügen",
"explanation": "Erdperlen (unten) sind jeweils 1 wert. Schiebe sie NACH OBEN, um sie zu aktivieren."
}
},
"basic-2": {
"title": "Grundlegende Addition: 1 + 1",
"description": "Füge die zweite Erdperle hinzu, um 2 zu erhalten",
"actionDescription": "Klicke auf die zweite Erdperle, um sie nach oben zu bewegen",
"tooltip": {
"content": "Erdperlen aufbauen",
"explanation": "Füge Erdperlen nacheinander für die Zahlen 2, 3 und 4 hinzu"
}
},
"basic-3": {
"title": "Grundlegende Addition: 2 + 1",
"description": "Füge die dritte Erdperle hinzu, um 3 zu erhalten",
"actionDescription": "Klicke auf die dritte Erdperle, um sie nach oben zu bewegen",
"tooltip": {
"content": "Erdperlen der Reihe nach hinzufügen",
"explanation": "Füge Erdperlen nacheinander hinzu, bis du 4 erreichst"
}
},
"basic-4": {
"title": "Grundlegende Addition: 3 + 1",
"description": "Füge die vierte Erdperle hinzu, um 4 zu erhalten",
"actionDescription": "Klicke auf die vierte Erdperle, um 4 zu vervollständigen",
"tooltip": {
"content": "Maximale Erdperlen",
"explanation": "Vier Erdperlen sind das Maximum - als nächstes brauchen wir einen anderen Ansatz"
}
},
"heaven-intro": {
"title": "Himmelsperle: 0 + 5",
"description": "Verwende die Himmelsperle, um 5 darzustellen",
"actionDescription": "Klicke auf die Himmelsperle, um sie zu aktivieren",
"tooltip": {
"content": "Himmelsperle = 5",
"explanation": "Die einzelne Perle über dem Stab stellt 5 dar"
}
},
"heaven-plus-earth": {
"title": "Kombination: 5 + 1",
"description": "Addiere 1 zu 5, indem du eine Erdperle aktivierst",
"actionDescription": "Klicke auf die erste Erdperle, um 6 zu erhalten",
"tooltip": {
"content": "Himmel + Erde = 6",
"explanation": "Wenn du Platz im Erdbereich hast, füge einfach direkt hinzu"
}
},
"complement-intro": {
"title": "Fünferkomplement: 3 + 4",
"description": "Du musst 4 addieren, hast aber nur 1 Erdperlenplatz. Verwende Komplement: 4 = 5 - 1",
"actionDescription": "Füge zuerst die Himmelsperle (5) hinzu, dann entferne 1 Erdperle",
"tooltip": {
"content": "Fünferkomplement: 4 = 5 - 1",
"explanation": "Wenn du 4 addieren musst, aber nur 1 Platz hast, verwende: addiere 5, entferne 1"
},
"multiStepInstructions": [
"Klicke auf die Himmelsperle, um 5 hinzuzufügen",
"Klicke auf die erste Erdperle, um 1 zu entfernen"
]
},
"complement-2": {
"title": "Fünferkomplement: 2 + 3",
"description": "Addiere 3, um 5 zu erhalten, indem du das Komplement verwendest: 3 = 5 - 2",
"actionDescription": "Füge die Himmelsperle (5) hinzu, dann entferne 2 Erdperlen",
"tooltip": {
"content": "Fünferkomplement: 3 = 5 - 2",
"explanation": "Um 3 zu addieren, denke: 3 = 5 - 2, also addiere 5 und nimm 2 weg"
},
"multiStepInstructions": [
"Klicke auf die Himmelsperle, um 5 hinzuzufügen",
"Klicke auf die erste Erdperle, um sie zu entfernen",
"Klicke auf die zweite Erdperle, um sie zu entfernen"
]
},
"complex-1": {
"title": "Komplex: 6 + 2",
"description": "Addiere 2 weitere zu 6 (das Himmel + 1 Erde hat)",
"actionDescription": "Füge zwei weitere Erdperlen hinzu",
"tooltip": {
"content": "Direkte Addition, wenn möglich",
"explanation": "Wenn du Platz im Erdbereich hast, füge einfach direkt hinzu"
}
},
"complex-2": {
"title": "Komplex: 7 + 4",
"description": "Addiere 4 zu 7, aber kein Platz für 4 Erdperlen. Verwende wieder Komplement",
"actionDescription": "Füge Zehnerhimmel hinzu, dann leere die Einerstelle: entferne Himmel + 2 Erde",
"tooltip": {
"content": "Übertrag zur Zehnerstelle",
"explanation": "7 + 4 = 11, das benötigt die Himmelsperle der Zehnerspalte"
},
"multiStepInstructions": [
"Klicke auf die Himmelsperle in der Zehnerspalte (links)",
"Klicke auf die Himmelsperle in der Einerspalte, um sie zu entfernen",
"Klicke auf die erste Erdperle, um sie zu entfernen",
"Klicke auf die zweite Erdperle, um sie zu entfernen"
]
}
}
}
}

View File

@ -91,6 +91,113 @@
},
"formula": "{original} becomes {expanded}",
"devWarning": "⚠ Summary/guard mismatch: {issues}"
},
"steps": {
"basic-1": {
"title": "Basic Addition: 0 + 1",
"description": "Start by adding your first earth bead",
"actionDescription": "Click the first earth bead to move it up",
"tooltip": {
"content": "Adding earth beads",
"explanation": "Earth beads (bottom) are worth 1 each. Push them UP to activate them."
}
},
"basic-2": {
"title": "Basic Addition: 1 + 1",
"description": "Add the second earth bead to make 2",
"actionDescription": "Click the second earth bead to move it up",
"tooltip": {
"content": "Building up earth beads",
"explanation": "Continue adding earth beads one by one for numbers 2, 3, and 4"
}
},
"basic-3": {
"title": "Basic Addition: 2 + 1",
"description": "Add the third earth bead to make 3",
"actionDescription": "Click the third earth bead to move it up",
"tooltip": {
"content": "Adding earth beads in sequence",
"explanation": "Continue adding earth beads one by one until you reach 4"
}
},
"basic-4": {
"title": "Basic Addition: 3 + 1",
"description": "Add the fourth earth bead to make 4",
"actionDescription": "Click the fourth earth bead to complete 4",
"tooltip": {
"content": "Maximum earth beads",
"explanation": "Four earth beads is the maximum - next we need a different approach"
}
},
"heaven-intro": {
"title": "Heaven Bead: 0 + 5",
"description": "Use the heaven bead to represent 5",
"actionDescription": "Click the heaven bead to activate it",
"tooltip": {
"content": "Heaven bead = 5",
"explanation": "The single bead above the bar represents 5"
}
},
"heaven-plus-earth": {
"title": "Combining: 5 + 1",
"description": "Add 1 to 5 by activating one earth bead",
"actionDescription": "Click the first earth bead to make 6",
"tooltip": {
"content": "Heaven + Earth = 6",
"explanation": "When you have room in the earth section, simply add directly"
}
},
"complement-intro": {
"title": "Five Complement: 3 + 4",
"description": "Need to add 4, but only have 1 earth bead space. Use complement: 4 = 5 - 1",
"actionDescription": "First add heaven bead (5), then remove 1 earth bead",
"tooltip": {
"content": "Five Complement: 4 = 5 - 1",
"explanation": "When you need to add 4 but only have 1 space, use: add 5, remove 1"
},
"multiStepInstructions": [
"Click the heaven bead to add 5",
"Click the first earth bead to remove 1"
]
},
"complement-2": {
"title": "Five Complement: 2 + 3",
"description": "Add 3 to make 5 by using complement: 3 = 5 - 2",
"actionDescription": "Add heaven bead (5), then remove 2 earth beads",
"tooltip": {
"content": "Five Complement: 3 = 5 - 2",
"explanation": "To add 3, think: 3 = 5 - 2, so add 5 and take away 2"
},
"multiStepInstructions": [
"Click the heaven bead to add 5",
"Click the first earth bead to remove it",
"Click the second earth bead to remove it"
]
},
"complex-1": {
"title": "Complex: 6 + 2",
"description": "Add 2 more to 6 (which has heaven + 1 earth)",
"actionDescription": "Add two more earth beads",
"tooltip": {
"content": "Direct addition when possible",
"explanation": "When you have space in the earth section, just add directly"
}
},
"complex-2": {
"title": "Complex: 7 + 4",
"description": "Add 4 to 7, but no room for 4 earth beads. Use complement again",
"actionDescription": "Add tens heaven, then clear ones place: remove heaven + 2 earth",
"tooltip": {
"content": "Carrying to tens place",
"explanation": "7 + 4 = 11, which needs the tens column heaven bead"
},
"multiStepInstructions": [
"Click the heaven bead in the tens column (left)",
"Click the heaven bead in the ones column to remove it",
"Click the first earth bead to remove it",
"Click the second earth bead to remove it"
]
}
}
}
}

View File

@ -91,6 +91,113 @@
},
"formula": "{original} se convierte en {expanded}",
"devWarning": "⚠ Resumen y verificación no coinciden: {issues}"
},
"steps": {
"basic-1": {
"title": "Suma básica: 0 + 1",
"description": "Comienza añadiendo tu primera cuenta de tierra",
"actionDescription": "Haz clic en la primera cuenta de tierra para moverla hacia arriba",
"tooltip": {
"content": "Añadiendo cuentas de tierra",
"explanation": "Las cuentas de tierra (abajo) valen 1 cada una. Empújalas HACIA ARRIBA para activarlas."
}
},
"basic-2": {
"title": "Suma básica: 1 + 1",
"description": "Añade la segunda cuenta de tierra para hacer 2",
"actionDescription": "Haz clic en la segunda cuenta de tierra para moverla hacia arriba",
"tooltip": {
"content": "Acumulando cuentas de tierra",
"explanation": "Continúa añadiendo cuentas de tierra una por una para los números 2, 3 y 4"
}
},
"basic-3": {
"title": "Suma básica: 2 + 1",
"description": "Añade la tercera cuenta de tierra para hacer 3",
"actionDescription": "Haz clic en la tercera cuenta de tierra para moverla hacia arriba",
"tooltip": {
"content": "Añadiendo cuentas de tierra en secuencia",
"explanation": "Continúa añadiendo cuentas de tierra una por una hasta llegar a 4"
}
},
"basic-4": {
"title": "Suma básica: 3 + 1",
"description": "Añade la cuarta cuenta de tierra para hacer 4",
"actionDescription": "Haz clic en la cuarta cuenta de tierra para completar 4",
"tooltip": {
"content": "Máximo de cuentas de tierra",
"explanation": "Cuatro cuentas de tierra es el máximo - a continuación necesitamos un enfoque diferente"
}
},
"heaven-intro": {
"title": "Cuenta del cielo: 0 + 5",
"description": "Usa la cuenta del cielo para representar 5",
"actionDescription": "Haz clic en la cuenta del cielo para activarla",
"tooltip": {
"content": "Cuenta del cielo = 5",
"explanation": "La cuenta única arriba de la barra representa 5"
}
},
"heaven-plus-earth": {
"title": "Combinando: 5 + 1",
"description": "Suma 1 a 5 activando una cuenta de tierra",
"actionDescription": "Haz clic en la primera cuenta de tierra para hacer 6",
"tooltip": {
"content": "Cielo + Tierra = 6",
"explanation": "Cuando tienes espacio en la sección de tierra, simplemente suma directamente"
}
},
"complement-intro": {
"title": "Complemento de cinco: 3 + 4",
"description": "Necesitas sumar 4, pero solo tienes 1 espacio de cuenta de tierra. Usa el complemento: 4 = 5 - 1",
"actionDescription": "Primero suma la cuenta del cielo (5), luego quita 1 cuenta de tierra",
"tooltip": {
"content": "Complemento de cinco: 4 = 5 - 1",
"explanation": "Cuando necesitas sumar 4 pero solo tienes 1 espacio, usa: suma 5, quita 1"
},
"multiStepInstructions": [
"Haz clic en la cuenta del cielo para sumar 5",
"Haz clic en la primera cuenta de tierra para quitar 1"
]
},
"complement-2": {
"title": "Complemento de cinco: 2 + 3",
"description": "Suma 3 para hacer 5 usando el complemento: 3 = 5 - 2",
"actionDescription": "Suma la cuenta del cielo (5), luego quita 2 cuentas de tierra",
"tooltip": {
"content": "Complemento de cinco: 3 = 5 - 2",
"explanation": "Para sumar 3, piensa: 3 = 5 - 2, así que suma 5 y quita 2"
},
"multiStepInstructions": [
"Haz clic en la cuenta del cielo para sumar 5",
"Haz clic en la primera cuenta de tierra para quitarla",
"Haz clic en la segunda cuenta de tierra para quitarla"
]
},
"complex-1": {
"title": "Complejo: 6 + 2",
"description": "Suma 2 más a 6 (que tiene cielo + 1 tierra)",
"actionDescription": "Añade dos cuentas de tierra más",
"tooltip": {
"content": "Suma directa cuando es posible",
"explanation": "Cuando tienes espacio en la sección de tierra, simplemente suma directamente"
}
},
"complex-2": {
"title": "Complejo: 7 + 4",
"description": "Suma 4 a 7, pero no hay espacio para 4 cuentas de tierra. Usa el complemento de nuevo",
"actionDescription": "Suma el cielo de las decenas, luego limpia las unidades: quita cielo + 2 tierra",
"tooltip": {
"content": "Llevando a las decenas",
"explanation": "7 + 4 = 11, que necesita la cuenta del cielo de la columna de las decenas"
},
"multiStepInstructions": [
"Haz clic en la cuenta del cielo en la columna de las decenas (izquierda)",
"Haz clic en la cuenta del cielo en la columna de las unidades para quitarla",
"Haz clic en la primera cuenta de tierra para quitarla",
"Haz clic en la segunda cuenta de tierra para quitarla"
]
}
}
}
}

View File

@ -91,6 +91,113 @@
},
"formula": "{original} {expanded} बन जाता है",
"devWarning": "⚠ सारांश/गार्ड मेल नहीं खाता: {issues}"
},
"steps": {
"basic-1": {
"title": "बुनियादी जोड़: 0 + 1",
"description": "अपना पहला पृथ्वी मोती जोड़कर शुरू करें",
"actionDescription": "पहले पृथ्वी मोती पर क्लिक करके इसे ऊपर ले जाएं",
"tooltip": {
"content": "पृथ्वी मोती जोड़ना",
"explanation": "पृथ्वी मोती (नीचे) प्रत्येक 1 के बराबर होते हैं। उन्हें सक्रिय करने के लिए ऊपर धकेलें।"
}
},
"basic-2": {
"title": "बुनियादी जोड़: 1 + 1",
"description": "2 बनाने के लिए दूसरा पृथ्वी मोती जोड़ें",
"actionDescription": "दूसरे पृथ्वी मोती पर क्लिक करके इसे ऊपर ले जाएं",
"tooltip": {
"content": "पृथ्वी मोती बनाना",
"explanation": "संख्या 2, 3 और 4 के लिए एक-एक करके पृथ्वी मोती जोड़ते रहें"
}
},
"basic-3": {
"title": "बुनियादी जोड़: 2 + 1",
"description": "3 बनाने के लिए तीसरा पृथ्वी मोती जोड़ें",
"actionDescription": "तीसरे पृथ्वी मोती पर क्लिक करके इसे ऊपर ले जाएं",
"tooltip": {
"content": "पृथ्वी मोतियों को क्रम में जोड़ना",
"explanation": "जब तक आप 4 तक नहीं पहुंचते, तब तक पृथ्वी मोती एक-एक करके जोड़ते रहें"
}
},
"basic-4": {
"title": "बुनियादी जोड़: 3 + 1",
"description": "4 बनाने के लिए चौथा पृथ्वी मोती जोड़ें",
"actionDescription": "चौथे पृथ्वी मोती पर क्लिक करके 4 पूर्ण करें",
"tooltip": {
"content": "अधिकतम पृथ्वी मोती",
"explanation": "चार पृथ्वी मोती अधिकतम हैं - अगले के लिए हमें एक अलग तरीके की आवश्यकता है"
}
},
"heaven-intro": {
"title": "स्वर्ग मोती: 0 + 5",
"description": "5 को दर्शाने के लिए स्वर्ग मोती का उपयोग करें",
"actionDescription": "स्वर्ग मोती को सक्रिय करने के लिए उस पर क्लिक करें",
"tooltip": {
"content": "स्वर्ग मोती = 5",
"explanation": "पट्टी के ऊपर का एकल मोती 5 को दर्शाता है"
}
},
"heaven-plus-earth": {
"title": "संयोजन: 5 + 1",
"description": "एक पृथ्वी मोती सक्रिय करके 5 में 1 जोड़ें",
"actionDescription": "6 बनाने के लिए पहले पृथ्वी मोती पर क्लिक करें",
"tooltip": {
"content": "स्वर्ग + पृथ्वी = 6",
"explanation": "जब आपके पास पृथ्वी खंड में जगह हो, तो बस सीधे जोड़ें"
}
},
"complement-intro": {
"title": "पांच का पूरक: 3 + 4",
"description": "4 जोड़ने की आवश्यकता है, लेकिन केवल 1 पृथ्वी मोती की जगह है। पूरक का उपयोग करें: 4 = 5 - 1",
"actionDescription": "पहले स्वर्ग मोती (5) जोड़ें, फिर 1 पृथ्वी मोती हटाएं",
"tooltip": {
"content": "पांच का पूरक: 4 = 5 - 1",
"explanation": "जब आपको 4 जोड़ना हो लेकिन केवल 1 जगह हो, तो उपयोग करें: 5 जोड़ें, 1 घटाएं"
},
"multiStepInstructions": [
"5 जोड़ने के लिए स्वर्ग मोती पर क्लिक करें",
"1 हटाने के लिए पहले पृथ्वी मोती पर क्लिक करें"
]
},
"complement-2": {
"title": "पांच का पूरक: 2 + 3",
"description": "पूरक का उपयोग करके 3 जोड़कर 5 बनाएं: 3 = 5 - 2",
"actionDescription": "स्वर्ग मोती (5) जोड़ें, फिर 2 पृथ्वी मोती हटाएं",
"tooltip": {
"content": "पांच का पूरक: 3 = 5 - 2",
"explanation": "3 जोड़ने के लिए, सोचें: 3 = 5 - 2, इसलिए 5 जोड़ें और 2 घटाएं"
},
"multiStepInstructions": [
"5 जोड़ने के लिए स्वर्ग मोती पर क्लिक करें",
"इसे हटाने के लिए पहले पृथ्वी मोती पर क्लिक करें",
"इसे हटाने के लिए दूसरे पृथ्वी मोती पर क्लिक करें"
]
},
"complex-1": {
"title": "जटिल: 6 + 2",
"description": "6 (जिसमें स्वर्ग + 1 पृथ्वी है) में 2 और जोड़ें",
"actionDescription": "दो और पृथ्वी मोती जोड़ें",
"tooltip": {
"content": "जब संभव हो तो सीधा जोड़",
"explanation": "जब आपके पास पृथ्वी खंड में जगह हो, तो बस सीधे जोड़ें"
}
},
"complex-2": {
"title": "जटिल: 7 + 4",
"description": "7 में 4 जोड़ें, लेकिन 4 पृथ्वी मोतियों के लिए जगह नहीं है। फिर से पूरक का उपयोग करें",
"actionDescription": "दहाई का स्वर्ग जोड़ें, फिर इकाई स्थान साफ करें: स्वर्ग + 2 पृथ्वी हटाएं",
"tooltip": {
"content": "दहाई स्थान पर ले जाना",
"explanation": "7 + 4 = 11, जिसके लिए दहाई स्तंभ के स्वर्ग मोती की आवश्यकता है"
},
"multiStepInstructions": [
"दहाई स्तंभ (बाएं) में स्वर्ग मोती पर क्लिक करें",
"इसे हटाने के लिए इकाई स्तंभ में स्वर्ग मोती पर क्लिक करें",
"इसे हटाने के लिए पहले पृथ्वी मोती पर क्लिक करें",
"इसे हटाने के लिए दूसरे पृथ्वी मोती पर क्लिक करें"
]
}
}
}
}

View File

@ -91,6 +91,113 @@
},
"formula": "{original} は {expanded} になる",
"devWarning": "⚠ 要約とガードが一致しません: {issues}"
},
"steps": {
"basic-1": {
"title": "基本的な足し算0 + 1",
"description": "最初の地珠を入れてみましょう",
"actionDescription": "最初の地珠をクリックして上に動かします",
"tooltip": {
"content": "地珠を入れる",
"explanation": "地珠下の珠は1つで1を表します。上に上げて有効にします。"
}
},
"basic-2": {
"title": "基本的な足し算1 + 1",
"description": "2つ目の地珠を入れて2を作ります",
"actionDescription": "2つ目の地珠をクリックして上に動かします",
"tooltip": {
"content": "地珠を積み上げる",
"explanation": "2、3、4の数字のために地珠を1つずつ入れていきます"
}
},
"basic-3": {
"title": "基本的な足し算2 + 1",
"description": "3つ目の地珠を入れて3を作ります",
"actionDescription": "3つ目の地珠をクリックして上に動かします",
"tooltip": {
"content": "地珠を順番に入れる",
"explanation": "4になるまで地珠を1つずつ入れていきます"
}
},
"basic-4": {
"title": "基本的な足し算3 + 1",
"description": "4つ目の地珠を入れて4を作ります",
"actionDescription": "4つ目の地珠をクリックして4を完成させます",
"tooltip": {
"content": "地珠の最大値",
"explanation": "4つの地珠が最大です。次は別の方法が必要です"
}
},
"heaven-intro": {
"title": "天珠0 + 5",
"description": "天珠を使って5を表します",
"actionDescription": "天珠をクリックして有効にします",
"tooltip": {
"content": "天珠 = 5",
"explanation": "桁の上にある1つの珠は5を表します"
}
},
"heaven-plus-earth": {
"title": "組み合わせ5 + 1",
"description": "地珠を1つ入れて5に1を足します",
"actionDescription": "最初の地珠をクリックして6を作ります",
"tooltip": {
"content": "天 + 地 = 6",
"explanation": "地珠の欄に空きがあれば、そのまま足します"
}
},
"complement-intro": {
"title": "五の補数3 + 4",
"description": "4を足したいが地珠の空きは1つだけ。補数を使います4 = 5 - 1",
"actionDescription": "まず天珠5を入れて、それから地珠を1つ外します",
"tooltip": {
"content": "五の補数4 = 5 - 1",
"explanation": "4を足したいが空きが1つの時は、5を足して1を引きます"
},
"multiStepInstructions": [
"天珠をクリックして5を足します",
"最初の地珠をクリックして1を引きます"
]
},
"complement-2": {
"title": "五の補数2 + 3",
"description": "補数を使って3を足して5にします3 = 5 - 2",
"actionDescription": "天珠5を入れて、それから地珠を2つ外します",
"tooltip": {
"content": "五の補数3 = 5 - 2",
"explanation": "3を足すには、3 = 5 - 2と考えて、5を足して2を引きます"
},
"multiStepInstructions": [
"天珠をクリックして5を足します",
"最初の地珠をクリックして外します",
"2つ目の地珠をクリックして外します"
]
},
"complex-1": {
"title": "複雑6 + 2",
"description": "6天珠 + 地珠1つに2を足します",
"actionDescription": "地珠を2つ追加します",
"tooltip": {
"content": "可能なら直接足す",
"explanation": "地珠の欄に空きがあれば、そのまま足します"
}
},
"complex-2": {
"title": "複雑7 + 4",
"description": "7に4を足すが、地珠の空きは4つありません。再び補数を使います",
"actionDescription": "十の位の天珠を入れて、一の位をクリア天珠と地珠2つを外します",
"tooltip": {
"content": "十の位への繰り上がり",
"explanation": "7 + 4 = 11なので、十の位の天珠が必要です"
},
"multiStepInstructions": [
"十の位(左)の天珠をクリックします",
"一の位の天珠をクリックして外します",
"最初の地珠をクリックして外します",
"2つ目の地珠をクリックして外します"
]
}
}
}
}

View File

@ -91,6 +91,113 @@
},
"formula": "{original} fit {expanded}",
"devWarning": "⚠ Summarium cum custodia non congruit: {issues}"
},
"steps": {
"basic-1": {
"title": "Additio Simplex: 0 + 1",
"description": "Incipe addendo primam gemmam terrestrem",
"actionDescription": "Preme primam gemmam terrestrem ut sursum moveatur",
"tooltip": {
"content": "Gemmas terrestres addere",
"explanation": "Gemmae terrestres (infra) singulae valent 1. Trudie eas SURSUM ut activentur."
}
},
"basic-2": {
"title": "Additio Simplex: 1 + 1",
"description": "Adde secundam gemmam terrestrem ut 2 fiat",
"actionDescription": "Preme secundam gemmam terrestrem ut sursum moveatur",
"tooltip": {
"content": "Gemmas terrestres aedificare",
"explanation": "Perge addere gemmas terrestres singulas pro numeris 2, 3, et 4"
}
},
"basic-3": {
"title": "Additio Simplex: 2 + 1",
"description": "Adde tertiam gemmam terrestrem ut 3 fiat",
"actionDescription": "Preme tertiam gemmam terrestrem ut sursum moveatur",
"tooltip": {
"content": "Gemmas terrestres per ordinem addere",
"explanation": "Perge addere gemmas terrestres singulas donec ad 4 pervenias"
}
},
"basic-4": {
"title": "Additio Simplex: 3 + 1",
"description": "Adde quartam gemmam terrestrem ut 4 fiat",
"actionDescription": "Preme quartam gemmam terrestrem ut 4 compleatur",
"tooltip": {
"content": "Maximum gemmarum terrestrium",
"explanation": "Quattuor gemmae terrestres maximum sunt - deinde nobis opus est ratione diversa"
}
},
"heaven-intro": {
"title": "Gemma Caelestis: 0 + 5",
"description": "Utere gemma caelesti ut 5 repraesentet",
"actionDescription": "Preme gemmam caelestem ut activetur",
"tooltip": {
"content": "Gemma caelestis = 5",
"explanation": "Gemma unica supra tignum 5 repraesentat"
}
},
"heaven-plus-earth": {
"title": "Coniunctio: 5 + 1",
"description": "Adde 1 ad 5 activando unam gemmam terrestrem",
"actionDescription": "Preme primam gemmam terrestrem ut 6 fiat",
"tooltip": {
"content": "Caelum + Terra = 6",
"explanation": "Cum spatium in sectione terrestri habes, simpliciter adde directe"
}
},
"complement-intro": {
"title": "Complementum Quinque: 3 + 4",
"description": "Opus est 4 addere, sed tantum 1 spatium gemmae terrestris habes. Utere complemento: 4 = 5 - 1",
"actionDescription": "Primum adde gemmam caelestem (5), tum remove 1 gemmam terrestrem",
"tooltip": {
"content": "Complementum Quinque: 4 = 5 - 1",
"explanation": "Cum opus est 4 addere sed tantum 1 spatium habes, utere: adde 5, remove 1"
},
"multiStepInstructions": [
"Preme gemmam caelestem ut 5 addas",
"Preme primam gemmam terrestrem ut 1 removes"
]
},
"complement-2": {
"title": "Complementum Quinque: 2 + 3",
"description": "Adde 3 ut 5 fiat utendo complemento: 3 = 5 - 2",
"actionDescription": "Adde gemmam caelestem (5), tum remove 2 gemmas terrestres",
"tooltip": {
"content": "Complementum Quinque: 3 = 5 - 2",
"explanation": "Ut 3 addas, cogita: 3 = 5 - 2, ergo adde 5 et aufer 2"
},
"multiStepInstructions": [
"Preme gemmam caelestem ut 5 addas",
"Preme primam gemmam terrestrem ut removeatur",
"Preme secundam gemmam terrestrem ut removeatur"
]
},
"complex-1": {
"title": "Complexus: 6 + 2",
"description": "Adde 2 plura ad 6 (quod habet caelum + 1 terram)",
"actionDescription": "Adde duas gemmas terrestres plures",
"tooltip": {
"content": "Additio directa cum possibilis",
"explanation": "Cum spatium in sectione terrestri habes, simpliciter adde directe"
}
},
"complex-2": {
"title": "Complexus: 7 + 4",
"description": "Adde 4 ad 7, sed non est spatium pro 4 gemmis terrestribus. Iterum utere complemento",
"actionDescription": "Adde caelum decadum, tum purga locum unitatum: remove caelum + 2 terras",
"tooltip": {
"content": "Translatio ad locum decadum",
"explanation": "7 + 4 = 11, quod opus est gemma caelesti columnae decadum"
},
"multiStepInstructions": [
"Preme gemmam caelestem in columna decadum (sinistra)",
"Preme gemmam caelestem in columna unitatum ut removeatur",
"Preme primam gemmam terrestrem ut removeatur",
"Preme secundam gemmam terrestrem ut removeatur"
]
}
}
}
}

View File

@ -1,4 +1,5 @@
import { rithmomachiaMessages } from '@/arcade-games/rithmomachia/messages'
import { gamesMessages } from '@/i18n/locales/games/messages'
import { homeMessages } from '@/i18n/locales/home/messages'
import { tutorialMessages } from '@/i18n/locales/tutorial/messages'
@ -35,6 +36,7 @@ export async function getMessages(locale: Locale) {
return mergeMessages(
common,
{ home: homeMessages[locale] },
{ games: gamesMessages[locale] },
{ tutorial: tutorialMessages[locale] },
rithmomachiaMessages[locale]
)

View File

@ -1,5 +1,6 @@
// Utility to extract and convert the existing GuidedAdditionTutorial data
import type { Tutorial } from '../types/tutorial'
import type { Locale } from '../i18n/messages'
import { generateAbacusInstructions } from './abacusInstructionGenerator'
// Import the existing tutorial step interface to match the current structure
@ -217,25 +218,34 @@ export const guidedAdditionSteps: ExistingTutorialStep[] = [
]
// Convert the existing tutorial format to our new format
export function convertGuidedAdditionTutorial(): Tutorial {
export function convertGuidedAdditionTutorial(tutorialMessages: Record<string, any>): Tutorial {
// Convert existing static steps to progressive step data
const convertedSteps = guidedAdditionSteps.map((step) => {
// Generate progressive instruction data
const generatedInstruction = generateAbacusInstructions(step.startValue, step.targetValue)
// Progressive instruction data generated successfully
// Get translated strings for this step
const stepTranslations = tutorialMessages.steps?.[step.id] || {}
return {
...step,
// Use translated strings if available, otherwise keep original
title: stepTranslations.title || step.title,
description: stepTranslations.description || step.description,
actionDescription: generatedInstruction.actionDescription, // Keep generated for now
tooltip: {
content: stepTranslations.tooltip?.content || step.tooltip.content,
explanation: stepTranslations.tooltip?.explanation || step.tooltip.explanation,
},
multiStepInstructions:
stepTranslations.multiStepInstructions ||
step.multiStepInstructions ||
generatedInstruction.multiStepInstructions,
// Override with generated step-based highlighting and instructions
stepBeadHighlights: generatedInstruction.stepBeadHighlights,
totalSteps: generatedInstruction.totalSteps,
// Keep existing multi-step instructions if available, otherwise use generated ones
multiStepInstructions:
step.multiStepInstructions || generatedInstruction.multiStepInstructions,
// Update action description if multi-step was generated
expectedAction: generatedInstruction.expectedAction,
actionDescription: generatedInstruction.actionDescription,
}
})
@ -271,14 +281,14 @@ export function convertGuidedAdditionTutorial(): Tutorial {
}
// Helper to validate that the existing tutorial steps work with our new interfaces
export function validateTutorialConversion(): {
export function validateTutorialConversion(tutorialMessages: Record<string, any>): {
isValid: boolean
errors: string[]
} {
const errors: string[] = []
try {
const tutorial = convertGuidedAdditionTutorial()
const tutorial = convertGuidedAdditionTutorial(tutorialMessages)
// Basic validation
if (!tutorial.id || !tutorial.title || !tutorial.steps.length) {
@ -319,12 +329,12 @@ export function validateTutorialConversion(): {
}
// Helper to export tutorial data for use in the editor
export function getTutorialForEditor(): Tutorial {
const validation = validateTutorialConversion()
export function getTutorialForEditor(tutorialMessages: Record<string, any>): Tutorial {
const validation = validateTutorialConversion(tutorialMessages)
if (!validation.isValid) {
console.warn('Tutorial validation errors:', validation.errors)
}
return convertGuidedAdditionTutorial()
return convertGuidedAdditionTutorial(tutorialMessages)
}