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:
copilot-swe-agent[bot] 2025-09-24 02:49:40 +00:00
parent ae996888b0
commit 4ad8da4083
5 changed files with 89 additions and 7 deletions

View 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": "Dont 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"
}
}
}

View File

@ -6,7 +6,12 @@ export async function getPexelsImage() {
return response.data;
} catch (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;
} catch (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));
} 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));
}
}

View File

@ -9,6 +9,8 @@ i18n
.use(initReactI18next)
.init({
fallbackLng: 'en',
defaultNS: 'common',
ns: ['common'],
detection: {
order: ['localStorage', 'navigator'],
lookupLocalStorage: 'app_lang_33651',

View File

@ -12,8 +12,10 @@ import { getPageTitle } from '../config';
import { useAppSelector } from '../stores/hooks';
import CardBoxComponentTitle from '../components/CardBoxComponentTitle';
import { getPexelsImage, getPexelsVideo } from '../helpers/pexels';
import { useTranslation } from 'react-i18next';
export default function Starter() {
const { t } = useTranslation('common');
const [illustrationImage, setIllustrationImage] = useState({
src: undefined,
photographer: undefined,
@ -145,10 +147,14 @@ export default function Starter() {
</SectionFullScreen>
<div className='bg-gray text-white flex flex-col text-center justify-center md:flex-row'>
<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>
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>
Privacy Policy
{t('pages.login.footer.privacy', { defaultValue: 'Privacy Policy' })}
</Link>
</div>
</div>

View File

@ -361,9 +361,10 @@ export default function Login() {
</SectionFullScreen>
<div className='bg-black text-white flex flex-col text-center justify-center md:flex-row'>
<p className='py-6 text-sm'>
© 2025 <span>{title}</span>.{' '}
{t('pages.login.footer.copyright', {
defaultValue: '© All rights reserved',
year: new Date().getFullYear(),
title: title,
defaultValue: '© {{year}} {{title}}. All rights reserved',
})}
</p>
<Link className='py-6 ml-4 text-sm' href='/privacy-policy/'>