mirror of
https://github.com/mediacms-io/mediacms.git
synced 2024-11-22 00:03:28 +01:00
initial translations related commit
This commit is contained in:
parent
7237040777
commit
687a0016e9
71
frontend/package-lock.json
generated
71
frontend/package-lock.json
generated
@ -10,10 +10,12 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"flux": "^4.0.1",
|
||||
"i18next": "^20.3.3",
|
||||
"mediacms-player": "file:packages/player",
|
||||
"normalize.css": "^8.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-i18next": "^11.11.3",
|
||||
"sortablejs": "^1.13.0",
|
||||
"timeago.js": "^4.0.2",
|
||||
"url-parse": "^1.5.1"
|
||||
@ -8619,6 +8621,14 @@
|
||||
"tslib": "^2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"dependencies": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-prettify": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/html-prettify/-/html-prettify-1.0.3.tgz",
|
||||
@ -8752,6 +8762,14 @@
|
||||
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/i18next": {
|
||||
"version": "20.3.3",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-20.3.3.tgz",
|
||||
"integrity": "sha512-tx9EUhHeaipvZ5pFLTaN9Xdm5Ssal774MpujaTA1Wv/ST/1My5SnoBmliY1lOpyEP5Z51Dq1gXifk/y4Yt3agQ==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@ -13205,6 +13223,19 @@
|
||||
"react": "17.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/react-i18next": {
|
||||
"version": "11.11.3",
|
||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.11.3.tgz",
|
||||
"integrity": "sha512-upzG5/SpyOlYP5oSF4K8TZBvDWVhnCo38JNV+KnWjrg0+IaJCBltyh6lRGZDO5ovLyA4dU6Ip0bwbUCjb6Yyxw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.14.5",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"i18next": ">= 19.0.0",
|
||||
"react": ">= 16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@ -20404,6 +20435,14 @@
|
||||
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk=",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz",
|
||||
@ -21821,6 +21860,7 @@
|
||||
}
|
||||
},
|
||||
"packages/vjs-plugin": {
|
||||
"name": "mediacms-vjs-plugin",
|
||||
"version": "0.9.0",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
@ -21854,6 +21894,7 @@
|
||||
}
|
||||
},
|
||||
"packages/vjs-plugin-font-icons": {
|
||||
"name": "mediacms-vjs-plugin-font-icons",
|
||||
"version": "0.9.0",
|
||||
"license": "Apache-2.0",
|
||||
"devDependencies": {
|
||||
@ -28693,6 +28734,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"html-parse-stringify": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz",
|
||||
"integrity": "sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg==",
|
||||
"requires": {
|
||||
"void-elements": "3.1.0"
|
||||
}
|
||||
},
|
||||
"html-prettify": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/html-prettify/-/html-prettify-1.0.3.tgz",
|
||||
@ -28798,6 +28847,14 @@
|
||||
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
|
||||
"dev": true
|
||||
},
|
||||
"i18next": {
|
||||
"version": "20.3.3",
|
||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-20.3.3.tgz",
|
||||
"integrity": "sha512-tx9EUhHeaipvZ5pFLTaN9Xdm5Ssal774MpujaTA1Wv/ST/1My5SnoBmliY1lOpyEP5Z51Dq1gXifk/y4Yt3agQ==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.12.0"
|
||||
}
|
||||
},
|
||||
"iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
@ -32276,6 +32333,15 @@
|
||||
"scheduler": "^0.20.2"
|
||||
}
|
||||
},
|
||||
"react-i18next": {
|
||||
"version": "11.11.3",
|
||||
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-11.11.3.tgz",
|
||||
"integrity": "sha512-upzG5/SpyOlYP5oSF4K8TZBvDWVhnCo38JNV+KnWjrg0+IaJCBltyh6lRGZDO5ovLyA4dU6Ip0bwbUCjb6Yyxw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.14.5",
|
||||
"html-parse-stringify": "^3.0.1"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@ -38069,6 +38135,11 @@
|
||||
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
||||
"dev": true
|
||||
},
|
||||
"void-elements": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz",
|
||||
"integrity": "sha1-YU9/v42AHwu18GYfWy9XhXUOTwk="
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz",
|
||||
|
@ -42,10 +42,12 @@
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"flux": "^4.0.1",
|
||||
"i18next": "^20.3.3",
|
||||
"mediacms-player": "file:packages/player",
|
||||
"normalize.css": "^8.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-i18next": "^11.11.3",
|
||||
"sortablejs": "^1.13.0",
|
||||
"timeago.js": "^4.0.2",
|
||||
"url-parse": "^1.5.1"
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface MediaListHeaderProps {
|
||||
title?: string;
|
||||
@ -9,7 +10,8 @@ interface MediaListHeaderProps {
|
||||
}
|
||||
|
||||
export const MediaListHeader: React.FC<MediaListHeaderProps> = (props) => {
|
||||
const viewAllText = props.viewAllText || 'VIEW ALL';
|
||||
const { t } = useTranslation();
|
||||
const viewAllText = props.viewAllText || t('VIEW ALL');
|
||||
return (
|
||||
<div className={(props.className ? props.className + ' ' : '') + 'media-list-header'} style={props.style}>
|
||||
<h2>{props.title}</h2>
|
||||
|
@ -1,8 +1,17 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useLayout, usePopup } from '../../../utils/hooks/';
|
||||
import { PageStore } from '../../../utils/stores/';
|
||||
import { HeaderConsumer, MemberConsumer, LinksConsumer } from '../../../utils/contexts/';
|
||||
import { CircleIconButton, MaterialIcon, NavigationContentApp, NavigationMenuList, PopupTop, PopupMain, UserThumbnail } from '../../_shared';
|
||||
import {
|
||||
CircleIconButton,
|
||||
MaterialIcon,
|
||||
NavigationContentApp,
|
||||
NavigationMenuList,
|
||||
PopupTop,
|
||||
PopupMain,
|
||||
UserThumbnail,
|
||||
} from '../../_shared';
|
||||
import { HeaderThemeSwitcher } from './HeaderThemeSwitcher';
|
||||
|
||||
function headerPopupPages(user, popupNavItems, hasHeaderThemeSwitcher) {
|
||||
@ -87,6 +96,8 @@ function UploadMediaButton({ user, links }) {
|
||||
}
|
||||
|
||||
function LoginButton({ user, link, hasHeaderThemeSwitcher }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return user.is.anonymous && user.can.login ? (
|
||||
<div className="sign-in-wrap">
|
||||
<a
|
||||
@ -95,15 +106,17 @@ function LoginButton({ user, link, hasHeaderThemeSwitcher }) {
|
||||
className={
|
||||
'button-link sign-in' + (hasHeaderThemeSwitcher ? ' hidden-only-in-small' : ' hidden-only-in-extra-small')
|
||||
}
|
||||
title="Sign in"
|
||||
title="{t('Sign in')}"
|
||||
>
|
||||
Sign in
|
||||
{t('Sign in')}
|
||||
</a>
|
||||
</div>
|
||||
) : null;
|
||||
}
|
||||
|
||||
function RegisterButton({ user, link, hasHeaderThemeSwitcher }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return user.is.anonymous && user.can.register ? (
|
||||
<div className="register-wrap">
|
||||
<a
|
||||
@ -112,9 +125,9 @@ function RegisterButton({ user, link, hasHeaderThemeSwitcher }) {
|
||||
'button-link register-link' +
|
||||
(hasHeaderThemeSwitcher ? ' hidden-only-in-small' : ' hidden-only-in-extra-small')
|
||||
}
|
||||
title="Register"
|
||||
title="{t('Register')}"
|
||||
>
|
||||
Register
|
||||
{t('Register')}
|
||||
</a>
|
||||
</div>
|
||||
) : null;
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ApiUrlConsumer } from '../utils/contexts/';
|
||||
import { MediaListWrapper } from '../components/MediaListWrapper';
|
||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
|
||||
@ -9,18 +10,21 @@ interface CategoriesPageProps {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const CategoriesPage: React.FC<CategoriesPageProps> = ({ id = 'categories', title = 'Categories' }) => (
|
||||
<Page id={id}>
|
||||
<ApiUrlConsumer>
|
||||
{(apiUrl) => (
|
||||
<MediaListWrapper title={title} className="items-list-ver">
|
||||
<LazyLoadItemListAsync
|
||||
singleLinkContent={true}
|
||||
inCategoriesList={true}
|
||||
requestUrl={apiUrl.archive.categories}
|
||||
/>
|
||||
</MediaListWrapper>
|
||||
)}
|
||||
</ApiUrlConsumer>
|
||||
</Page>
|
||||
);
|
||||
export const CategoriesPage: React.FC<CategoriesPageProps> = ({ id = 'categories', title }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Page id={id}>
|
||||
<ApiUrlConsumer>
|
||||
{(apiUrl) => (
|
||||
<MediaListWrapper title={title || t('Categories')} className="items-list-ver">
|
||||
<LazyLoadItemListAsync
|
||||
singleLinkContent={true}
|
||||
inCategoriesList={true}
|
||||
requestUrl={apiUrl.archive.categories}
|
||||
/>
|
||||
</MediaListWrapper>
|
||||
)}
|
||||
</ApiUrlConsumer>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ApiUrlConsumer } from '../utils/contexts/';
|
||||
import { MediaListWrapper } from '../components/MediaListWrapper';
|
||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
|
||||
@ -9,14 +10,17 @@ interface MembersPageProps {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const MembersPage: React.FC<MembersPageProps> = ({ id = 'members', title = 'Members' }) => (
|
||||
<Page id={id}>
|
||||
<ApiUrlConsumer>
|
||||
{(apiUrl) => (
|
||||
<MediaListWrapper title={title} className="items-list-ver">
|
||||
<LazyLoadItemListAsync requestUrl={apiUrl.users} />
|
||||
</MediaListWrapper>
|
||||
)}
|
||||
</ApiUrlConsumer>
|
||||
</Page>
|
||||
);
|
||||
export const MembersPage: React.FC<MembersPageProps> = ({ id = 'members', title }) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Page id={id}>
|
||||
<ApiUrlConsumer>
|
||||
{(apiUrl) => (
|
||||
<MediaListWrapper title={title || t('Members')} className="items-list-ver">
|
||||
<LazyLoadItemListAsync requestUrl={apiUrl.users} />
|
||||
</MediaListWrapper>
|
||||
)}
|
||||
</ApiUrlConsumer>
|
||||
</Page>
|
||||
);
|
||||
};
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import { withTranslation } from 'react-i18next';
|
||||
import { ApiUrlConsumer } from '../utils/contexts/';
|
||||
import { PageStore } from '../utils/stores/';
|
||||
import { MediaListWrapper } from '../components/MediaListWrapper';
|
||||
@ -7,7 +8,7 @@ import ProfilePagesContent from '../components/profile-page/ProfilePagesContent'
|
||||
import { LazyLoadItemListAsync } from '../components/item-list/LazyLoadItemListAsync.jsx';
|
||||
import { ProfileMediaPage } from './ProfileMediaPage';
|
||||
|
||||
export class ProfilePlaylistsPage extends ProfileMediaPage {
|
||||
class ProfilePlaylistsPageClass extends ProfileMediaPage {
|
||||
constructor(props) {
|
||||
super(props, 'author-playlists');
|
||||
|
||||
@ -37,7 +38,7 @@ export class ProfilePlaylistsPage extends ProfileMediaPage {
|
||||
<ApiUrlConsumer>
|
||||
{(apiUrl) => (
|
||||
<MediaListWrapper
|
||||
title={-1 < this.state.playlistsCount ? 'Created playlists' : void 0}
|
||||
title={-1 < this.state.playlistsCount ? this.props.t('Created playlists') : void 0}
|
||||
className="profile-playlists-content items-list-ver"
|
||||
>
|
||||
<LazyLoadItemListAsync
|
||||
@ -55,3 +56,7 @@ export class ProfilePlaylistsPage extends ProfileMediaPage {
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
const ProfilePlaylistsPage = withTranslation()(ProfilePlaylistsPageClass);
|
||||
|
||||
export { ProfilePlaylistsPage };
|
||||
|
37
frontend/src/static/js/utils/languages/i18n.ts
Normal file
37
frontend/src/static/js/utils/languages/i18n.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import { enabled as langEnabled, translations as langTranslations, selected as langSelected } from '.';
|
||||
|
||||
// the translations
|
||||
// (tip move them in a JSON file and import them,
|
||||
// or even better, manage them via a UI: https://react.i18next.com/guides/multiple-translation-files#manage-your-translations-with-a-management-gui)
|
||||
const resources: {
|
||||
[key: string]: {
|
||||
translation: { [key: string]: string };
|
||||
};
|
||||
} = {};
|
||||
|
||||
for (let k in langEnabled) {
|
||||
resources[langEnabled[k]] = { translation: langTranslations[langEnabled[k]] };
|
||||
}
|
||||
|
||||
i18n
|
||||
.use(initReactI18next) // passes i18n down to react-i18next
|
||||
.init({
|
||||
resources,
|
||||
lng: langSelected, // if you're using a language detector, do not define the lng option & // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
|
||||
fallbackLng: langSelected,
|
||||
// you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
|
||||
// if you're using a language detector, do not define the lng option
|
||||
|
||||
interpolation: {
|
||||
escapeValue: false, // react already safes from xss
|
||||
},
|
||||
|
||||
// react-i18next options
|
||||
react: {
|
||||
wait: true,
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
25
frontend/src/static/js/utils/languages/index.ts
Normal file
25
frontend/src/static/js/utils/languages/index.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { el, en, hi } from './translations/';
|
||||
import { BrowserCache } from '../classes/';
|
||||
import { config as mediacmsConfig } from '../settings/config.js';
|
||||
|
||||
const siteId = mediacmsConfig(window.MediaCMS).site.id;
|
||||
|
||||
// @ts-ignore
|
||||
const browserCache = new BrowserCache('MediaCMS[' + siteId + '][language]');
|
||||
|
||||
export const labels = {
|
||||
el: 'Greek',
|
||||
en: 'English',
|
||||
hi: 'Hindi',
|
||||
} as { [key: string]: string };
|
||||
|
||||
// In display order.
|
||||
export const translations: { [key: string]: { [key: string]: string } } = {
|
||||
en,
|
||||
hi,
|
||||
el,
|
||||
};
|
||||
|
||||
export const enabled: string[] = Object.keys(translations);
|
||||
|
||||
export const selected = browserCache.get('code') || 'en';
|
20
frontend/src/static/js/utils/languages/translations/el.ts
Normal file
20
frontend/src/static/js/utils/languages/translations/el.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
administration: 'διαχείριση',
|
||||
Categories: 'Κατηγορίες',
|
||||
'Change password': 'Αλλαγή κωδικού',
|
||||
'Created playlists': 'Λίστες αναπαραγωγής',
|
||||
'Edit profile': 'Επεξεργασία προφίλ',
|
||||
History: 'Ιστορικό',
|
||||
Language: 'Γλώσσα',
|
||||
Members: 'Μέλη',
|
||||
'My media': 'Oι μεταφορτώσεις μου',
|
||||
Register: 'Εγγραφή',
|
||||
REGISTER: 'ΕΓΓΡΑΦΗ',
|
||||
'Sign in': 'Σύνδεση',
|
||||
'SIGN IN': 'ΣΥΝΔΕΣΗ',
|
||||
'Sign out': 'Αποσύνδεση',
|
||||
'SIGN OUT': 'ΑΠΟΣΥΝΔΕΣΗ',
|
||||
'Switch theme': 'Επιλογή θέματος',
|
||||
'Upload media': 'Προσθήκη αρχείου',
|
||||
'VIEW ALL': 'ΠΡΟΒΟΛΗ ΟΛΩΝ',
|
||||
} as { [key: string]: string };
|
20
frontend/src/static/js/utils/languages/translations/en.ts
Normal file
20
frontend/src/static/js/utils/languages/translations/en.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
administration: 'administration',
|
||||
Categories: 'Categories',
|
||||
'Change password': 'Change password',
|
||||
'Created playlists': 'Created playlists',
|
||||
'Edit profile': 'Edit profile',
|
||||
History: 'History',
|
||||
Language: 'Language',
|
||||
Members: 'Members',
|
||||
'My media': 'My media',
|
||||
Register: 'Register',
|
||||
REGISTER: 'REGISTER',
|
||||
'Sign in': 'Sign in',
|
||||
'SIGN IN': 'SIGN IN',
|
||||
'Sign out': 'Sign out',
|
||||
'SIGN OUT': 'SIGN OUT',
|
||||
'Switch theme': 'Switch theme',
|
||||
'Upload media': 'Upload media',
|
||||
'VIEW ALL': 'VIEW ALL',
|
||||
} as { [key: string]: string };
|
20
frontend/src/static/js/utils/languages/translations/hi.ts
Normal file
20
frontend/src/static/js/utils/languages/translations/hi.ts
Normal file
@ -0,0 +1,20 @@
|
||||
export default {
|
||||
administration: 'administration',
|
||||
Categories: 'Categories',
|
||||
'Change password': 'Change password',
|
||||
'Created playlists': 'Created playlists',
|
||||
'Edit profile': 'Edit profile',
|
||||
History: 'History',
|
||||
Language: 'Language',
|
||||
Members: 'Members',
|
||||
'My media': 'My media',
|
||||
Register: 'Register',
|
||||
REGISTER: 'REGISTER',
|
||||
'Sign in': 'Sign in',
|
||||
'SIGN IN': 'SIGN IN',
|
||||
'Sign out': 'Sign out',
|
||||
'SIGN OUT': 'SIGN OUT',
|
||||
'Switch theme': 'Switch theme',
|
||||
'Upload media': 'Upload media',
|
||||
'VIEW ALL': 'VIEW ALL',
|
||||
} as { [key: string]: string };
|
@ -0,0 +1,3 @@
|
||||
export { default as el } from './el';
|
||||
export { default as en } from './en';
|
||||
export { default as hi } from './hi';
|
@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
|
||||
import { ThemeProvider } from './contexts/ThemeContext';
|
||||
import { LayoutProvider } from './contexts/LayoutContext';
|
||||
import { UserProvider } from './contexts/UserContext';
|
||||
import './languages/i18n';
|
||||
|
||||
const AppProviders = ({ children }) => (
|
||||
<LayoutProvider>
|
||||
|
Loading…
Reference in New Issue
Block a user