FPSMS-frontend
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

99 lines
2.8 KiB

  1. import { cookies, headers } from "next/headers";
  2. import { createInstance, i18n, LanguageDetectorAsyncModule } from "i18next";
  3. import resourcesToBackend from "i18next-resources-to-backend";
  4. import { getServerSession } from "next-auth";
  5. import { authOptions } from "@/config/authConfig";
  6. import I18nClientProvider from "./I18nClientProvider";
  7. import universalLanguageDetect from "@unly/universal-language-detector";
  8. const FALLBACK_LANG = "zh";
  9. const SUPPORTED_LANGUAGES = ["zh"];
  10. export const detectLanguage = async (): Promise<string> => {
  11. // Logic to get language preference from cookies/headers/session
  12. const cookiesList = cookies();
  13. const cookiesObj = cookiesList
  14. .getAll()
  15. .reduce<{ [name: string]: string }>(
  16. (acc, cookie) => ({ ...acc, [cookie.name]: cookie.value }),
  17. {},
  18. );
  19. const headersList = headers();
  20. console.time("[i18n] detectLanguage total");
  21. console.time("[i18n] getServerSession");
  22. const session = await getServerSession(authOptions);
  23. console.timeEnd("[i18n] getServerSession");
  24. console.time("[i18n] universalLanguageDetect");
  25. const lang = universalLanguageDetect({
  26. supportedLanguages: SUPPORTED_LANGUAGES,
  27. fallbackLanguage: FALLBACK_LANG,
  28. acceptLanguageHeader: headersList.get("accept-language") || undefined,
  29. serverCookies: cookiesObj,
  30. });
  31. console.timeEnd("[i18n] universalLanguageDetect");
  32. console.timeEnd("[i18n] detectLanguage total");
  33. return lang;
  34. };
  35. const languageDetector: LanguageDetectorAsyncModule = {
  36. type: "languageDetector",
  37. detect: detectLanguage,
  38. async: true,
  39. };
  40. const initI18next = async (namespaces: string[]): Promise<i18n> => {
  41. const label = `[i18n] initI18next ns=${namespaces.join(",")}`;
  42. console.time(label);
  43. const i18nInstance = createInstance();
  44. await i18nInstance
  45. .use(languageDetector)
  46. .use(
  47. resourcesToBackend((language: string, namespace: string) => {
  48. return import(`./${language}/${namespace}.json`);
  49. }),
  50. )
  51. .init({
  52. fallbackLng: "en",
  53. interpolation: {
  54. escapeValue: false,
  55. },
  56. ns: namespaces,
  57. });
  58. return i18nInstance as i18n;
  59. };
  60. export const getServerI18n = async (...namespaces: string[]) => {
  61. return initI18next(namespaces);
  62. };
  63. interface Props {
  64. children: React.ReactNode;
  65. namespaces: string[];
  66. }
  67. // Provides the resources for the client
  68. export const I18nProvider: React.FC<Props> = async ({
  69. children,
  70. namespaces,
  71. }) => {
  72. const i18n = await getServerI18n(...namespaces);
  73. const language = i18n.language;
  74. const resources = namespaces.reduce<{ [ns: string]: any }>(
  75. (acc, ns) => ({
  76. ...acc,
  77. [ns]: i18n.getResourceBundle(language, ns),
  78. }),
  79. {},
  80. );
  81. return (
  82. <I18nClientProvider
  83. language={language}
  84. resources={resources}
  85. namespaces={namespaces}
  86. >
  87. {children}
  88. </I18nClientProvider>
  89. );
  90. };