diff --git a/package-lock.json b/package-lock.json index 80d1fd7862..9e54dd08b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22,16 +22,16 @@ "focus-trap-react": "^12.0.0", "formik": "^2.4.9", "http-proxy-middleware": "^3.0.5", - "i18next": "25.8.11", + "i18next": "26.0.7", "i18next-browser-languagedetector": "^8.2.1", - "i18next-http-backend": "^3.0.5", + "i18next-http-backend": "^3.0.6", "lodash": "^4.17.23", "react": "^19.2.4", "react-chartjs-2": "^5.3.1", "react-datepicker": "^8.8.0", "react-dom": "^19.2.4", "react-hotkeys-hook": "^5.2.4", - "react-i18next": "16.5.0", + "react-i18next": "17.0.4", "react-icons": "^5.5.0", "react-redux": "^9.2.0", "react-router": "^7.13.0", @@ -203,24 +203,24 @@ } }, "node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", + "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", "dev": true, - "license": "MIT", "optional": true, + "peer": true, "dependencies": { "@emnapi/wasi-threads": "1.2.1", "tslib": "^2.4.0" } }, "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", + "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", "dev": true, - "license": "MIT", "optional": true, + "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -1534,6 +1534,29 @@ "node": "^20.19.0 || >=22.12.0" } }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@rolldown/binding-win32-arm64-msvc": { "version": "1.0.0-rc.16", "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz", @@ -3927,29 +3950,26 @@ } }, "node_modules/i18next": { - "version": "25.8.11", - "resolved": "https://registry.npmjs.org/i18next/-/i18next-25.8.11.tgz", - "integrity": "sha512-LZ32llTLGludnddjLoijHV7TbmVubU5eJnsWf8taiuM3jmSfUuvBLuyDeubJKS1yBjLBgb7As124M4KWNcBvpw==", + "version": "26.0.7", + "resolved": "https://registry.npmjs.org/i18next/-/i18next-26.0.7.tgz", + "integrity": "sha512-f7tL/iw0VQsx4nC5oNxBM2RjM8alNys5KzyiQTU6A9TI5TI89py4/Ez1cKFvHiLWsvzOXvuGUES+Kk/A2WiANQ==", "funding": [ { "type": "individual", - "url": "https://locize.com" + "url": "https://www.locize.com/i18next" }, { "type": "individual", - "url": "https://locize.com/i18next.html" + "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" }, { "type": "individual", - "url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project" + "url": "https://www.locize.com" } ], "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.28.4" - }, "peerDependencies": { - "typescript": "^5" + "typescript": "^5 || ^6" }, "peerDependenciesMeta": { "typescript": { @@ -3967,9 +3987,9 @@ } }, "node_modules/i18next-http-backend": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.5.tgz", - "integrity": "sha512-QaWHnsxieEDcqKe+vo/RFqpiIFRi/KBqlOSPcUlvinBaISCeiTRCbtrazHAjtHtsLC66oDsROAH8frWkQzfMMQ==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/i18next-http-backend/-/i18next-http-backend-3.0.6.tgz", + "integrity": "sha512-mBOqy8993jtqAoj6XaI1XeC/8/9v6EPS+681ziegrPvTB0DoaCY7PpTS0SpY56qLMoS4OI1TZEM2Zf59zNh05w==", "license": "MIT", "dependencies": { "cross-fetch": "4.1.0" @@ -5501,19 +5521,19 @@ } }, "node_modules/react-i18next": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-16.5.0.tgz", - "integrity": "sha512-IMpPTyCTKxEj8klCrLKUTIUa8uYTd851+jcu2fJuUB9Agkk9Qq8asw4omyeHVnOXHrLgQJGTm5zTvn8HpaPiqw==", + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.4.tgz", + "integrity": "sha512-hQipmK4EF0y6RO6tt6WuqnmWpWYEXmQUUzecmMBuNsIgYd3smXcG4GtYPWhvgxn0pqMOItKlEO8H24HCs5hc3g==", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.27.6", + "@babel/runtime": "^7.29.2", "html-parse-stringify": "^3.0.1", "use-sync-external-store": "^1.6.0" }, "peerDependencies": { - "i18next": ">= 25.6.2", + "i18next": ">= 26.0.1", "react": ">= 16.8.0", - "typescript": "^5" + "typescript": "^5 || ^6" }, "peerDependenciesMeta": { "react-dom": { diff --git a/package.json b/package.json index 034aaad995..5fe6120a62 100644 --- a/package.json +++ b/package.json @@ -19,16 +19,16 @@ "focus-trap-react": "^12.0.0", "formik": "^2.4.9", "http-proxy-middleware": "^3.0.5", - "i18next": "25.8.11", + "i18next": "26.0.7", "i18next-browser-languagedetector": "^8.2.1", - "i18next-http-backend": "^3.0.5", + "i18next-http-backend": "^3.0.6", "lodash": "^4.17.23", "react": "^19.2.4", "react-chartjs-2": "^5.3.1", "react-datepicker": "^8.8.0", "react-dom": "^19.2.4", "react-hotkeys-hook": "^5.2.4", - "react-i18next": "16.5.0", + "react-i18next": "17.0.4", "react-icons": "^5.5.0", "react-redux": "^9.2.0", "react-router": "^7.13.0", @@ -67,6 +67,7 @@ "@types/node": "^25.3.0", "@types/react-dom": "^19.2.3", "@types/uuid": "^11.0.0", + "@vitejs/plugin-react": "^6.0.1", "eslint": "^9.39.2", "prop-types": "^15.8.1", "sass": "^1.97.3", @@ -74,7 +75,6 @@ "typescript-eslint": "^8.56.0", "uuid": "^13.0.0", "vite": "^8.0.9", - "@vitejs/plugin-react": "^6.0.1", "vitest": "^4.0.18" } } diff --git a/src/i18n/i18n.ts b/src/i18n/i18n.ts index 0c6af4e310..4a8b19122e 100644 --- a/src/i18n/i18n.ts +++ b/src/i18n/i18n.ts @@ -1,4 +1,4 @@ -import i18n from "i18next"; +import i18n, { FormatterModule } from "i18next"; import { initReactI18next } from "react-i18next"; import HttpBackend, { HttpBackendOptions } from "i18next-http-backend"; @@ -23,7 +23,7 @@ import trTRTrans from "./org/opencastproject/adminui/languages/lang-tr_TR.json"; import zhCNTrans from "./org/opencastproject/adminui/languages/lang-zh_CN.json"; import zhTWTrans from "./org/opencastproject/adminui/languages/lang-zh_TW.json"; import { getCurrentLanguageInformation } from "../utils/utils"; -import { format } from "date-fns/format"; +import { format as dateFnsFormat } from "date-fns/format"; // Assignment of language code to translation file // !!! If translation file of a new language is added, please add assignment here, too !!! @@ -47,11 +47,29 @@ const resources = { "zh-TW": { translation: zhTWTrans }, } as const; +const myFormatter: FormatterModule = { + type: "formatter", + init(_services, _i18nextOptions) {}, + format(value, format, lng, _options) { + if (value instanceof Date && format && lng) { + return dateFnsFormat(value, format, { + locale: getCurrentLanguageInformation(lng)?.dateLocale, + }); + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return value; + }, + add(_name, _fc) { }, + addCached(_name, _fc) { }, +}; + // Configuration of i18next i18n .use(HttpBackend) .use(LanguageDetector) .use(initReactI18next) + .use(myFormatter) .init({ resources, fallbackLng: "en-US", @@ -59,17 +77,9 @@ i18n interpolation: { escapeValue: false, - format: function (value, formatStr, lng) { - if (value instanceof Date && formatStr && lng) { - return format(value, formatStr, { - locale: getCurrentLanguageInformation(lng)?.dateLocale, - }); - } - - // eslint-disable-next-line @typescript-eslint/no-unsafe-return - return value; - }, + alwaysFormat: true, }, + react: { useSuspense: false, },