diff --git a/i18n/index.js b/i18n/index.js new file mode 100644 index 00000000..d0b3ae96 --- /dev/null +++ b/i18n/index.js @@ -0,0 +1,14 @@ +const en = require("./translations.en.json"); +const es = require("./translations.es.json"); + +const i18n = { + translations: { + en, + es, + }, + defaultLang: "en", + useBrowserDefault: true, + languageDataStore: "localStorage", +}; + +module.exports = i18n; diff --git a/i18n/translations.en.json b/i18n/translations.en.json new file mode 100644 index 00000000..592ceea3 --- /dev/null +++ b/i18n/translations.en.json @@ -0,0 +1,3 @@ +{ + "tagline": "An open source Flash Player emulator" +} diff --git a/i18n/translations.es.json b/i18n/translations.es.json new file mode 100644 index 00000000..a45cc1ca --- /dev/null +++ b/i18n/translations.es.json @@ -0,0 +1,3 @@ +{ + "tagline": "Un emulador de Flash Player de código abierto" +} diff --git a/package-lock.json b/package-lock.json index 63f08f6c..b6e06ea8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "feed": "^4.2.2", "gray-matter": "^4.0.3", "jsdom": "^25.0.1", + "next-export-i18n": "^3.0.0", "octokit": "^4.0.2", "postcss": "^8.4.49", "postcss-preset-mantine": "^1.17.0", @@ -6393,6 +6394,16 @@ "dev": true, "license": "MIT" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -6472,6 +6483,21 @@ } } }, + "node_modules/next-export-i18n": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/next-export-i18n/-/next-export-i18n-3.0.0.tgz", + "integrity": "sha512-OMp4L9rLD9OC7f2AcQj7XC2oi1sh4mIiAg61lO+gKBRubypjQ/UHXC8nGES4wJpweYH0HYwHcA6H4H8K2NXn5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mustache": "^4.2.0" + }, + "peerDependencies": { + "next": ">=13.0.0", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", diff --git a/package.json b/package.json index 01319622..0d05f65f 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "feed": "^4.2.2", "gray-matter": "^4.0.3", "jsdom": "^25.0.1", + "next-export-i18n": "^3.0.0", "octokit": "^4.0.2", "postcss": "^8.4.49", "postcss-preset-mantine": "^1.17.0", diff --git a/src/app/globals.css b/src/app/globals.css index 31275902..4cd4a9cb 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -2,3 +2,6 @@ a:link, a:visited { color: var(--ruffle-orange-3); } +span[data-language-switcher] { + display: none; +} diff --git a/src/app/page.tsx b/src/app/page.tsx index c1e2eee1..8bf7459e 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,6 +1,7 @@ "use client"; import dynamic from "next/dynamic"; +import { useTranslation } from "next-export-i18n"; import classes from "./index.module.css"; import { Container, @@ -26,6 +27,7 @@ const Installers = dynamic(() => import("./installers"), { }); export default function Home() { + const { t } = useTranslation(); const [latest, setLatest] = React.useState(null); React.useEffect(() => { @@ -45,8 +47,8 @@ export default function Home() { - - An open source Flash Player emulator + <Title className={classes.title} suppressHydrationWarning> + {t("tagline")}
{ + if (typeof window !== "undefined") { + const browserLang = + window.navigator.language || window.navigator.languages + ? (window.navigator.language || window.navigator.languages[0]) + .split("-")[0] + .toLowerCase() + : "en"; + setSelectedLang(browserLang); + const selectedLang = window.localStorage + ? window.localStorage.getItem("next-export-i18n-lang") + : null; + if (selectedLang) { + setSelectedLang(selectedLang); + } + } + }, []); + + const handleLanguageChange = (event) => { + const newLang = event.target.value; + setSelectedLang(newLang); + // Trigger the LanguageSwitcher programmatically + document + .querySelector( + `[data-language-switcher][aria-label='set language to ${newLang}']`, + ) + .click(); + }; + const [opened, { toggle, close }] = useDisclosure(false); const pathname = usePathname(); @@ -43,7 +79,7 @@ export function Header() { return (
- + {items} + {" "} + {Object.keys(languages).map((langCode) => ( + + {languages[langCode]} + + ))} {items} +