commons.ts 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import { DevidedPagePath, Lang, AllLang } from '@growi/core';
  2. import { GetServerSideProps, GetServerSidePropsContext } from 'next';
  3. import { SSRConfig, UserConfig } from 'next-i18next';
  4. import * as nextI18NextConfig from '^/config/next-i18next.config';
  5. import { SupportedActionType } from '~/interfaces/activity';
  6. import { CrowiRequest } from '~/interfaces/crowi-request';
  7. import { GrowiThemes } from '~/interfaces/theme';
  8. export type CommonProps = {
  9. namespacesRequired: string[], // i18next
  10. currentPathname: string,
  11. appTitle: string,
  12. siteUrl: string,
  13. confidential: string,
  14. theme: GrowiThemes,
  15. customTitleTemplate: string,
  16. csrfToken: string,
  17. isContainerFluid: boolean,
  18. growiVersion: string,
  19. isMaintenanceMode: boolean,
  20. redirectDestination: string | null,
  21. customizedLogoSrc?: string,
  22. } & Partial<SSRConfig>;
  23. // eslint-disable-next-line max-len
  24. export const getServerSideCommonProps: GetServerSideProps<CommonProps> = async(context: GetServerSidePropsContext) => {
  25. const req: CrowiRequest = context.req as CrowiRequest;
  26. const { crowi } = req;
  27. const {
  28. appService, configManager, customizeService,
  29. } = crowi;
  30. const url = new URL(context.resolvedUrl, 'http://example.com');
  31. const currentPathname = decodeURI(url.pathname);
  32. const isMaintenanceMode = appService.isMaintenanceMode();
  33. // eslint-disable-next-line max-len, no-nested-ternary
  34. const redirectDestination = !isMaintenanceMode && currentPathname === '/maintenance' ? '/' : isMaintenanceMode && !currentPathname.match('/admin/*') && !(currentPathname === '/maintenance') ? '/maintenance' : null;
  35. const props: CommonProps = {
  36. namespacesRequired: ['translation'],
  37. currentPathname,
  38. appTitle: appService.getAppTitle(),
  39. siteUrl: configManager.getConfig('crowi', 'app:siteUrl'), // DON'T USE appService.getSiteUrl()
  40. confidential: appService.getAppConfidential() || '',
  41. theme: configManager.getConfig('crowi', 'customize:theme'),
  42. customTitleTemplate: customizeService.customTitleTemplate,
  43. csrfToken: req.csrfToken(),
  44. isContainerFluid: configManager.getConfig('crowi', 'customize:isContainerFluid') ?? false,
  45. growiVersion: crowi.version,
  46. isMaintenanceMode,
  47. redirectDestination,
  48. customizedLogoSrc: configManager.getConfig('crowi', 'customize:customizedLogoSrc'),
  49. };
  50. return { props };
  51. };
  52. export const getNextI18NextConfig = async(
  53. // 'serverSideTranslations' method should be given from Next.js Page
  54. // because importing it in this file causes https://github.com/isaachinman/next-i18next/issues/1545
  55. serverSideTranslations: (
  56. initialLocale: string, namespacesRequired?: string[] | undefined, configOverride?: UserConfig | null, extraLocales?: string[] | false
  57. ) => Promise<SSRConfig>,
  58. context: GetServerSidePropsContext, namespacesRequired?: string[] | undefined, preloadAllLang = false,
  59. ): Promise<SSRConfig> => {
  60. const req: CrowiRequest = context.req as CrowiRequest;
  61. const { crowi, user } = req;
  62. const { configManager } = crowi;
  63. // determine language
  64. const locale = user?.lang
  65. ?? configManager.getConfig('crowi', 'app:globalLang') as Lang
  66. ?? Lang.en_US;
  67. const namespaces = ['commons'];
  68. if (namespacesRequired != null) {
  69. namespaces.push(...namespacesRequired);
  70. }
  71. // TODO: deprecate 'translation.json' in the future
  72. else {
  73. namespaces.push('translation');
  74. }
  75. return serverSideTranslations(locale, namespaces, nextI18NextConfig, preloadAllLang ? AllLang : false);
  76. };
  77. /**
  78. * Generate whole title string for the specified title
  79. * @param props
  80. * @param title
  81. */
  82. export const useCustomTitle = (props: CommonProps, title: string): string => {
  83. return props.customTitleTemplate
  84. .replace('{{sitename}}', props.appTitle)
  85. .replace('{{page}}', title)
  86. .replace('{{pagepath}}', title)
  87. .replace('{{pagename}}', title);
  88. };
  89. /**
  90. * Generate whole title string for the specified page path
  91. * @param props
  92. * @param pagePath
  93. */
  94. export const useCustomTitleForPage = (props: CommonProps, pagePath: string): string => {
  95. const dPagePath = new DevidedPagePath(pagePath, true, true);
  96. return props.customTitleTemplate
  97. .replace('{{sitename}}', props.appTitle)
  98. .replace('{{pagepath}}', pagePath)
  99. .replace('{{page}}', dPagePath.latter) // for backward compatibility
  100. .replace('{{pagename}}', dPagePath.latter);
  101. };