Web: Doceditor: added i18n implementation on server side
This commit is contained in:
parent
d927c64764
commit
66411680fb
@ -1,12 +0,0 @@
|
||||
const localesFolder = "./public/locales";
|
||||
const fs = require("fs");
|
||||
|
||||
const availableLocales = fs.readdirSync(localesFolder);
|
||||
|
||||
module.exports = {
|
||||
i18n: {
|
||||
defaultLocale: "en",
|
||||
locales: availableLocales,
|
||||
defaultNS: "Editor",
|
||||
},
|
||||
};
|
@ -18,6 +18,7 @@ import {
|
||||
|
||||
import { EditorWrapper } from "./StyledEditor";
|
||||
import DynamicComponent from "./components/dynamic";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const { homepage } = pkg;
|
||||
|
||||
@ -148,6 +149,9 @@ export default function Editor({
|
||||
const [documentTitle, setNewDocumentTitle] = useState("Loading...");
|
||||
const [faviconHref, setFaviconHref] = useState("/favicon.ico"); // try without state
|
||||
|
||||
const [t] = useTranslation();
|
||||
// console.log(t, i18n);
|
||||
|
||||
useEffect(() => {
|
||||
if (error) {
|
||||
error?.unAuthorized &&
|
||||
@ -500,7 +504,7 @@ export default function Editor({
|
||||
goBack = {
|
||||
blank: true,
|
||||
requestClose: false,
|
||||
text: 't("FileLocation")',
|
||||
text: t("FileLocation"),
|
||||
url: `${combineUrl(filesUrl, `/filter?${urlFilter}`)}`,
|
||||
};
|
||||
}
|
||||
|
@ -1,16 +1,32 @@
|
||||
import React from "react";
|
||||
import React, { Suspense } from "react";
|
||||
import { hydrate } from "react-dom";
|
||||
import { registerSW } from "@appserver/common/sw/helper";
|
||||
import App from "../App.js";
|
||||
import { useSSR } from "react-i18next";
|
||||
import "../i18n";
|
||||
|
||||
const propsObj = window.__ASC_INITIAL_STATE__;
|
||||
const initialI18nStore = window.initialI18nStore;
|
||||
const initialLanguage = window.initialLanguage;
|
||||
|
||||
delete window.__ASC_INITIAL_STATE__;
|
||||
delete window.initialI18nStore;
|
||||
delete window.initialLanguage;
|
||||
|
||||
const stateJS = document.getElementById("__ASC_INITIAL_STATE__");
|
||||
stateJS.parentNode.removeChild(stateJS);
|
||||
|
||||
const { props } = propsObj;
|
||||
|
||||
hydrate(<App {...props} />, document.getElementById("root"));
|
||||
const AppWrapper = () => {
|
||||
useSSR(initialI18nStore, initialLanguage);
|
||||
return (
|
||||
<Suspense fallback={<div />}>
|
||||
<App {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
|
||||
hydrate(<AppWrapper />, document.getElementById("root"));
|
||||
|
||||
registerSW();
|
||||
|
@ -1,6 +1,5 @@
|
||||
import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import Backend from "i18next-http-backend";
|
||||
import config from "../package.json";
|
||||
import { LANGUAGE } from "@appserver/common/constants";
|
||||
import { loadLanguagePath } from "@appserver/common/utils";
|
||||
@ -9,10 +8,7 @@ const newInstance = i18n.createInstance();
|
||||
|
||||
const lng = localStorage.getItem(LANGUAGE) || "en";
|
||||
|
||||
newInstance
|
||||
.use(initReactI18next)
|
||||
.use(Backend)
|
||||
.init({
|
||||
newInstance.use(initReactI18next).init({
|
||||
lng: lng,
|
||||
fallbackLng: "en",
|
||||
load: "currentOnly",
|
||||
|
@ -2,8 +2,38 @@ import express from "express";
|
||||
import path from "path";
|
||||
import template from "./server/template";
|
||||
import render from "./server/render";
|
||||
import i18nextMiddleware from "i18next-express-middleware";
|
||||
import i18next from "i18next";
|
||||
import Backend from "i18next-node-fs-backend";
|
||||
|
||||
const app = express();
|
||||
const port = process.env.PORT || 5013;
|
||||
|
||||
i18next.use(Backend).init({
|
||||
backend: {
|
||||
loadPath:
|
||||
path.resolve(process.cwd(), "clientBuild") +
|
||||
"/locales/{{lng}}/{{ns}}.json",
|
||||
allowMultiLoading: true,
|
||||
crossDomain: false,
|
||||
},
|
||||
fallbackLng: "en",
|
||||
load: "currentOnly",
|
||||
|
||||
saveMissing: true,
|
||||
ns: ["Editor", "Common"],
|
||||
defaultNS: "Editor",
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
format: function (value, format) {
|
||||
if (format === "lowercase") return value.toLowerCase();
|
||||
return value;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
app.use(i18nextMiddleware.handle(i18next));
|
||||
|
||||
app.use(
|
||||
"/products/files/doceditor/static/",
|
||||
@ -11,24 +41,37 @@ app.use(
|
||||
);
|
||||
app.use(express.static(path.resolve(__dirname, "../clientBuild")));
|
||||
|
||||
app.disable("x-powered-by");
|
||||
|
||||
const port = process.env.PORT || 5013;
|
||||
|
||||
app.get("/products/files/doceditor", async (req, res) => {
|
||||
const { props, content, styleTags, scriptTags } = await render(req);
|
||||
const userLng = props?.props?.user?.cultureName || "en";
|
||||
|
||||
i18next.changeLanguage(userLng).then(() => {
|
||||
const initialLanguage = userLng;
|
||||
const initialI18nStore = {};
|
||||
const usedNamespaces = req.i18n.reportNamespaces.getUsedNamespaces();
|
||||
|
||||
initialI18nStore[initialLanguage] = {};
|
||||
|
||||
usedNamespaces.forEach((namespace) => {
|
||||
initialI18nStore[initialLanguage][namespace] =
|
||||
req.i18n.services.resourceStore.data[initialLanguage][namespace];
|
||||
});
|
||||
|
||||
const response = template(
|
||||
"Server Rendered Page",
|
||||
props,
|
||||
content,
|
||||
styleTags,
|
||||
scriptTags
|
||||
scriptTags,
|
||||
initialI18nStore,
|
||||
initialLanguage
|
||||
);
|
||||
res.setHeader("Cache-Control", "assets, max-age=604800");
|
||||
|
||||
res.send(response);
|
||||
});
|
||||
//app.get("/", (req, res) => console.log("root", req));
|
||||
const isDevelopment = process.env.NODE_ENV === "development";
|
||||
});
|
||||
|
||||
app.listen(port, () => console.log(`server listen port: ${port}`));
|
||||
app.listen(port, (err) => {
|
||||
console.log(`Server is listening on port ${port}`);
|
||||
});
|
||||
|
@ -5,6 +5,7 @@ import { initDocEditor } from "../helpers/utils";
|
||||
import { ServerStyleSheet } from "styled-components";
|
||||
import { ChunkExtractor } from "@loadable/server";
|
||||
import path from "path";
|
||||
import { I18nextProvider } from "react-i18next";
|
||||
const sheet = new ServerStyleSheet();
|
||||
const statsFile = path.resolve("clientBuild/stats.json");
|
||||
export default async (req) => {
|
||||
@ -13,7 +14,13 @@ export default async (req) => {
|
||||
const extractor = new ChunkExtractor({ statsFile });
|
||||
const scriptTags = extractor.getScriptTags();
|
||||
|
||||
const content = renderToString(sheet.collectStyles(<App />));
|
||||
const content = renderToString(
|
||||
sheet.collectStyles(
|
||||
<I18nextProvider i18n={req.i18n}>
|
||||
<App />
|
||||
</I18nextProvider>
|
||||
)
|
||||
);
|
||||
const styleTags = sheet.getStyleTags();
|
||||
|
||||
return { props, content, styleTags, scriptTags };
|
||||
|
@ -3,13 +3,19 @@ export default function template(
|
||||
initialState = {},
|
||||
content = "",
|
||||
styleTags,
|
||||
scriptTags
|
||||
scriptTags,
|
||||
initialI18nStore,
|
||||
initialLanguage
|
||||
) {
|
||||
const { docApiUrl } = initialState.props;
|
||||
|
||||
const scripts = `
|
||||
<script id="__ASC_INITIAL_STATE__">
|
||||
window.__ASC_INITIAL_STATE__ = ${JSON.stringify(initialState)}
|
||||
window.initialI18nStore = JSON.parse('${JSON.stringify(
|
||||
initialI18nStore
|
||||
)}')
|
||||
window.initialLanguage = '${initialLanguage}'
|
||||
</script>
|
||||
<script type='text/javascript' id='scripDocServiceAddress' src="${docApiUrl}" async></script>
|
||||
${scriptTags}
|
||||
|
Loading…
Reference in New Issue
Block a user