Fix JSON parsing error in i18n configuration and API error handling
Co-authored-by: lora322 <39804183+lora322@users.noreply.github.com>
This commit is contained in:
parent
ae996888b0
commit
4ad8da4083
52
frontend/public/locales/en-US/common.json
Normal file
52
frontend/public/locales/en-US/common.json
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"pages": {
|
||||||
|
"dashboard": {
|
||||||
|
"pageTitle": "Dashboard",
|
||||||
|
"overview": "Overview",
|
||||||
|
"loadingWidgets": "Loading widgets...",
|
||||||
|
"loading": "Loading..."
|
||||||
|
},
|
||||||
|
"login": {
|
||||||
|
"pageTitle": "Login",
|
||||||
|
|
||||||
|
"form": {
|
||||||
|
"loginLabel": "Login",
|
||||||
|
"loginHelp": "Please enter your login",
|
||||||
|
"passwordLabel": "Password",
|
||||||
|
"passwordHelp": "Please enter your password",
|
||||||
|
"remember": "Remember",
|
||||||
|
"forgotPassword": "Forgot password?",
|
||||||
|
"loginButton": "Login",
|
||||||
|
"loading": "Loading...",
|
||||||
|
"noAccountYet": "Don’t have an account yet?",
|
||||||
|
"newAccount": "New Account"
|
||||||
|
},
|
||||||
|
|
||||||
|
"pexels": {
|
||||||
|
"photoCredit": "Photo by {{photographer}} on Pexels",
|
||||||
|
"videoCredit": "Video by {{name}} on Pexels",
|
||||||
|
"videoUnsupported": "Your browser does not support the video tag."
|
||||||
|
},
|
||||||
|
|
||||||
|
"footer": {
|
||||||
|
"copyright": "© {{year}} {{title}}. All rights reserved",
|
||||||
|
"privacy": "Privacy Policy"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"widgetCreator": {
|
||||||
|
"title": "Create Chart or Widget",
|
||||||
|
"helpText": "Describe your new widget or chart in natural language. For example: \"Number of admin users\" OR \"red chart with number of closed contracts grouped by month\"",
|
||||||
|
"settingsTitle": "Widget Creator Settings",
|
||||||
|
"settingsDescription": "What role are we showing and creating widgets for?",
|
||||||
|
"doneButton": "Done",
|
||||||
|
"loading": "Loading..."
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"placeholder": "Search",
|
||||||
|
"required": "Required",
|
||||||
|
"minLength": "Minimum length: {{count}} characters"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,12 @@ export async function getPexelsImage() {
|
|||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching image:', error);
|
console.error('Error fetching image:', error);
|
||||||
return null;
|
// Return fallback data when backend is not available
|
||||||
|
return {
|
||||||
|
src: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZGRkIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxOCIgZmlsbD0iIzk5OSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPkltYWdlIE5vdCBBdmFpbGFibGU8L3RleHQ+PC9zdmc+',
|
||||||
|
photographer: 'Placeholder',
|
||||||
|
photographer_url: '#'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -16,7 +21,11 @@ export async function getPexelsVideo() {
|
|||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching video:', error);
|
console.error('Error fetching video:', error);
|
||||||
return null;
|
// Return fallback data when backend is not available
|
||||||
|
return {
|
||||||
|
src: '',
|
||||||
|
name: 'Video Not Available'
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +72,19 @@ export async function getMultiplePexelsImages(
|
|||||||
|
|
||||||
localStorage.setItem('pexelsImagesCache', JSON.stringify(cachedImages));
|
localStorage.setItem('pexelsImagesCache', JSON.stringify(cachedImages));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error('Error fetching multiple images:', error);
|
||||||
|
// Provide fallback images when backend is not available
|
||||||
|
missingQueries.forEach((query) => {
|
||||||
|
const normalizedQuery = normalizeQuery(query);
|
||||||
|
if (!cachedImages[normalizedQuery]) {
|
||||||
|
cachedImages[normalizedQuery] = {
|
||||||
|
src: 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDAwIiBoZWlnaHQ9IjMwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cmVjdCB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiBmaWxsPSIjZGRkIi8+PHRleHQgeD0iNTAlIiB5PSI1MCUiIGZvbnQtZmFtaWx5PSJBcmlhbCwgc2Fucy1zZXJpZiIgZm9udC1zaXplPSIxOCIgZmlsbD0iIzk5OSIgdGV4dC1hbmNob3I9Im1pZGRsZSIgZHk9Ii4zZW0iPkltYWdlIE5vdCBBdmFpbGFibGU8L3RleHQ+PC9zdmc+',
|
||||||
|
photographer: 'Placeholder',
|
||||||
|
photographer_url: '#'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
localStorage.setItem('pexelsImagesCache', JSON.stringify(cachedImages));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,8 @@ i18n
|
|||||||
.use(initReactI18next)
|
.use(initReactI18next)
|
||||||
.init({
|
.init({
|
||||||
fallbackLng: 'en',
|
fallbackLng: 'en',
|
||||||
|
defaultNS: 'common',
|
||||||
|
ns: ['common'],
|
||||||
detection: {
|
detection: {
|
||||||
order: ['localStorage', 'navigator'],
|
order: ['localStorage', 'navigator'],
|
||||||
lookupLocalStorage: 'app_lang_33651',
|
lookupLocalStorage: 'app_lang_33651',
|
||||||
|
|||||||
@ -12,8 +12,10 @@ import { getPageTitle } from '../config';
|
|||||||
import { useAppSelector } from '../stores/hooks';
|
import { useAppSelector } from '../stores/hooks';
|
||||||
import CardBoxComponentTitle from '../components/CardBoxComponentTitle';
|
import CardBoxComponentTitle from '../components/CardBoxComponentTitle';
|
||||||
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
|
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
|
||||||
export default function Starter() {
|
export default function Starter() {
|
||||||
|
const { t } = useTranslation('common');
|
||||||
const [illustrationImage, setIllustrationImage] = useState({
|
const [illustrationImage, setIllustrationImage] = useState({
|
||||||
src: undefined,
|
src: undefined,
|
||||||
photographer: undefined,
|
photographer: undefined,
|
||||||
@ -145,10 +147,14 @@ export default function Starter() {
|
|||||||
</SectionFullScreen>
|
</SectionFullScreen>
|
||||||
<div className='bg-gray text-white flex flex-col text-center justify-center md:flex-row'>
|
<div className='bg-gray text-white flex flex-col text-center justify-center md:flex-row'>
|
||||||
<p className='py-6 text-sm'>
|
<p className='py-6 text-sm'>
|
||||||
© 2025 <span>{title}</span>. All rights reserved
|
{t('pages.login.footer.copyright', {
|
||||||
|
year: new Date().getFullYear(),
|
||||||
|
title: title,
|
||||||
|
defaultValue: '© {{year}} {{title}}. All rights reserved',
|
||||||
|
})}
|
||||||
</p>
|
</p>
|
||||||
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
|
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
|
||||||
Privacy Policy
|
{t('pages.login.footer.privacy', { defaultValue: 'Privacy Policy' })}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -361,9 +361,10 @@ export default function Login() {
|
|||||||
</SectionFullScreen>
|
</SectionFullScreen>
|
||||||
<div className='bg-black text-white flex flex-col text-center justify-center md:flex-row'>
|
<div className='bg-black text-white flex flex-col text-center justify-center md:flex-row'>
|
||||||
<p className='py-6 text-sm'>
|
<p className='py-6 text-sm'>
|
||||||
© 2025 <span>{title}</span>.{' '}
|
|
||||||
{t('pages.login.footer.copyright', {
|
{t('pages.login.footer.copyright', {
|
||||||
defaultValue: '© All rights reserved',
|
year: new Date().getFullYear(),
|
||||||
|
title: title,
|
||||||
|
defaultValue: '© {{year}} {{title}}. All rights reserved',
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
|
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user