// ============================================================================
// i18n — English / Spanish translation layer for Black Craft
// Dictionary keyed by section. Names (Charlie, Mabu, Black Craft, version
// strings) and internal image placeholders are intentionally NOT translated.
// ============================================================================
const { createContext: createI18nContext, useContext: useI18nContext } = React;
const DICT = {
en: {
code: "en",
nav: { game: "The Game", team: "The Team", devlog: "Devlog" },
hero: {
subtitle:
"A 2D toon survival RPG. Build a home, raid the dungeon, and try not to wake the things sleeping down there.",
tags: ["Survival RPG", "Dungeon Crawler", "Base Building", "Single-Player"],
ctaWishlist: "Wishlist on Steam",
ctaSee: "See the Game",
rune1: "Day 41. The compass spins anti-clockwise now. We took it as decoration. It was a warning.",
rune2: "The bottles catch a wind no draught makes. The bubbles always rise toward whatever is watching.",
},
game: {
label: "The Game",
title1: "Build by day.",
title2: "Dig by night.",
lede: "Dimension Disrupt is a 2D toon survival RPG with dungeon-crawler combat and base-building roots. Made by two people. Drawn by hand.",
pillarWord: "PILLAR",
pillars: [
{ title: "Survive", copy: "Hunger. Cold. Sanity. Whatever's in the cupboard. The world only pretends to sit still while you sleep." },
{ title: "Disrupt", copy: "Procedural dungeons that hold a grudge. Loot is a polite word for what you bring back up." },
{ title: "Build", copy: "Workshop, garden, shrine, fence. Decide what to put near the door — something out there is taking notes." },
],
featuresLabel: "Features",
features: [
{ t: "Hand-drawn, hand-animated", c: "Every leaf, lantern and lurking horror toon-shaded frame by frame." },
{ t: "Sanity is a stat", c: "See too much, lose the thread. Your character will start to lie to you. The UI joins in eventually." },
{ t: "Dimensions, plural", c: "Five worlds bleed through one map. Find the seams. Don't pull on them." },
{ t: "A base that's yours", c: "Modular building, tools and traps. Lay it out, light it up, lock it down." },
{ t: "Pets that pull weight", c: "Companions that fight, fetch, and occasionally judge your choices." },
],
rune: "The first thing the dungeon takes is your shadow. The second is your name. The third is negotiable.",
},
studio: {
label: "The Team",
title1: "Two people.",
title2: "One small studio.",
lede: "Black Craft is Charlie and Mabu. We work from our home, on our own hours, with our own pets at our feet.",
mainsK: "MAINS",
fearsK: "FEARS",
members: [
{
role: "Developer · Technical Artist",
bio: "Writes the code, builds the tools, teaches sprites to behave. Charlie keeps the engine humming.",
mains: "Engine, tools",
fears: "French lawyers",
},
{
role: "Artist · Animator · Writer",
bio: "Draws everything you see and writes everything you read. Painstakingly animates hand-drawn sprites, the old school way.",
mains: "Art, anim, narrative",
fears: "Blank pages",
},
],
rune: "Mabu's first drawing of the protagonist had four eyes. Charlie said no. Mabu compromised at three. Two are usually closed.",
},
devlog: {
label: "Devlog",
title1: "Notes from",
title2: "the desk.",
all: "All Entries",
posts: [
{ tag: "Patchwork", title: "Stitching a dungeon that remembers you", excerpt: "On procedural dungeons that aren't actually procedural — how rooms carry grudges between runs, and why we let the map keep a diary." },
{ tag: "Art", title: "Sixty frames of one nervous slime", excerpt: "Mabu walks through the wobble-to-burst animation pipeline." },
{ tag: "Build", title: "Sanity, the worst stat we've ever shipped", excerpt: "Lies, hallucinations, and the UI elements that fight back." },
],
rune: "The dungeon was supposed to forget. We left the variable in. We are leaving it in.",
},
support: {
label: "Supported by",
blurb: "Demo development backed by ACAU's 2024 Videogame Development grant — strengthening Uruguay's audiovisual sector.",
},
footer: {
tagline: "A two-person studio making small, stubborn games. Currently making Dimension Disrupt.",
colGame: { title: "The Game", links: ["Pillars", "Features", "Press Kit", "Wishlist"] },
colStudio: { title: "Studio", links: ["About", "Devlog", "Contact"] },
colFollow: { title: "Follow", links: ["Twitter / X", "Bluesky", "Discord", "Mailing list"] },
copyright: "© 2026 Black Craft",
},
},
es: {
code: "es",
nav: { game: "El Juego", team: "El Equipo", devlog: "Diario" },
hero: {
subtitle:
"Un RPG de supervivencia toon en 2D. Construye un hogar, saquea la mazmorra e intenta no despertar a las cosas que duermen ahí abajo.",
tags: ["Supervivencia", "Exploración", "Construcción de Base", "1 Jugador"],
ctaWishlist: "Añadir a deseados en Steam",
ctaSee: "Ver el Juego",
rune1: "Día 41. La brújula ahora gira en sentido antihorario. La tomamos por decoración. Era una advertencia.",
rune2: "Las botellas atrapan un viento que ninguna corriente produce. Las burbujas siempre suben hacia lo que sea que esté observando.",
},
game: {
label: "El Juego",
title1: "Construye de día.",
title2: "Excava de noche.",
lede: "Dimension Disrupt es un RPG de supervivencia toon en 2D con combate, construcción de bases y exploración de distintas dimensiones. Hecho por dos personas. Dibujado a mano.",
pillarWord: "PILAR",
pillars: [
{ title: "Sobrevive", copy: "Hambre. Frío. Cordura. Lo que sea que haya en la alacena. El mundo solo finge quedarse quieto mientras duermes." },
{ title: "Altera", copy: "Dimensiones que guardan rencor. «Botín» es una palabra educada para lo que logras traer de vuelta." },
{ title: "Construye", copy: "Taller, jardín, santuario, valla. Decide qué poner cerca de la puerta: algo allá afuera está tomando notas." },
],
featuresLabel: "Características",
features: [
{ t: "Dibujado y animado a mano", c: "Cada hoja, linterna y horror al acecho sombreado en estilo toon, fotograma a fotograma." },
{ t: "La cordura es una estadística", c: "Si ves demasiado, pierdes el hilo. Tu personaje empezará a mentirte. La interfaz acabará por unirse." },
{ t: "Dimensiones, en plural", c: "Cinco mundos se filtran a través de un solo mapa. Encuentra las costuras. No tires de ellas." },
{ t: "Una base que es tuya", c: "Construcción modular, herramientas y trampas. Distribúyela, ilumínala, asegúrala." },
{ t: "Mascotas que aportan", c: "Compañeros que luchan, recogen cosas y, de vez en cuando, juzgan tus decisiones." },
],
rune: "Lo primero que la mazmorra te quita es tu sombra. Lo segundo, tu nombre. Lo tercero es negociable.",
},
studio: {
label: "El Equipo",
title1: "Dos personas.",
title2: "Un pequeño estudio.",
lede: "Black Craft son Charlie y Mabu. Trabajamos desde casa, con nuestros propios horarios y con nuestras mascotas a los pies.",
mainsK: "DOMINA",
fearsK: "TEME",
members: [
{
role: "Desarrollador · Artista Técnico",
bio: "Escribe el código, crea las herramientas y enseña a los sprites a comportarse. Charlie mantiene el motor en marcha.",
mains: "Motor, herramientas",
fears: "Abogados franceses",
},
{
role: "Artista · Animadora · Escritora",
bio: "Dibuja todo lo que ves y escribe todo lo que lees. Anima minuciosamente sprites dibujados a mano, a la vieja usanza.",
mains: "Arte, animación, narrativa",
fears: "Páginas en blanco",
},
],
rune: "El primer dibujo de Mabu del protagonista tenía cuatro ojos. Charlie dijo que no. Mabu transigió con tres. Dos suelen estar cerrados.",
},
devlog: {
label: "Diario",
title1: "Notas",
title2: "de desarrollo.",
all: "Todas las Entradas",
posts: [
{ tag: "Remiendos", title: "Cosiendo una mazmorra que te recuerda", excerpt: "Sobre mazmorras procedurales que en realidad no lo son: cómo las salas guardan rencor entre partidas y por qué dejamos que el mapa lleve un diario." },
{ tag: "Arte", title: "Sesenta fotogramas de un slime nervioso", excerpt: "Mabu repasa el proceso de animación, del temblor al estallido." },
{ tag: "Construcción", title: "La cordura, la peor estadística que hemos lanzado", excerpt: "Mentiras, alucinaciones y los elementos de interfaz que se resisten." },
],
rune: "La mazmorra debía olvidar. Dejamos la variable. La vamos a dejar.",
},
support: {
label: "Apoyado por",
blurb: "Desarrollo de la demo apoyado por la convocatoria Desarrollo de Videojuegos 2024 de ACAU — fortaleciendo el sector audiovisual uruguayo.",
},
footer: {
tagline: "Un estudio de dos personas que hace juegos pequeños y tercos. Actualmente desarrollando Dimension Disrupt.",
colGame: { title: "El Juego", links: ["Pilares", "Características", "Kit de Prensa", "Lista de Deseados"] },
colStudio: { title: "Estudio", links: ["Acerca de", "Devlog", "Contacto"] },
colFollow: { title: "Síguenos", links: ["Twitter / X", "Bluesky", "Discord", "Lista de correo"] },
copyright: "© 2026 Black Craft",
},
},
};
const LANGS = [
{ code: "en", short: "EN", label: "English", flag: "https://flagcdn.com/gb.svg" },
{ code: "es", short: "ES", label: "Español", flag: "https://flagcdn.com/es.svg" },
];
const LangContext = createI18nContext({ lang: "en", t: DICT.en, setLang: () => {} });
const LANG_STORAGE_KEY = "blackcraft.lang";
function LanguageProvider({ children }) {
const [lang, setLangState] = React.useState(() => {
try {
const saved = localStorage.getItem(LANG_STORAGE_KEY);
if (saved && DICT[saved]) return saved;
} catch (e) {}
// fall back to browser preference, default English
const nav = (navigator.language || "en").slice(0, 2).toLowerCase();
return DICT[nav] ? nav : "en";
});
const setLang = React.useCallback((next) => {
if (!DICT[next]) return;
setLangState(next);
try { localStorage.setItem(LANG_STORAGE_KEY, next); } catch (e) {}
}, []);
React.useEffect(() => {
document.documentElement.lang = lang;
}, [lang]);
const value = { lang, setLang, t: DICT[lang] };
return