From d241f69f3b2b2effc6ac503e06cb9aa6e77b3deb Mon Sep 17 00:00:00 2001 From: David Kotnik Date: Sat, 10 Jan 2026 23:23:19 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=8C=8D=F0=9F=94=A5=20LOCALIZATION=20SYSTE?= =?UTF-8?q?M=20-=20INTRO=20SYNC=20+=20VOICE=20SWITCHING?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✅ LOCALIZATION.JSON CREATED (5 LANGUAGES): 📂 assets/localization.json (NEW!): - 🇸🇮 Slovenščina (slo) - 🇬🇧 English (en) - 🇩🇪 Deutsch (de) - 🇮🇹 Italiano (it) - 🇨🇳 中文 (cn) 📝 COMPLETE TRANSLATIONS: - All 20 Polaroid texts - Menu buttons (New Game, Load, Settings, Exit) - Game title + subtitle ✅ LOCALIZATIONSYSTEM.JS UPDATED: 🔧 NEW METHODS ADDED: 1. loadIntroTexts() - Load JSON - Fetches assets/localization.json - Merges intro_polaroids into translations - Merges menu texts - Adds title/subtitle - Console: '✅ Intro texts loaded from JSON' 2. getIntroText(polaroidKey) - Get text - Returns translated Polaroid text - Falls back to English if missing - Usage: i18n.getIntroText('kai_dad_longboard') 3. getVoicePath(character, index) - Voice switching! - 🇸🇮 Slovenian → assets/audio/voiceover/sl/ - 🇬🇧 English → assets/audio/voiceover/en/ - Auto-formats filename - Example SL: kai_01.mp3 - Example EN: kai_en_01.mp3 4. hasVoiceForLanguage(character, index) - Checks if voice exists for language - SL + EN have full voiceovers - DE/IT/CN fall back to EN 🎯 LANGUAGE TO VOICE PATH MAPPING: - slo → /voiceover/sl/kai_01.mp3 - en → /voiceover/en/kai_en_01.mp3 - de → /voiceover/en/kai_en_01.mp3 (fallback) - it → /voiceover/en/kai_en_01.mp3 (fallback) - cn → /voiceover/en/kai_en_01.mp3 (fallback) 📋 20 POLAROID KEYS: 1. kai_dad_longboard 2. barbershop 3. birthday_cake 4. family_portrait 5. twins_holding_hands 6. kai_bedroom 7. virus_microscope 8. chaos_streets 9. zombies 10. parents_ghosts 11. ana_taken 12. black_screen 13. kai_alone 14. ana_memory_1 15. ana_memory_2 16. ana_memory_3 17. ana_memory_4 18. ana_memory_5 19. gronk_arrival 20. determination 21. lifetime 🎮 USAGE EXAMPLE: // In IntroScene preload() await window.i18n.loadIntroTexts(); // Get text for current language const text = window.i18n.getIntroText('birthday_cake'); // SL: 'Tukaj smo bili še vedno srečni...' // EN: 'Here we were still happy...' // Get voice path const path = window.i18n.getVoicePath('kai', 1); // SL: 'assets/audio/voiceover/sl/kai_01.mp3' // EN: 'assets/audio/voiceover/en/kai_en_01.mp3' 🌍 LANGUAGE FLOW: 1. Player selects language on launcher 2. window.i18n.setLanguage('slo') 3. Saved to LocalStorage 4. IntroScene loads JSON texts 5. Displays translated Polaroid captions 6. Plays SL voice files from /sl/ folder 7. Full sync! NEXT: Hook up IntroScene to use these methods! Files: - assets/localization.json (NEW!) - src/systems/LocalizationSystem.js (UPDATED!) READY FOR INTRO TEXT SYNC! 🌍🔥 --- assets/localization.json | 167 ++++++++++++++++++++++++++++++ src/systems/LocalizationSystem.js | 84 +++++++++++++++ 2 files changed, 251 insertions(+) create mode 100644 assets/localization.json diff --git a/assets/localization.json b/assets/localization.json new file mode 100644 index 000000000..be6e2142e --- /dev/null +++ b/assets/localization.json @@ -0,0 +1,167 @@ +{ + "en": { + "game_title": "DEATH VALLEY", + "subtitle": "~ 2084 - Survival Farm ~", + "intro_polaroids": { + "kai_dad_longboard": "Dad and I. Before everything changed.", + "barbershop": "Getting ready. We always did things together.", + "birthday_cake": "Here we were still happy. Still a family.", + "family_portrait": "All of us. Together. Perfect.", + "twins_holding_hands": "We were always two. Inseparable.", + "kai_bedroom": "Our room. Our sanctuary.", + "virus_microscope": "Then came X-Noir. The virus.", + "chaos_streets": "Everyone changed. Streets burned.", + "zombies": "Friends became zombies.", + "parents_ghosts": "Our parents fought... and lost.", + "ana_taken": "KAI! DON'T FORGET ME!", + "black_screen": "I have no memory. Everything is... gone.", + "kai_alone": "They say I'm fourteen. But I don't remember... anything.", + "ana_memory_1": "Alone. In darkness. With only... this.", + "ana_memory_2": "Her face. The only thing I remember.", + "ana_memory_3": "Ana. My sister. My twin.", + "ana_memory_4": "The last thing I saw...", + "ana_memory_5": "...before everything went dark.", + "gronk_arrival": "Finally awake, old man. Your mission awaits.", + "determination": "I must find her.", + "lifetime": "...even if it takes my entire life." + }, + "menu": { + "new_game": "▶ NEW GAME", + "load_game": "📁 LOAD GAME", + "settings": "⚙️ SETTINGS", + "exit": "❌ EXIT" + } + }, + "slo": { + "game_title": "MRTVA DOLINA", + "subtitle": "~ 2084 - Preživetje na Kmetiji ~", + "intro_polaroids": { + "kai_dad_longboard": "Oče in jaz. Preden se je vse spremenilo.", + "barbershop": "Pripravljanje. Vedno sva delala skupaj.", + "birthday_cake": "Tukaj smo bili še vedno srečni. Še vedno družina.", + "family_portrait": "Vsi skupaj. Združeni. Popolno.", + "twins_holding_hands": "Vedno sva bila dva. Neločljiva.", + "kai_bedroom": "Najina soba. Najino zatočišče.", + "virus_microscope": "Potem je prišel X-Noir. Virus.", + "chaos_streets": "Vsi so se spremenili. Ulice so gorele.", + "zombies": "Prijatelji so postali zombiji.", + "parents_ghosts": "Najini starši so se borili... in izgubili.", + "ana_taken": "KAI! NE POZABI ME!", + "black_screen": "Nimam spomina. Vse je... izginilo.", + "kai_alone": "Pravijo, da sem štirinajst. Ampak... ne spomnim se ničesar.", + "ana_memory_1": "Sam. V temi. Samo s... tem.", + "ana_memory_2": "Njen obraz. Edina stvar, ki se je spomnim.", + "ana_memory_3": "Ana. Moja sestra. Moja dvojčica.", + "ana_memory_4": "Zadnja stvar, ki sem jo videl...", + "ana_memory_5": "...preden je vse potemnelo.", + "gronk_arrival": "Končno buden, stari. Tvoja misija čaka.", + "determination": "Moram jo najti.", + "lifetime": "...tudi če mi vzame celo življenje." + }, + "menu": { + "new_game": "▶ NOVA IGRA", + "load_game": "📁 NALOŽI IGRO", + "settings": "⚙️ NASTAVITVE", + "exit": "❌ IZHOD" + } + }, + "de": { + "game_title": "TODESTAL", + "subtitle": "~ 2084 - Überlebensbauernhof ~", + "intro_polaroids": { + "kai_dad_longboard": "Papa und ich. Bevor sich alles änderte.", + "barbershop": "Wir machten uns fertig. Zusammen.", + "birthday_cake": "Hier waren wir noch glücklich. Noch eine Familie.", + "family_portrait": "Alle zusammen. Vereint. Perfekt.", + "twins_holding_hands": "Wir waren immer zwei. Unzertrennlich.", + "kai_bedroom": "Unser Zimmer. Unser Heiligtum.", + "virus_microscope": "Dann kam X-Noir. Das Virus.", + "chaos_streets": "Alle haben sich verändert. Straßen brannten.", + "zombies": "Freunde wurden zu Zombies.", + "parents_ghosts": "Unsere Eltern kämpften... und verloren.", + "ana_taken": "KAI! VERGISS MICH NICHT!", + "black_screen": "Ich habe keine Erinnerung. Alles ist... weg.", + "kai_alone": "Sie sagen, ich bin vierzehn. Aber ich erinnere mich nicht... an nichts.", + "ana_memory_1": "Allein. In der Dunkelheit. Nur mit... diesem.", + "ana_memory_2": "Ihr Gesicht. Das einzige, woran ich mich erinnere.", + "ana_memory_3": "Ana. Meine Schwester. Mein Zwilling.", + "ana_memory_4": "Das Letzte, was ich sah...", + "ana_memory_5": "...bevor alles dunkel wurde.", + "gronk_arrival": "Endlich wach, Alter. Deine Mission wartet.", + "determination": "Ich muss sie finden.", + "lifetime": "...auch wenn es mein ganzes Leben dauert." + }, + "menu": { + "new_game": "▶ NEUES SPIEL", + "load_game": "📁 SPIEL LADEN", + "settings": "⚙️ EINSTELLUNGEN", + "exit": "❌ BEENDEN" + } + }, + "it": { + "game_title": "VALLE DELLA MORTE", + "subtitle": "~ 2084 - Fattoria di Sopravvivenza ~", + "intro_polaroids": { + "kai_dad_longboard": "Papà ed io. Prima che tutto cambiasse.", + "barbershop": "Preparandoci. Facevamo sempre tutto insieme.", + "birthday_cake": "Qui eravamo ancora felici. Ancora una famiglia.", + "family_portrait": "Tutti insieme. Uniti. Perfetto.", + "twins_holding_hands": "Eravamo sempre in due. Inseparabili.", + "kai_bedroom": "La nostra stanza. Il nostro santuario.", + "virus_microscope": "Poi arrivò X-Noir. Il virus.", + "chaos_streets": "Tutti cambiarono. Le strade bruciavano.", + "zombies": "Gli amici diventarono zombie.", + "parents_ghosts": "I nostri genitori combatterono... e persero.", + "ana_taken": "KAI! NON DIMENTICARMI!", + "black_screen": "Non ho memoria. Tutto è... sparito.", + "kai_alone": "Dicono che ho quattordici anni. Ma non ricordo... niente.", + "ana_memory_1": "Solo. Nell'oscurità. Con solo... questo.", + "ana_memory_2": "Il suo viso. L'unica cosa che ricordo.", + "ana_memory_3": "Ana. Mia sorella. La mia gemella.", + "ana_memory_4": "L'ultima cosa che vidi...", + "ana_memory_5": "...prima che tutto diventasse buio.", + "gronk_arrival": "Finalmente sveglio, vecchio. La tua missione ti aspetta.", + "determination": "Devo trovarla.", + "lifetime": "...anche se ci vorrà tutta la mia vita." + }, + "menu": { + "new_game": "▶ NUOVA PARTITA", + "load_game": "📁 CARICA PARTITA", + "settings": "⚙️ IMPOSTAZIONI", + "exit": "❌ ESCI" + } + }, + "cn": { + "game_title": "死亡谷", + "subtitle": "~ 2084 - 生存农场 ~", + "intro_polaroids": { + "kai_dad_longboard": "爸爸和我。在一切改变之前。", + "barbershop": "准备好。我们总是一起做事。", + "birthday_cake": "这里我们还很快乐。还是一家人。", + "family_portrait": "我们所有人。在一起。完美。", + "twins_holding_hands": "我们永远是两个。形影不离。", + "kai_bedroom": "我们的房间。我们的避难所。", + "virus_microscope": "然后X-Noir来了。病毒。", + "chaos_streets": "每个人都变了。街道在燃烧。", + "zombies": "朋友变成了僵尸。", + "parents_ghosts": "我们的父母战斗了...失败了。", + "ana_taken": "KAI!不要忘记我!", + "black_screen": "我没有记忆。一切都...消失了。", + "kai_alone": "他们说我十四岁。但我什么都不记得了。", + "ana_memory_1": "独自一人。在黑暗中。只有...这个。", + "ana_memory_2": "她的脸。我唯一记得的。", + "ana_memory_3": "Ana。我的姐妹。我的双胞胎。", + "ana_memory_4": "我看到的最后一件事...", + "ana_memory_5": "...在一切变黑之前。", + "gronk_arrival": "终于醒了,老头。你的任务在等着。", + "determination": "我必须找到她。", + "lifetime": "...即使这需要我的一生。" + }, + "menu": { + "new_game": "▶ 新游戏", + "load_game": "📁 载入游戏", + "settings": "⚙️ 设置", + "exit": "❌ 退出" + } + } +} \ No newline at end of file diff --git a/src/systems/LocalizationSystem.js b/src/systems/LocalizationSystem.js index 1c1fce9ca..636013737 100644 --- a/src/systems/LocalizationSystem.js +++ b/src/systems/LocalizationSystem.js @@ -278,6 +278,90 @@ class LocalizationSystem { return fallback; } + /** + * LOAD INTRO TEXTS FROM JSON + */ + async loadIntroTexts() { + try { + const response = await fetch('assets/localization.json'); + const data = await response.json(); + + // Merge intro texts into translations + for (const lang in data) { + if (!this.translations[lang]) { + this.translations[lang] = {}; + } + + // Add intro polaroid texts + if (data[lang].intro_polaroids) { + this.translations[lang].intro_polaroids = data[lang].intro_polaroids; + } + + // Add menu texts + if (data[lang].menu) { + Object.assign(this.translations[lang], data[lang].menu); + } + + // Add title/subtitle + if (data[lang].game_title) { + this.translations[lang].game_title = data[lang].game_title; + } + if (data[lang].subtitle) { + this.translations[lang].subtitle = data[lang].subtitle; + } + } + + console.log('✅ Intro texts loaded from JSON'); + return true; + } catch (error) { + console.warn('⚠️ Could not load localization.json:', error); + return false; + } + } + + /** + * GET INTRO POLAROID TEXT + */ + getIntroText(polaroidKey) { + const lang = this.translations[this.currentLang]; + if (lang && lang.intro_polaroids && lang.intro_polaroids[polaroidKey]) { + return lang.intro_polaroids[polaroidKey]; + } + + // Fallback to English + const enLang = this.translations['en']; + if (enLang && enLang.intro_polaroids && enLang.intro_polaroids[polaroidKey]) { + return enLang.intro_polaroids[polaroidKey]; + } + + return polaroidKey; // Return key if not found + } + + /** + * GET VOICE FILE PATH (switches language folder) + */ + getVoicePath(character, index, format = 'mp3') { + const langSuffix = this.currentLang === 'en' ? 'en' : 'sl'; + + // Map language codes to voice folders + if (this.currentLang === 'slo') { + // Slovenian voices in /sl/ folder + return `assets/audio/voiceover/sl/${character}_${String(index).padStart(2, '0')}.${format}`; + } else { + // English voices (default for DE, IT, CN too) + return `assets/audio/voiceover/en/${character}_en_${String(index).padStart(2, '0')}.${format}`; + } + } + + /** + * CHECK IF VOICE FILE EXISTS FOR CURRENT LANGUAGE + */ + hasVoiceForLanguage(character, index) { + // Slovenian and English have full voiceovers + // Other languages fall back to English + return this.currentLang === 'slo' || this.currentLang === 'en'; + } + /** * Set current language */