Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/MC-World-Compressor/Frontend/llms.txt

Use this file to discover all available pages before exploring further.

Overview

MC World Compressor supports multiple languages with automatic detection based on browser preferences. The i18n system uses Next.js middleware for locale routing and a custom translation hook for component-level translations.

Supported Locales

From lib/i18n.js:1-11:
export const i18n = {
  defaultLocale: 'en',
  locales: ['en', 'es', 'hi', 'ar'],
};

export const Locale = {
  ES: 'es',
  EN: 'en',
  HI: 'hi',
  AR: 'ar',
};

English (en)

Default locale

Spanish (es)

Español

Hindi (hi)

हिन्दी

Arabic (ar)

العربية (RTL support)

Locale Detection

The middleware automatically detects and redirects users to the appropriate locale.

Detection Logic

From middleware.js:4-28:
function getLocale(request) {
  // 1. Verificar si ya hay un locale en la URL
  const pathname = request.nextUrl.pathname;
  const pathnameIsMissingLocale = i18n.locales.every(
    (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
  );
  
  if (!pathnameIsMissingLocale) return;

  // 2. Obtener locale del header Accept-Language
  const acceptLanguage = request.headers.get('accept-language');
  
  if (acceptLanguage) {
    // Extraer los idiomas del header y buscar el primero soportado
    const accepted = acceptLanguage.split(',').map(l => l.split(';')[0].trim().slice(0,2));
    for (const lang of accepted) {
      if (i18n.locales.includes(lang)) {
        return lang;
      }
    }
  }

  // 3. Fallback al idioma por defecto
  return i18n.defaultLocale;
}

Detection Priority

1

URL Locale

First, check if the URL already contains a locale (e.g., /en/upload or /es/upload)
2

Accept-Language Header

If no locale in URL, parse the browser’s Accept-Language header to find a supported language
3

Default Fallback

If no match is found, fall back to the default locale (en)

URL Routing

All routes are prefixed with the locale:
/en/upload          → English upload page
/es/upload          → Spanish upload page
/hi/status/123      → Hindi status page
/ar                 → Arabic home page

Middleware Redirect

From middleware.js:30-57:
export function middleware(request) {
  const pathname = request.nextUrl.pathname;
  
  // Verificar si la ruta ya tiene un locale
  const pathnameIsMissingLocale = i18n.locales.every(
    (locale) => !pathname.startsWith(`/${locale}/`) && pathname !== `/${locale}`
  );

  // Redireccionar si no hay locale en la URL
  if (pathnameIsMissingLocale) {
    const locale = getLocale(request);
    if (pathname === '/' || pathname === '') {
      return NextResponse.redirect(new URL(`/${locale}`, request.url));
    }
    let newPath = `/${locale}${pathname.startsWith('/') ? '' : '/'}${pathname}`;
    if (newPath === `/${locale}`) {
      newPath = `/${locale}/`;
    }
    return NextResponse.redirect(new URL(newPath, request.url));
  }

  // Al final, añade el header con el locale:
  const response = NextResponse.next();
  const pathLocale = pathname.split('/')[1];
  const locale = i18n.locales.includes(pathLocale) ? pathLocale : i18n.defaultLocale;
  response.headers.set('x-path-locale', locale);
  return response;
}
Visiting /upload automatically redirects to /en/upload (or your browser’s preferred language)

Translation System

Translations are stored in JSON files and accessed via custom hooks.

Translation Files Structure

From lib/translations.js:1-6:
import es from '../locales/es.json';
import en from '../locales/en.json';
import hi from '../locales/hi.json';
import ar from "../locales/ar.json";

const translations = { en, es, hi, ar };
Translation files are located in /locales/ and contain nested JSON objects:
{
  "home": {
    "title": "Minecraft World Compressor",
    "subtitle": "Reduce your world size by up to",
    "compressButton": "Compress Now"
  },
  "upload": {
    "title": "Upload Your World",
    "dragDrop": "Drag and drop your world here"
  }
}

Using Translations in Client Components

The useTranslations hook is for client-side components: From lib/translations.js:12-27:
export function useTranslations(locale = "en") {
  const t = (key, varsOrDefault = key) => {
    let translation = getNestedTranslation(translations[locale], key) 
      || getNestedTranslation(translations.en, key) 
      || key;
    
    if (typeof varsOrDefault === 'object' && varsOrDefault !== null) {
      Object.entries(varsOrDefault).forEach(([k, v]) => {
        translation = translation.replace(
          new RegExp(`{{\\s*${k}\\s*}}`, "g"),
          v
        );
      });
    }
    return translation;
  };
  return { t };
}

Example Usage

From app/[locale]/upload/page.js:5-17:
import { useTranslations } from '@/lib/translations';

export default function HomePage({ params }) {
  const [locale, setLocale] = useState(null);
  const { t } = useTranslations(locale || 'en');
  
  // Use in JSX:
  <h1>{t('upload.title')}</h1>
  <p>{t('upload.dragDrop')}</p>
  <button>{t('upload.selectFile')}</button>
}

Using Translations in Server Components

For server-side rendering, use getPageTranslations: From lib/translations.js:36-38:
export function getPageTranslations(locale, pageName) {
  return translations[locale]?.[pageName] || translations.en?.[pageName] || {};
}

Example Usage

From app/[locale]/page.js:52-54:
import { getPageTranslations } from '@/lib/translations';

export default async function Inicio({ params }) {
  const { locale } = await params;
  const t = getPageTranslations(locale, 'home');
  
  // Access translations directly:
  <h1>{t.title}</h1>
  <p>{t.subtitle}</p>
  <button>{t.compressButton}</button>
}

Variable Interpolation

The translation system supports variable substitution:
// Translation file:
{
  "welcome": "Welcome, {{name}}!"
}

// Usage:
const { t } = useTranslations('en');
t('welcome', { name: 'Steve' }); // Returns: "Welcome, Steve!"

Nested Translation Keys

Access nested translations using dot notation: From lib/translations.js:8-10:
function getNestedTranslation(obj, path) {
  return path.split(".").reduce((current, key) => current?.[key], obj);
}

Example

// Translation file:
{
  "upload": {
    "errors": {
      "sizeLimit": "File too large",
      "zipOnly": "Only ZIP files allowed"
    }
  }
}

// Usage:
t('upload.errors.sizeLimit')  // Returns: "File too large"

Fallback Behavior

  1. Requested locale: First, try to get the translation from the requested locale
  2. English fallback: If not found, fall back to English translation
  3. Key fallback: If still not found, return the key itself
This ensures users always see something meaningful, even if translations are incomplete.

Adding a New Language

To add support for a new language:
1

Create translation file

Create a new JSON file in /locales/ (e.g., fr.json for French)
2

Import in translations.js

import fr from '../locales/fr.json';
const translations = { en, es, hi, ar, fr };
3

Add to i18n config

export const i18n = {
  defaultLocale: 'en',
  locales: ['en', 'es', 'hi', 'ar', 'fr'],
};
4

Update Locale enum (optional)

export const Locale = {
  EN: 'en',
  ES: 'es',
  HI: 'hi',
  AR: 'ar',
  FR: 'fr',
};
Ensure all translation keys exist in the new language file, or they will fall back to English.

Middleware Configuration

The middleware applies to all routes except static files and API routes: From middleware.js:59-65:
export const config = {
  matcher: [
    // Excluir archivos estáticos y rutas de API
    '/((?!api|_next/static|_next/image|favicon.ico|.*\\..*|public).*)'
  ]
};
This ensures:
  • API routes (/api/*) are not redirected
  • Static files (/_next/*, /favicon.ico) load normally
  • Only page routes get locale prefixes

RTL Support

For right-to-left languages like Arabic, the application can detect and apply RTL styles based on the locale:
const isRTL = locale === 'ar';

<div dir={isRTL ? 'rtl' : 'ltr'}>
  {/* Content */}
</div>

Build docs developers (and LLMs) love