diff --git a/package.json b/package.json
index d4b45c7..71bd26d 100644
--- a/package.json
+++ b/package.json
@@ -37,14 +37,15 @@
"devDependencies": {
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.6.0",
+ "@formatjs/ts-transformer": "^3.13.20",
"@mui/icons-material": "^5.2.5",
"@mui/material": "^5.2.5",
"@types/express": "^4.17.11",
"@types/lodash": "^4.14.168",
"@types/morgan": "^1.9.2",
"@types/node": "^14.14.41",
- "@types/react": "^17.0.3",
- "@types/react-dom": "^17.0.3",
+ "@types/react": "^18.3.12",
+ "@types/react-dom": "^18.3.1",
"@types/yup": "^0.29.11",
"@typescript-eslint/eslint-plugin": "^6.7.4",
"@typescript-eslint/parser": "^6.7.4",
@@ -56,8 +57,9 @@
"nodemon": "^3.0.1",
"postcss": "^8.2.10",
"prettier": "^2.2.1",
- "react": "^17.0.2",
- "react-dom": "^17.0.2",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1",
+ "react-intl": "^6.8.4",
"rimraf": "^6.0.1",
"swr": "^2.2.4",
"terser-webpack-plugin": "^5.3.9",
diff --git a/src/frontend/components/App.tsx b/src/frontend/components/App.tsx
index 2a32d0d..de74fa4 100644
--- a/src/frontend/components/App.tsx
+++ b/src/frontend/components/App.tsx
@@ -1,10 +1,12 @@
import CssBaseline from '@mui/material/CssBaseline';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import React, { FunctionComponent, useEffect, useState } from 'react';
+import { IntlProvider } from 'react-intl';
import { mutate } from 'swr';
import { deleteEntry, patchEntry } from '../api';
import { useAllEntries, usePreferDarkMode } from '../hooks';
+import { getBrowserLanguage, translations } from '../i18n';
import { EntryType, SavedEntry } from '../types';
import { Content } from './Content';
@@ -32,6 +34,7 @@ export const App: FunctionComponent = () => {
const theme = createTheme({
palette: { mode: preferDarkMode ? 'dark' : 'light' },
});
+ const language = getBrowserLanguage();
const handleTabChange = (selectedTab: EntryType) => {
setState((oldState) => ({
@@ -127,35 +130,37 @@ export const App: FunctionComponent = () => {
return (
-
-
-
-
-
-
+
+
+
+
+
+
+
+
);
};
diff --git a/src/frontend/components/DeleteAllEntriesListItem.tsx b/src/frontend/components/DeleteAllEntriesListItem.tsx
index aa09e0c..986ea30 100644
--- a/src/frontend/components/DeleteAllEntriesListItem.tsx
+++ b/src/frontend/components/DeleteAllEntriesListItem.tsx
@@ -1,9 +1,10 @@
import IconButton from '@mui/material/IconButton';
-import ListItem from '@mui/material/ListItem';
+import ListItemButton from '@mui/material/ListItemButton';
import ListItemIcon from '@mui/material/ListItemIcon';
import ListItemText from '@mui/material/ListItemText';
import DeleteIcon from '@mui/icons-material/Delete';
import React, { FunctionComponent, useState } from 'react';
+import { FormattedMessage } from 'react-intl';
import { DeleteAllConfirmationDialog } from './dialog';
@@ -32,14 +33,18 @@ export const DeleteAllEntriesListItem: FunctionComponent
-
+
-
-
+
+ }
+ />
+
= ({
};
return (
-
+
= ({
-
+
);
};
diff --git a/src/frontend/components/Toolbar.tsx b/src/frontend/components/Toolbar.tsx
index fc2d575..6b1849f 100644
--- a/src/frontend/components/Toolbar.tsx
+++ b/src/frontend/components/Toolbar.tsx
@@ -7,7 +7,7 @@ import Typography from '@mui/material/Typography';
import AddIcon from '@mui/icons-material/Add';
import CheckBoxOutlineBlankOutlinedIcon from '@mui/icons-material/CheckBoxOutlineBlankOutlined';
import CheckBoxOutlinedIcon from '@mui/icons-material/CheckBoxOutlined';
-import React, { ChangeEvent, FunctionComponent } from 'react';
+import React, { FunctionComponent, SyntheticEvent } from 'react';
import { EntryType } from '../types';
@@ -24,7 +24,7 @@ export const Toolbar: FunctionComponent = ({
onTabChange,
selectedTab,
}) => {
- const handleTabChange = (ev: ChangeEvent, selectedTab: EntryType) =>
+ const handleTabChange = (ev: SyntheticEvent, selectedTab: EntryType) =>
onTabChange(selectedTab);
return (
diff --git a/src/frontend/components/dialog/AddEntryDialog.tsx b/src/frontend/components/dialog/AddEntryDialog.tsx
index ce21023..a274601 100644
--- a/src/frontend/components/dialog/AddEntryDialog.tsx
+++ b/src/frontend/components/dialog/AddEntryDialog.tsx
@@ -1,4 +1,5 @@
import React, { FunctionComponent } from 'react';
+import { FormattedMessage } from 'react-intl';
import { createEntry } from '../../api';
@@ -21,7 +22,9 @@ export const AddEntryDialog: FunctionComponent = ({
onClose={onClose}
onSubmit={handleSubmit}
open={open}
- title="Add new entry"
+ title={
+
+ }
/>
);
};
diff --git a/src/frontend/components/dialog/DeleteAllConfirmationDialog.tsx b/src/frontend/components/dialog/DeleteAllConfirmationDialog.tsx
index 608f86b..b84b0ff 100644
--- a/src/frontend/components/dialog/DeleteAllConfirmationDialog.tsx
+++ b/src/frontend/components/dialog/DeleteAllConfirmationDialog.tsx
@@ -3,6 +3,7 @@ import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import React, { FunctionComponent } from 'react';
+import { FormattedMessage } from 'react-intl';
export type DeleteAllConfirmationDialogProps = {
onAnswer: (answer: boolean) => void;
@@ -18,14 +19,17 @@ export const DeleteAllConfirmationDialog: FunctionComponent
- Do you really want to delete all entries marked as done?
+
diff --git a/src/frontend/components/dialog/EditEntryDialog.tsx b/src/frontend/components/dialog/EditEntryDialog.tsx
index b0a411b..87f495c 100644
--- a/src/frontend/components/dialog/EditEntryDialog.tsx
+++ b/src/frontend/components/dialog/EditEntryDialog.tsx
@@ -4,6 +4,7 @@ import { patchEntry } from '../../api';
import { SavedEntry } from '../../types';
import { EntryDialogBase, EntryDialogValues } from './EntryDialogBase';
+import { FormattedMessage } from 'react-intl';
export type EditEntryDialogProps = {
entry?: SavedEntry;
@@ -31,7 +32,7 @@ export const EditEntryDialog: FunctionComponent = ({
onClose={onClose}
onSubmit={handleSubmit}
open={open}
- title="Edit entry"
+ title={}
/>
);
};
diff --git a/src/frontend/components/dialog/EntryDialogBase.tsx b/src/frontend/components/dialog/EntryDialogBase.tsx
index 2042b55..1c762f8 100644
--- a/src/frontend/components/dialog/EntryDialogBase.tsx
+++ b/src/frontend/components/dialog/EntryDialogBase.tsx
@@ -9,9 +9,11 @@ import React, {
ChangeEvent,
FormEvent,
FunctionComponent,
+ ReactNode,
useEffect,
useState,
} from 'react';
+import { FormattedMessage } from 'react-intl';
import { mutate } from 'swr';
export type EntryDialogValues = {
@@ -24,7 +26,7 @@ export type EntryDialogBaseProps = {
onClose: () => void;
onSubmit: (values: EntryDialogValues) => Promise;
open: boolean;
- title: string;
+ title: ReactNode;
};
export const EntryDialogBase: FunctionComponent = ({
@@ -77,12 +79,15 @@ export const EntryDialogBase: FunctionComponent = ({
{error && (
- Unable to save changes.
+
)}
}
fullWidth
required
value={text}
@@ -92,7 +97,7 @@ export const EntryDialogBase: FunctionComponent = ({
/>
}
fullWidth
value={url}
onChange={handleURLChange}
@@ -101,10 +106,10 @@ export const EntryDialogBase: FunctionComponent = ({
diff --git a/src/frontend/components/snackbar/ErrorSnackbar.tsx b/src/frontend/components/snackbar/ErrorSnackbar.tsx
index edcc2b6..4921509 100644
--- a/src/frontend/components/snackbar/ErrorSnackbar.tsx
+++ b/src/frontend/components/snackbar/ErrorSnackbar.tsx
@@ -3,6 +3,7 @@ import IconButton from '@mui/material/IconButton';
import Snackbar from '@mui/material/Snackbar';
import CloseIcon from '@mui/icons-material/Close';
import React, { FunctionComponent, SyntheticEvent } from 'react';
+import { FormattedMessage } from 'react-intl';
export type ErrorSnackbarProps = {
onClose: () => void;
@@ -36,7 +37,12 @@ export const ErrorSnackbar: FunctionComponent = ({
autoHideDuration={6000}
onClose={handleClose}
>
- API returned erroneous response.
+
+
+
);
};
diff --git a/src/frontend/i18n/en.json b/src/frontend/i18n/en.json
new file mode 100644
index 0000000..bb8893c
--- /dev/null
+++ b/src/frontend/i18n/en.json
@@ -0,0 +1,14 @@
+{
+ "add": "Add",
+ "addNewEntry": "Add new entry",
+ "apiError": "API returned erroneous response.",
+ "cancel": "Cancel",
+ "deleteAll": "Delete all",
+ "deleteAllConfirmation": "Do you really want to delete all entries marked as done?",
+ "editEntry": "Edit entry",
+ "no": "No",
+ "text": "Text",
+ "url": "URL",
+ "unableToSaveChanges": "Unable to save changes.",
+ "yes": "Yes"
+}
diff --git a/src/frontend/i18n/fi.json b/src/frontend/i18n/fi.json
new file mode 100644
index 0000000..0584986
--- /dev/null
+++ b/src/frontend/i18n/fi.json
@@ -0,0 +1,14 @@
+{
+ "add": "Lisää",
+ "addNewEntry": "Lisää uusi kohta",
+ "apiError": "Palvelin palautti virheen.",
+ "cancel": "Peruuta",
+ "deleteAll": "Poista kaikki",
+ "deleteAllConfirmation": "Haluatko varmasti poistaa kaikki valmiiksi merkityt kohteet?",
+ "editEntry": "Muokkaa",
+ "no": "Ei",
+ "text": "Teksti",
+ "url": "Verkko-osoite",
+ "unableToSaveChanges": "Tallentaminen epäonnistui.",
+ "yes": "Kyllä"
+}
diff --git a/src/frontend/i18n/index.ts b/src/frontend/i18n/index.ts
new file mode 100644
index 0000000..ff19d1c
--- /dev/null
+++ b/src/frontend/i18n/index.ts
@@ -0,0 +1,18 @@
+import enTranslations from './en.json';
+import fiTranslations from './fi.json';
+
+const SUPPORTED_LANGUAGES = new Set(['en', 'fi']);
+const DEFAULT_LANGUAGE = 'en';
+
+export const translations: Record> = {
+ en: enTranslations,
+ fi: fiTranslations,
+};
+
+export const getBrowserLanguage = (): string => {
+ const browserLanguageCode = navigator.language.split(/[-_]/)[0];
+
+ return SUPPORTED_LANGUAGES.has(browserLanguageCode)
+ ? browserLanguageCode
+ : DEFAULT_LANGUAGE;
+};
diff --git a/src/frontend/index.tsx b/src/frontend/index.tsx
index 776e97a..5bd8918 100644
--- a/src/frontend/index.tsx
+++ b/src/frontend/index.tsx
@@ -1,6 +1,9 @@
import React from 'react';
-import ReactDOM from 'react-dom';
+import { createRoot } from 'react-dom/client';
import { App } from './components';
-ReactDOM.render(, document.getElementById('root'));
+const container = document.getElementById('root');
+const root = createRoot(container!);
+
+root.render();
diff --git a/tsconfig.frontend.json b/tsconfig.frontend.json
index c491452..dbf2f46 100644
--- a/tsconfig.frontend.json
+++ b/tsconfig.frontend.json
@@ -5,11 +5,18 @@
"esModuleInterop": true,
"lib": ["DOM", "ESNext"],
"jsx": "react",
+ "plugins": [
+ {
+ "ast": true,
+ "import": "transform",
+ "overrideIdFn": "[sha512:contenthash:base64:6]",
+ "transform": "@formatjs/ts-transformer",
+ "type": "config"
+ }
+ ],
+ "resolveJsonModule": true,
"strict": true,
"target": "ES5"
},
- "include": [
- "./src/common/**/*.ts",
- "./src/frontend/**/*.ts",
- ]
+ "include": ["./src/common/**/*.ts", "./src/frontend/**/*.ts"]
}
diff --git a/webpack.config.js b/webpack.config.js
index aaab617..e15e407 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -1,6 +1,7 @@
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const nodeExternals = require('webpack-node-externals');
+const { transform } = require('@formatjs/ts-transformer');
const isProduction = /^prod/.test(process.env.NODE_ENV);
const mode = isProduction ? 'production' : 'development';
@@ -27,7 +28,9 @@ module.exports = [
test: /\.ts$/,
exclude: /node_modules/,
loader: 'ts-loader',
- options: { configFile: path.resolve(__dirname, 'tsconfig.backend.json') },
+ options: {
+ configFile: path.resolve(__dirname, 'tsconfig.backend.json'),
+ },
},
],
},
@@ -75,7 +78,18 @@ module.exports = [
test: /\.tsx?$/,
exclude: /node_modules/,
loader: 'ts-loader',
- options: { configFile: path.resolve(__dirname, 'tsconfig.frontend.json') },
+ options: {
+ configFile: path.resolve(__dirname, 'tsconfig.frontend.json'),
+ getCustomTransformers() {
+ return {
+ before: [
+ transform({
+ overrideIdFn: '[sha512:contenthash:base64:6]',
+ }),
+ ],
+ };
+ },
+ },
},
],
},
diff --git a/yarn.lock b/yarn.lock
index c78bbd5..439e2de 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -240,6 +240,90 @@
minimatch "^3.0.4"
strip-json-comments "^3.1.1"
+"@formatjs/ecma402-abstract@2.2.1":
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.2.1.tgz#2e62bc5c22b0e6a5e13bfec6aac15d3d403e1065"
+ integrity sha512-O4ywpkdJybrjFc9zyL8qK5aklleIAi5O4nYhBVJaOFtCkNrnU+lKFeJOFC48zpsZQmR8Aok2V79hGpHnzbmFpg==
+ dependencies:
+ "@formatjs/fast-memoize" "2.2.2"
+ "@formatjs/intl-localematcher" "0.5.6"
+ tslib "2"
+
+"@formatjs/fast-memoize@2.2.2":
+ version "2.2.2"
+ resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.2.tgz#2409ec10f5f7d6c65f4c04e6c2d6cc56fa1e4cef"
+ integrity sha512-mzxZcS0g1pOzwZTslJOBTmLzDXseMLLvnh25ymRilCm8QLMObsQ7x/rj9GNrH0iUhZMlFisVOD6J1n6WQqpKPQ==
+ dependencies:
+ tslib "2"
+
+"@formatjs/icu-messageformat-parser@2.9.1":
+ version "2.9.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.9.1.tgz#f127c6a8196446c7d842c08b1230f10cf27a3dc3"
+ integrity sha512-7AYk4tjnLi5wBkxst2w7qFj38JLMJoqzj7BhdEl7oTlsWMlqwgx4p9oMmmvpXWTSDGNwOKBRc1SfwMh5MOHeNg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.2.1"
+ "@formatjs/icu-skeleton-parser" "1.8.5"
+ tslib "2"
+
+"@formatjs/icu-skeleton-parser@1.8.5":
+ version "1.8.5"
+ resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.5.tgz#c25355778b9ea49bb0dcd85af727a375b9fcea62"
+ integrity sha512-zRZ/e3B5qY2+JCLs7puTzWS1Jb+t/K+8Jur/gEZpA2EjWeLDE17nsx8thyo9P48Mno7UmafnPupV2NCJXX17Dg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.2.1"
+ tslib "2"
+
+"@formatjs/intl-displaynames@6.8.1":
+ version "6.8.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-6.8.1.tgz#9cb16ecdd08410c884f0edf9057abb23ef842a86"
+ integrity sha512-nyWfJk4BZ1+GzLq9a40BgVPSRpBkRAVzrSpql+92i0i+lX11m9eS1trSRf/h3j/XcQ+h1h+ntA4Ra4jETK7nNg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.2.1"
+ "@formatjs/intl-localematcher" "0.5.6"
+ tslib "2"
+
+"@formatjs/intl-listformat@7.7.1":
+ version "7.7.1"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-7.7.1.tgz#267b7aff8ad3bf28d6608caab5dad26346a7b07c"
+ integrity sha512-bjBxWaUhYAbJFUlFSMWZGn3r2mglXwk+BLyGRu8dY8Q83ZPsqmmVQzjQKENHE3lV6eoQGHT2oZHxUaVndJlk6Q==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.2.1"
+ "@formatjs/intl-localematcher" "0.5.6"
+ tslib "2"
+
+"@formatjs/intl-localematcher@0.5.6":
+ version "0.5.6"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.5.6.tgz#cd0cd99483673d3196a15b4e2c924cfda7f002f8"
+ integrity sha512-roz1+Ba5e23AHX6KUAWmLEyTRZegM5YDuxuvkHCyK3RJddf/UXB2f+s7pOMm9ktfPGla0g+mQXOn5vsuYirnaA==
+ dependencies:
+ tslib "2"
+
+"@formatjs/intl@2.10.11":
+ version "2.10.11"
+ resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.10.11.tgz#f63c62cc540709b35d080188838b3dbb262f47ca"
+ integrity sha512-FNLZjzE1QRlv1Wf0oinnM97AbvZU1zQnQMHI0Oza2F7PxzrPf6bYFRs0ugapq/O4FrvNwDt9F9nyRNwsMM118g==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.2.1"
+ "@formatjs/fast-memoize" "2.2.2"
+ "@formatjs/icu-messageformat-parser" "2.9.1"
+ "@formatjs/intl-displaynames" "6.8.1"
+ "@formatjs/intl-listformat" "7.7.1"
+ intl-messageformat "10.7.3"
+ tslib "2"
+
+"@formatjs/ts-transformer@^3.13.20":
+ version "3.13.20"
+ resolved "https://registry.yarnpkg.com/@formatjs/ts-transformer/-/ts-transformer-3.13.20.tgz#f682e0649f2ec4fac7bf2db0c06f65f2891bde0b"
+ integrity sha512-63zGIsaLpxfu0w3jclfrgh8EBxbwO43IbCNIAWj31ZowFtgqIOBo7j/DspQCEhvpwDM2ErYfZv8DjV3cabphVQ==
+ dependencies:
+ "@formatjs/icu-messageformat-parser" "2.9.1"
+ "@types/json-stable-stringify" "1"
+ "@types/node" "14 || 16 || 17 || 18 || 20"
+ chalk "4"
+ json-stable-stringify "1"
+ tslib "2"
+ typescript "5"
+
"@fvilers/normalize-port@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@fvilers/normalize-port/-/normalize-port-1.0.0.tgz#411ab781f8beb5659172ff0a80d45ce860df8563"
@@ -478,6 +562,14 @@
"@types/qs" "*"
"@types/serve-static" "*"
+"@types/hoist-non-react-statics@3":
+ version "3.3.5"
+ resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz#dab7867ef789d87e2b4b0003c9d65c49cc44a494"
+ integrity sha512-SbcrWzkKBw2cdwRTwQAswfpB9g9LJWfjtUeW/jvNwbhC8cpmmNYVePa+ncbUe0rGTQ7G3Ff6mYUN2VMfLVr+Sg==
+ dependencies:
+ "@types/react" "*"
+ hoist-non-react-statics "^3.3.0"
+
"@types/http-errors@*":
version "2.0.4"
resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f"
@@ -488,6 +580,11 @@
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841"
integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==
+"@types/json-stable-stringify@1":
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/@types/json-stable-stringify/-/json-stable-stringify-1.1.0.tgz#41393e6b7a9a67221607346af4a79783aeb28aea"
+ integrity sha512-ESTsHWB72QQq+pjUFIbEz9uSCZppD31YrVkbt2rnUciTYEvcwN6uZIhX5JZeBHqRlFJ41x/7MewCs7E2Qux6Cg==
+
"@types/lodash@^4.14.168":
version "4.17.13"
resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.17.13.tgz#786e2d67cfd95e32862143abe7463a7f90c300eb"
@@ -512,6 +609,13 @@
dependencies:
undici-types "~6.19.8"
+"@types/node@14 || 16 || 17 || 18 || 20":
+ version "20.17.5"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.5.tgz#b7a1d8619ced7ce1da901b07a47c61107272449a"
+ integrity sha512-n8FYY/pRxu496441gIcAQFZPKXbhsd6VZygcq+PTSZ75eMh/Ke0hCAROdUa21qiFqKNsPPYic46yXDO1JGiPBQ==
+ dependencies:
+ undici-types "~6.19.2"
+
"@types/node@^14.14.41":
version "14.18.63"
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b"
@@ -537,12 +641,12 @@
resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
-"@types/react-dom@^17.0.3":
- version "17.0.25"
- resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.25.tgz#e0e5b3571e1069625b3a3da2b279379aa33a0cb5"
- integrity sha512-urx7A7UxkZQmThYA4So0NelOVjx3V4rNFVJwp0WZlbIK5eM4rNJDiN3R/E9ix0MBh6kAEojk/9YL+Te6D9zHNA==
+"@types/react-dom@^18.3.1":
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.3.1.tgz#1e4654c08a9cdcfb6594c780ac59b55aad42fe07"
+ integrity sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==
dependencies:
- "@types/react" "^17"
+ "@types/react" "*"
"@types/react-transition-group@^4.4.10":
version "4.4.11"
@@ -551,7 +655,7 @@
dependencies:
"@types/react" "*"
-"@types/react@*":
+"@types/react@*", "@types/react@^18.3.11", "@types/react@^18.3.12":
version "18.3.12"
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.3.12.tgz#99419f182ccd69151813b7ee24b792fe08774f60"
integrity sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==
@@ -559,20 +663,6 @@
"@types/prop-types" "*"
csstype "^3.0.2"
-"@types/react@^17", "@types/react@^17.0.3":
- version "17.0.83"
- resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.83.tgz#b477c56387b74279281149dcf5ba2a1e2216d131"
- integrity sha512-l0m4ArKJvmFtR4e8UmKrj1pB4tUgOhJITf+mADyF/p69Ts1YAR/E+G9XEM0mHXKVRa1dQNHseyyDNzeuAXfXQw==
- dependencies:
- "@types/prop-types" "*"
- "@types/scheduler" "^0.16"
- csstype "^3.0.2"
-
-"@types/scheduler@^0.16":
- version "0.16.8"
- resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.8.tgz#ce5ace04cfeabe7ef87c0091e50752e36707deff"
- integrity sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==
-
"@types/semver@^7.5.0":
version "7.5.8"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
@@ -1183,6 +1273,14 @@ caniuse-lite@^1.0.30001669:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001676.tgz#fe133d41fe74af8f7cc93b8a714c3e86a86e6f04"
integrity sha512-Qz6zwGCiPghQXGJvgQAem79esjitvJ+CxSbSQkW9H/UX5hg8XM88d4lp2W+MEQ81j+Hip58Il+jGVdazk1z9cw==
+chalk@4, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
+ integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
+ dependencies:
+ ansi-styles "^4.1.0"
+ supports-color "^7.1.0"
+
chalk@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
@@ -1192,14 +1290,6 @@ chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
-chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
- version "4.1.2"
- resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
- integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
- dependencies:
- ansi-styles "^4.1.0"
- supports-color "^7.1.0"
-
chokidar@^3.5.2:
version "3.6.0"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b"
@@ -2219,7 +2309,7 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2:
dependencies:
function-bind "^1.1.2"
-hoist-non-react-statics@^3.3.1:
+hoist-non-react-statics@3, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1:
version "3.3.2"
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -2307,6 +2397,16 @@ interpret@^3.1.1:
resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4"
integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==
+intl-messageformat@10.7.3:
+ version "10.7.3"
+ resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.3.tgz#a5cbc886f1db4b6324e6bfc4fd8f91a3e3e37c31"
+ integrity sha512-AAo/3oyh7ROfPhDuh7DxTTydh97OC+lv7h1Eq5LuHWuLsUMKOhtzTYuyXlUReuwZ9vANDHo4CS1bGRrn7TZRtg==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.2.1"
+ "@formatjs/fast-memoize" "2.2.2"
+ "@formatjs/icu-messageformat-parser" "2.9.1"
+ tslib "2"
+
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
@@ -2600,6 +2700,21 @@ json-stable-stringify-without-jsonify@^1.0.1:
resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==
+json-stable-stringify@1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz#52d4361b47d49168bcc4e564189a42e5a7439454"
+ integrity sha512-SU/971Kt5qVQfJpyDveVhQ/vya+5hvrjClFOcr8c0Fq5aODJjMwutrOfCU+eCnVD5gpx1Q3fEqkyom77zH1iIg==
+ dependencies:
+ call-bind "^1.0.5"
+ isarray "^2.0.5"
+ jsonify "^0.0.1"
+ object-keys "^1.1.1"
+
+jsonify@^0.0.1:
+ version "0.0.1"
+ resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.1.tgz#2aa3111dae3d34a0f151c63f3a45d995d9420978"
+ integrity sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==
+
"jsx-ast-utils@^2.4.1 || ^3.0.0":
version "3.3.5"
resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a"
@@ -3134,14 +3249,29 @@ raw-body@2.5.2:
iconv-lite "0.4.24"
unpipe "1.0.0"
-react-dom@^17.0.2:
- version "17.0.2"
- resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
- integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
+react-dom@^18.3.1:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.3.1.tgz#c2265d79511b57d479b3dd3fdfa51536494c5cb4"
+ integrity sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==
dependencies:
loose-envify "^1.1.0"
- object-assign "^4.1.1"
- scheduler "^0.20.2"
+ scheduler "^0.23.2"
+
+react-intl@^6.8.4:
+ version "6.8.4"
+ resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-6.8.4.tgz#e39b6a71bbce5db90460abba4869c9f58b38fc1e"
+ integrity sha512-UKYrCIztyvSiZCpvHjDwAHlXT735fDioABVP+uhRAOhDSBS9NQ2vVbxiUikvVEBdr2b0cTe1tUfOfvhbmSPi/A==
+ dependencies:
+ "@formatjs/ecma402-abstract" "2.2.1"
+ "@formatjs/icu-messageformat-parser" "2.9.1"
+ "@formatjs/intl" "2.10.11"
+ "@formatjs/intl-displaynames" "6.8.1"
+ "@formatjs/intl-listformat" "7.7.1"
+ "@types/hoist-non-react-statics" "3"
+ "@types/react" "^18.3.11"
+ hoist-non-react-statics "3"
+ intl-messageformat "10.7.3"
+ tslib "2"
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
@@ -3163,13 +3293,12 @@ react-transition-group@^4.4.5:
loose-envify "^1.4.0"
prop-types "^15.6.2"
-react@^17.0.2:
- version "17.0.2"
- resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
- integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
+react@^18.3.1:
+ version "18.3.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-18.3.1.tgz#49ab892009c53933625bd16b2533fc754cab2891"
+ integrity sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==
dependencies:
loose-envify "^1.1.0"
- object-assign "^4.1.1"
readdirp@~3.6.0:
version "3.6.0"
@@ -3331,13 +3460,12 @@ safe-regex-test@^1.0.3:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-scheduler@^0.20.2:
- version "0.20.2"
- resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
- integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
+scheduler@^0.23.2:
+ version "0.23.2"
+ resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3"
+ integrity sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==
dependencies:
loose-envify "^1.1.0"
- object-assign "^4.1.1"
schema-utils@^3.1.1, schema-utils@^3.2.0:
version "3.3.0"
@@ -3760,7 +3888,7 @@ ts-loader@^9.4.4:
semver "^7.3.4"
source-map "^0.7.4"
-tslib@^2.1.0:
+tslib@2, tslib@^2.1.0:
version "2.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
@@ -3839,7 +3967,7 @@ typed-array-length@^1.0.6:
is-typed-array "^1.1.13"
possible-typed-array-names "^1.0.0"
-typescript@^5.2.2:
+typescript@5, typescript@^5.2.2:
version "5.6.3"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b"
integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==
@@ -3859,7 +3987,7 @@ undefsafe@^2.0.5:
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
-undici-types@~6.19.8:
+undici-types@~6.19.2, undici-types@~6.19.8:
version "6.19.8"
resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02"
integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==