Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions api/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ app.get("/year-progress", (req, res) => {
const startDateParam = req.query.startDate;
const endDateParam = req.query.endDate;

const lang = req.query.lang || "en";

let start = startDateParam
? new Date(startDateParam)
: new Date(now.getFullYear(), 0, 1);
Expand All @@ -29,14 +31,24 @@ app.get("/year-progress", (req, res) => {

const progress = ((now - start) / (end - start)) * 100;
const progressFormatted = progress.toFixed(6);
const displayText = currentYear;


const translations = {
en: `Completed`,
es: `Completado`,
fr: `Terminé`,
de: `Abgeschlossen`,
hi: `पूरा हुआ`,
};

const localizedText = `${progressFormatted}% of ${currentYear} ${translations[lang] || translations["en"]}`;

Comment on lines +37 to 45
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word order assumption may not work for all languages. Consider using a more flexible template system like ${progressFormatted}% ${translations[lang]?.template || translations.en.template} where each language can define its own sentence structure.

Suggested change
en: `Completed`,
es: `Completado`,
fr: `Terminé`,
de: `Abgeschlossen`,
hi: `पूरा हुआ`,
};
const localizedText = `${progressFormatted}% of ${currentYear} ${translations[lang] || translations["en"]}`;
en: {
template: "{progress}% of {year} Completed"
},
es: {
template: "{progress}% del {year} Completado"
},
fr: {
template: "{progress}% de {year} Terminé"
},
de: {
template: "{progress}% von {year} Abgeschlossen"
},
hi: {
template: "{year} का {progress}% पूरा हुआ"
}
};
function formatTemplate(template, values) {
return template.replace(/{(\w+)}/g, (_, key) => values[key] ?? "");
}
const template = (translations[lang]?.template) || translations["en"].template;
const localizedText = formatTemplate(template, {
progress: progressFormatted,
year: currentYear
});

Copilot uses AI. Check for mistakes.
const svg = `
<svg width="300" height="50" xmlns="http://www.w3.org/2000/svg">
<rect width="100%" height="50" fill="#e0e0e0" />
<rect width="${progressFormatted}%" height="50" fill="#3b82f6" />
<text x="50%" y="30" alignment-baseline="middle" text-anchor="middle" fill="#000" font-size="12">
${progressFormatted}% of ${displayText} Completed
${localizedText}
</text>
</svg>
`;
Expand All @@ -50,4 +62,9 @@ app.get("/", (req, res) => {
res.sendFile(path.join(__dirname, "..", "public", "index.html"));
});

const PORT = 3000;
app.listen(PORT, () => {
console.log(`Server running at http://localhost:${PORT}`);
});

module.exports = app;
28 changes: 16 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.21.0"
"express": "^4.21.2"
}
}
}
35 changes: 33 additions & 2 deletions public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,40 @@
</head>

<body>
<h1>Year Progress</h1>
<h1 id="title">Year Progress</h1>

<div style="text-align: center; margin: 1rem;">
<label id="chooseLangLabel" for="language">Choose Language:</label>
<select id="language" onchange="changeLanguage()">
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
<option value="de">German</option>
<option value="hi">Hindi</option>
</select>
</div>

<script>
function changeLanguage() {
const lang = document.getElementById("language").value;
const img = document.getElementById("progress-img");

let startDate = document.getElementById("startDate").value;
let endDate = document.getElementById("endDate").value;

// Build query string
let qs = `lang=${lang}`;
if (startDate) qs += `&startDate=${startDate}`;
if (endDate) qs += `&endDate=${endDate}`;

img.src = `http://localhost:3000/year-progress?${qs}&time=${Date.now()}`;
}
</script>


<img
id="progress-img"
src="https://year-in-progress.vercel.app/year-progress"
src="http://localhost:3000/year-progress"
Comment on lines +58 to +65
Copy link

Copilot AI Oct 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded localhost URL should be configurable or use relative URLs for production deployment. Consider using a relative path like /year-progress?${qs}&time=${Date.now()} instead.

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +65
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded localhost URL will break in production. Consider using a relative URL or environment-based configuration.

Copilot uses AI. Check for mistakes.
Comment on lines +58 to +65
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hardcoded localhost URL will break in production. Consider using a relative URL like '/year-progress'.

Copilot uses AI. Check for mistakes.
alt="Year Progress"
/>

Expand Down Expand Up @@ -106,6 +136,7 @@ <h1 id="random-msg"></h1>
integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
crossorigin="anonymous"
></script>

<script src="js/theme.js"></script>
<script src="js/animation.js"></script>
<script src="js/randomMsg.js"></script>
Expand Down