Просмотр исходного кода

Merge branch 'support/apply-nextjs-2' into imprv/99346-next-Growi-SubNavigation

yuken 3 лет назад
Родитель
Сommit
f3b7d7305d

+ 6 - 0
packages/app/public/static/locales/en_US/translation.json

@@ -1,4 +1,7 @@
 {
+  "meta": {
+    "display_name": "English"
+  },
   "Help": "Help",
   "view": "View",
   "Edit": "Edit",
@@ -195,6 +198,9 @@
     "page_not_exist": "This page does not exist.",
     "page_not_exist_alert": "This page does not exist. Please create a new page."
   },
+  "not_creatable_page": {
+    "could_not_creata_path": "Couldn't create path."
+  },
   "custom_navigation": {
     "no_page_list": "There are no pages under this page.",
     "link_sharing_is_disabled": "Link sharing is disabled."

+ 6 - 0
packages/app/public/static/locales/ja_JP/translation.json

@@ -1,4 +1,7 @@
 {
+  "meta": {
+    "display_name": "日本語"
+  },
   "Help": "ヘルプ",
   "view": "View",
   "Edit": "編集",
@@ -197,6 +200,9 @@
     "page_not_exist": "このページは存在しません。",
     "page_not_exist_alert": "このページは存在しません。新たに作成する必要があります。"
   },
+  "not_creatable_page": {
+    "could_not_creata_path": "パスを作成できませんでした。"
+  },
   "custom_navigation": {
     "no_page_list": "このページの配下にはページが存在しません。",
     "link_sharing_is_disabled": "リンクのシェアは無効化されています"

+ 6 - 0
packages/app/public/static/locales/zh_CN/translation.json

@@ -1,4 +1,7 @@
 {
+  "meta": {
+    "display_name": "简体中文"
+  },
   "Help": "帮助",
   "view": "View",
 	"Edit": "编辑",
@@ -195,6 +198,9 @@
     "page_not_exist": "该页面不存在",
     "page_not_exist_alert": "该页面不存在,请创建一个新页面"
   },
+  "not_creatable_page": {
+    "could_not_creata_path": "无法创建路径"
+  },
   "custom_navigation": {
     "no_page_list": "There are no pages under this page.",
     "link_sharing_is_disabled": "链接共享已被禁用"

+ 4 - 0
packages/app/src/client/util/i18n.js

@@ -1,3 +1,4 @@
+
 /* eslint-disable */
 import i18n from 'i18next';
 import LanguageDetector from 'i18next-browser-languagedetector';
@@ -15,6 +16,9 @@ Object.values(locales).forEach((locale) => {
   });
 });
 
+/*
+* Note: This file will be deleted. use "~/next-i18next.config" instead
+*/
 // extract metadata list from 'public/static/locales/${locale}/meta.json'
 export const localeMetadatas = Object.values(locales).map(locale => locale.meta);
 

+ 23 - 18
packages/app/src/components/Admin/App/AppSetting.jsx

@@ -1,11 +1,11 @@
 import React, { useCallback } from 'react';
 
+import { useTranslation, i18n } from 'next-i18next';
 import PropTypes from 'prop-types';
-import { useTranslation } from 'next-i18next';
 
 import AdminAppContainer from '~/client/services/AdminAppContainer';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
-import { localeMetadatas } from '~/client/util/i18n';
+import { i18n as i18nConfig } from '~/next-i18next.config';
 import loggerFactory from '~/utils/logger';
 
 
@@ -77,22 +77,27 @@ const AppSetting = (props) => {
         </label>
         <div className="col-md-6 py-2">
           {
-            localeMetadatas.map(meta => (
-              <div key={meta.id} className="custom-control custom-radio custom-control-inline">
-                <input
-                  type="radio"
-                  id={`radioLang${meta.id}`}
-                  className="custom-control-input"
-                  name="globalLang"
-                  value={meta.id}
-                  checked={adminAppContainer.state.globalLang === meta.id}
-                  onChange={(e) => {
-                    adminAppContainer.changeGlobalLang(e.target.value);
-                  }}
-                />
-                <label className="custom-control-label" htmlFor={`radioLang${meta.id}`}>{meta.displayName}</label>
-              </div>
-            ))
+            i18nConfig.locales.map((locale) => {
+              const fixedT = i18n.getFixedT(locale);
+              i18n.loadLanguages(i18nConfig.locales);
+
+              return (
+                <div key={locale} className="custom-control custom-radio custom-control-inline">
+                  <input
+                    type="radio"
+                    id={`radioLang${locale}`}
+                    className="custom-control-input"
+                    name="globalLang"
+                    value={locale}
+                    checked={adminAppContainer.state.globalLang === locale}
+                    onChange={(e) => {
+                      adminAppContainer.changeGlobalLang(e.target.value);
+                    }}
+                  />
+                  <label className="custom-control-label" htmlFor={`radioLang${locale}`}>{fixedT('meta.display_name')}</label>
+                </div>
+              );
+            })
           }
         </div>
       </div>

+ 1 - 2
packages/app/src/components/Admin/App/AppSettingsPageContents.tsx

@@ -58,8 +58,7 @@ const AppSettingsPageContents = (props: Props) => {
       <div className="row">
         <div className="col-lg-12">
           <h2 className="admin-setting-header">{t('App Settings')}</h2>
-          {/* TODO: show AppSetting by https://redmine.weseek.co.jp/issues/100056 */}
-          {/* <AppSetting /> */}
+          <AppSetting />
         </div>
       </div>
 

+ 18 - 0
packages/app/src/components/NotCreatablePage.tsx

@@ -0,0 +1,18 @@
+import React, { FC } from 'react';
+
+import { useTranslation } from 'next-i18next';
+
+export const NotCreatablePage: FC = () => {
+  const { t } = useTranslation();
+
+  return (
+    <div className="row not-found-message-row">
+      <div className="col-md-12">
+        <h2 className="text-muted">
+          <i className="icon-ban mr-1" aria-hidden="true"></i>
+          { t('not_creatable_page.could_not_creata_path') }
+        </h2>
+      </div>
+    </div>
+  );
+};

+ 5 - 2
packages/app/src/components/Page/DisplaySwitcher.tsx

@@ -8,7 +8,7 @@ import { TabContent, TabPane } from 'reactstrap';
 import { smoothScrollIntoView } from '~/client/util/smooth-scroll';
 import { isPopulated } from '~/interfaces/common';
 import {
-  useCurrentPagePath, useIsSharedUser, useIsEditable, useIsUserPage, usePageUser, useShareLinkId, useIsNotFound,
+  useCurrentPagePath, useIsSharedUser, useIsEditable, useIsUserPage, usePageUser, useShareLinkId, useIsNotFound, useIsNotCreatable,
 } from '~/stores/context';
 import { useDescendantsPageListModal } from '~/stores/modal';
 import { useSWRxCurrentPage } from '~/stores/page';
@@ -16,6 +16,7 @@ import { EditorMode, useEditorMode } from '~/stores/ui';
 
 import CountBadge from '../Common/CountBadge';
 import PageListIcon from '../Icons/PageListIcon';
+import { NotCreatablePage } from '../NotCreatablePage';
 import NotFoundPage from '../NotFoundPage';
 import { Page } from '../Page';
 // import PageEditor from '../PageEditor';
@@ -46,6 +47,7 @@ const DisplaySwitcher = (): JSX.Element => {
   const { data: isEditable } = useIsEditable();
   const { data: pageUser } = usePageUser();
   const { data: isNotFound } = useIsNotFound();
+  const { data: isNotCreatable } = useIsNotCreatable();
   const { data: currentPage } = useSWRxCurrentPage(shareLinkId ?? undefined);
 
   const { data: editorMode } = useEditorMode();
@@ -115,7 +117,8 @@ const DisplaySwitcher = (): JSX.Element => {
             <div className="flex-grow-1 flex-basis-0 mw-0">
               { isUserPage && <UserInfo pageUser={pageUser} />}
               { !isNotFound && <Page /> }
-              { isNotFound && <NotFoundPage /> }
+              { isNotFound && !isNotCreatable && <NotFoundPage /> }
+              { isNotFound && isNotCreatable && <NotCreatablePage /> }
             </div>
 
           </div>

+ 4 - 0
packages/app/src/pages/[[...path]].page.tsx

@@ -92,6 +92,7 @@ type Props = CommonProps & {
   isIdenticalPathPage?: boolean,
   isForbidden: boolean,
   isNotFound: boolean,
+  IsNotCreatable: boolean,
   // isAbleToDeleteCompletely: boolean,
 
   isSearchServiceConfigured: boolean,
@@ -160,6 +161,7 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   // useOwnerOfCurrentPage(props.pageUser != null ? JSON.parse(props.pageUser) : null);
   useIsForbidden(props.isForbidden);
   useIsNotFound(props.isNotFound);
+  useIsNotCreatable(props.IsNotCreatable);
   // useIsTrashPage(_isTrashPage(props.currentPagePath));
   // useShared();
   // useShareLinkId(props.shareLinkId);
@@ -365,6 +367,8 @@ async function injectRoutingInformation(context: GetServerSidePropsContext, prop
   else if (page == null) {
     props.isNotFound = true;
 
+    props.IsNotCreatable = !isCreatablePage(currentPathname);
+
     // check the page is forbidden or just does not exist.
     const count = isPermalink ? await Page.count({ _id: pageId }) : await Page.count({ path: currentPathname });
     props.isForbidden = count > 0;