Dynamic Language Switching — i18n

Dynamic Language Switching User harus bisa mengganti bahasa kapan saja tanpa reload halaman. Pilihan bahasa harus di-persist agar tidak hilang saat kembali. Lan

Dynamic Language Switching

User harus bisa mengganti bahasa kapan saja tanpa reload halaman. Pilihan bahasa harus di-persist agar tidak hilang saat kembali.

Language Switcher Component

import { useTranslation } from "react-i18next";

const LANGUAGES = [
  { code: "id", label: "Bahasa Indonesia", flag: "🇮🇩" },
  { code: "en", label: "English", flag: "🇺🇸" },
  { code: "ja", label: "日本語", flag: "🇯🇵" },
  { code: "ar", label: "العربية", flag: "🇸🇦" },
];

function LanguageSwitcher() {
  const { i18n } = useTranslation();

  const changeLanguage = async (code) => {
    await i18n.changeLanguage(code);
    document.documentElement.lang = code;
    document.documentElement.dir =
      ["ar", "he", "fa"].includes(code) ? "rtl" : "ltr";
    localStorage.setItem("preferred-language", code);
  };

  return (
    <select
      value={i18n.language}
      onChange={(e) => changeLanguage(e.target.value)}
    >
      {LANGUAGES.map(({ code, label, flag }) => (
        <option key={code} value={code}>
          {flag} {label}
        </option>
      ))}
    </select>
  );
}

Persistence Strategy

// Urutan deteksi bahasa (priority)
// 1. URL parameter (?lng=id)
// 2. localStorage
// 3. Cookie
// 4. Navigator language (browser setting)
// 5. Fallback language

// i18next LanguageDetector sudah handle ini
i18n.use(LanguageDetector).init({
  detection: {
    order: ["querystring", "localStorage", "cookie", "navigator"],
    lookupQuerystring: "lng",
    lookupLocalStorage: "i18nextLng",
    lookupCookie: "i18next",
    caches: ["localStorage", "cookie"],
  },
});

URL-based Language (Next.js)

// Strategi URL: /en/about, /id/about
// next.config.js
module.exports = {
  i18n: {
    locales: ["en", "id", "ja"],
    defaultLocale: "id",
    localeDetection: true,
  },
};

// Middleware: redirect berdasarkan Accept-Language
// middleware.ts
import createMiddleware from "next-intl/middleware";

export default createMiddleware({
  locales: ["en", "id", "ja"],
  defaultLocale: "id",
  localePrefix: "as-needed", // /about untuk default, /en/about untuk lainnya
});

Sync Language ke Server

// Kirim preferensi bahasa ke backend untuk
// email notifications, push notifications, dll
async function updateUserLanguage(locale) {
  // Update frontend
  await i18n.changeLanguage(locale);

  // Persist ke server
  await fetch("/api/user/preferences", {
    method: "PATCH",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ locale }),
  });
}

// Laravel: simpan di users table
// migration: $table->string("locale")->default("id");
// Middleware: App::setLocale($user->locale);

Loading State saat Switch

function LanguageSwitcher() {
  const { i18n } = useTranslation();
  const [loading, setLoading] = useState(false);

  const changeLanguage = async (code) => {
    setLoading(true);
    try {
      await i18n.changeLanguage(code);
    } finally {
      setLoading(false);
    }
  };

  return (
    <select disabled={loading} onChange={(e) => changeLanguage(e.target.value)}>
      {/* options */}
    </select>
  );
}

Yang akan kamu pelajari