From c779eba4698f0c3fe197d2c42268ac048075a00c Mon Sep 17 00:00:00 2001 From: Dobromir Popov Date: Mon, 29 Apr 2024 01:28:59 +0300 Subject: [PATCH] translation system working now --- pages/_app.tsx | 12 +++- pages/api/translations/[...locale].ts | 81 +++++++++++++++++++++------ pages/cart/translations/index.tsx | 72 ++++++++++++++---------- 3 files changed, 114 insertions(+), 51 deletions(-) diff --git a/pages/_app.tsx b/pages/_app.tsx index 084c2db..afb21f2 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -33,10 +33,18 @@ export default function App({ Component, pageProps: { session, ...pageProps }, } useEffect(() => { console.log("Current locale:", router.locale); async function loadLocaleData() { - const localeMessages = await import(`../content/i18n/${router.locale}.json`); + // Replace the static import with a fetch request + const res = await fetch(`/api/translations/${router.locale}`); + if (res.ok) { + const localeMessages = await res.json(); + console.log("Loaded messages for locale:", router.locale, localeMessages); + setMessages(localeMessages); + } else { + const localeMessages = await import(`../content/i18n/${router.locale}.json`); setMessages(localeMessages.default); + } console.log("Loaded locale '", router.locale, "' ",); //console.log("Loaded messages for locale:", router.locale, localeMessages.default); - setMessages(localeMessages.default); + } loadLocaleData(); }, [router.locale]); diff --git a/pages/api/translations/[...locale].ts b/pages/api/translations/[...locale].ts index 84cb6c7..4deebec 100644 --- a/pages/api/translations/[...locale].ts +++ b/pages/api/translations/[...locale].ts @@ -1,37 +1,82 @@ +import { NextApiRequest, NextApiResponse } from 'next'; import fs from 'fs'; import path from 'path'; -import { NextApiRequest, NextApiResponse } from 'next'; +import common from "../../../src/helpers/common"; + +function flattenTranslations(data) { + const result = {}; + + function recurse(cur, prop) { + if (Object(cur) !== cur) { + result[prop] = cur; + } else if (Array.isArray(cur)) { + for (let i = 0, l = cur.length; i < l; i++) + recurse(cur[i], prop ? prop + "." + i : "" + i); + if (l == 0) + result[prop] = []; + } else { + let isEmpty = true; + for (let p in cur) { + isEmpty = false; + recurse(cur[p], prop ? prop + "." + p : p); + } + if (isEmpty) + result[prop] = {}; + } + } + recurse(data, ""); + return result; +} + +function unflattenTranslations(data) { + const result = {}; + + for (let i in data) { + const keys = i.split('.'); + keys.reduce((r, e, j) => { + return r[e] || (r[e] = isNaN(Number(keys[j + 1])) ? (keys.length - 1 === j ? data[i] : {}) : []); + }, result); + } + return result; +} export default async function handler(req: NextApiRequest, res: NextApiResponse) { - const { locale, type } = req.query; - const baseFilePath = path.join(process.cwd(), `content/i18n/${locale}.json`); + const { locale } = req.query; + const filePath = path.join(process.cwd(), `content/i18n/${locale.join(".")}.json`); const modifiedFilePath = path.join(process.cwd(), `content/i18n/${locale}.modified.json`); - let translations = {}; - - try { - translations = JSON.parse(fs.readFileSync(baseFilePath, 'utf8')); - if (fs.existsSync(modifiedFilePath)) { - const modifiedTranslations = JSON.parse(fs.readFileSync(modifiedFilePath, 'utf8')); - translations = { ...translations, ...modifiedTranslations }; - } - } catch (error) { - console.error('Error loading translation files:', error); - } - switch (req.method) { case 'GET': - res.status(200).json(translations); + let flat = common.parseBool(req.query.flat); + try { + const fileContents = fs.readFileSync(filePath, 'utf8'); + let translations = JSON.parse(fileContents); + if (fs.existsSync(modifiedFilePath)) { + const modifiedTranslations = JSON.parse(fs.readFileSync(modifiedFilePath, 'utf8')); + translations = { ...translations, ...modifiedTranslations }; + } + if (flat) { + translations = flattenTranslations(translations); + } + res.status(200).json(translations); + } catch (error) { + console.error('Error reading translation file:', error); + res.status(500).json({ error: 'Failed to read translation file' }); + } break; + case 'POST': try { - fs.writeFileSync(modifiedFilePath, JSON.stringify(req.body, null, 2), 'utf8'); + const newTranslations = req.body; + const reconstructedTranslations = unflattenTranslations(newTranslations); + fs.writeFileSync(filePath, JSON.stringify(reconstructedTranslations, null, 2), 'utf8'); res.status(200).json({ status: 'Updated' }); } catch (error) { - console.error('Error writing modified translation file:', error); + console.error('Error writing translation file:', error); res.status(500).json({ error: 'Failed to update translation file' }); } break; + default: res.setHeader('Allow', ['GET', 'POST']); res.status(405).end(`Method ${req.method} Not Allowed`); diff --git a/pages/cart/translations/index.tsx b/pages/cart/translations/index.tsx index e272f7f..782c4f7 100644 --- a/pages/cart/translations/index.tsx +++ b/pages/cart/translations/index.tsx @@ -2,16 +2,22 @@ import axiosInstance from '../../../src/axiosSecure'; import { useState, useEffect } from 'react'; import ProtectedRoute from "../../../components/protectedRoute"; import { UserRole } from "@prisma/client"; +import Layout from 'components/layout'; +import { useRouter } from "next/router"; -// Simulate importing locales from a config or define directly here -const locales = ['en', 'bg', 'ru']; +const locales = ['bg', 'en', 'ru']; const AdminTranslations = () => { const [translations, setTranslations] = useState({}); - const [locale, setLocale] = useState('en'); + // set locale to the current locale by default. get it from the useRouter + let router = useRouter(); + + const [locale, setLocale] = useState(router.locale); + const [baseTranslations, setBaseTranslations] = useState(locales[0]); useEffect(() => { - axiosInstance.get(`/api/translations/${locale}`).then(res => setTranslations(res.data)); + axiosInstance.get(`/api/translations/${locale}?flat=true`).then(res => setTranslations(res.data)); + axiosInstance.get(`/api/translations/${locales[0]}?flat=true`).then(res => setBaseTranslations(res.data)); }, [locale]); const handleSave = () => { @@ -28,34 +34,38 @@ const AdminTranslations = () => { }; return ( - -
-

Edit Translations

- - - - {Object.entries(translations).map(([key, value]) => ( - - - - + + + +
+

Edit Translations

+
-
{key} - handleChange(key, e.target.value)} - style={{ width: '100%' }} - /> -
- -
-
+ + + + {Object.entries(translations).map(([key, value]) => ( + + + + + + ))} + +
{key}{baseTranslations[key]} + handleChange(key, e.target.value)} + style={{ width: '100%' }} + /> +
+ + + + ); };