diff --git a/api/index.js b/api/index.js
index b09a87fe..f2fd54ec 100644
--- a/api/index.js
+++ b/api/index.js
@@ -28,6 +28,7 @@ module.exports = async (req, res) => {
theme,
cache_seconds,
custom_title,
+ lang,
} = req.query;
let stats;
@@ -36,6 +37,9 @@ module.exports = async (req, res) => {
if (blacklist.includes(username)) {
return res.send(renderError("Something went wrong"));
}
+ if (lang && ![ "cn", "de", "en", "es", "fr", "it", "ja", "kr", "pt-br" ].includes(lang.toLowerCase())) {
+ return res.send(renderError("Something went wrong", "Language not found"));
+ }
try {
stats = await fetchStats(
@@ -67,6 +71,7 @@ module.exports = async (req, res) => {
bg_color,
theme,
custom_title,
+ lang: lang ? lang.toLowerCase() : null,
}),
);
} catch (err) {
diff --git a/api/pin.js b/api/pin.js
index 3486e70d..4d6c6fca 100644
--- a/api/pin.js
+++ b/api/pin.js
@@ -21,6 +21,7 @@ module.exports = async (req, res) => {
theme,
show_owner,
cache_seconds,
+ lang,
} = req.query;
let repoData;
@@ -31,6 +32,10 @@ module.exports = async (req, res) => {
return res.send(renderError("Something went wrong"));
}
+ if (lang && ![ "cn", "de", "en", "es", "fr", "it", "ja", "kr", "pt-br" ].includes(lang.toLowerCase())) {
+ return res.send(renderError("Something went wrong", "Language not found"));
+ }
+
try {
repoData = await fetchRepo(username, repo);
@@ -64,6 +69,7 @@ module.exports = async (req, res) => {
bg_color,
theme,
show_owner: parseBoolean(show_owner),
+ lang: lang ? lang.toLowerCase() : null,
}),
);
} catch (err) {
diff --git a/api/top-langs.js b/api/top-langs.js
index 77bcc19b..b8e0d705 100644
--- a/api/top-langs.js
+++ b/api/top-langs.js
@@ -26,6 +26,7 @@ module.exports = async (req, res) => {
langs_count,
exclude_repo,
custom_title,
+ lang,
} = req.query;
let topLangs;
@@ -35,6 +36,10 @@ module.exports = async (req, res) => {
return res.send(renderError("Something went wrong"));
}
+ if (lang && ![ "cn", "de", "en", "es", "fr", "it", "ja", "kr", "pt-br" ].includes(lang.toLowerCase())) {
+ return res.send(renderError("Something went wrong", "Language not found"));
+ }
+
try {
topLangs = await fetchTopLanguages(
username,
@@ -62,6 +67,7 @@ module.exports = async (req, res) => {
bg_color,
theme,
layout,
+ lang: lang ? lang.toLowerCase() : null,
}),
);
} catch (err) {
diff --git a/api/wakatime.js b/api/wakatime.js
index 7277c9d9..75878b37 100644
--- a/api/wakatime.js
+++ b/api/wakatime.js
@@ -22,10 +22,15 @@ module.exports = async (req, res) => {
hide_title,
hide_progress,
custom_title,
+ lang,
} = req.query;
res.setHeader("Content-Type", "image/svg+xml");
+ if (lang && ![ "cn", "de", "en", "es", "fr", "it", "ja", "kr", "pt-br" ].includes(lang.toLowerCase())) {
+ return res.send(renderError("Something went wrong", "Language not found"));
+ }
+
try {
const last7Days = await fetchLast7Days({ username });
@@ -53,6 +58,7 @@ module.exports = async (req, res) => {
bg_color,
theme,
hide_progress,
+ lang: lang ? lang.toLowerCase() : null,
}),
);
} catch (err) {
diff --git a/src/cards/repo-card.js b/src/cards/repo-card.js
index 7b021ca0..2f11c8a7 100644
--- a/src/cards/repo-card.js
+++ b/src/cards/repo-card.js
@@ -28,8 +28,34 @@ const renderRepoCard = (repo, options = {}) => {
bg_color,
show_owner,
theme = "default_repocard",
+ lang = "en",
} = options;
+ const translations = {
+ template: {
+ cn: "模板",
+ de: "Vorlage",
+ en: "Template",
+ es: "Modelo",
+ fr: "Modèle",
+ it: "Modella",
+ ja: "テンプレート",
+ kr: "주형",
+ "pt-br": "Modelo",
+ },
+ archived: {
+ cn: "已封存",
+ de: "Archiviert",
+ en: "Archived",
+ es: "Archivé",
+ fr: "Archivé",
+ it: "Archiviata",
+ ja: "アーカイブ済み",
+ kr: "보관 됨",
+ "pt-br": "Arquivada",
+ },
+ }
+
const header = show_owner ? nameWithOwner : name;
const langName = (primaryLanguage && primaryLanguage.name) || "Unspecified";
const langColor = (primaryLanguage && primaryLanguage.color) || "#333";
@@ -132,9 +158,9 @@ const renderRepoCard = (repo, options = {}) => {
return card.render(`
${
isTemplate
- ? getBadgeSVG("Template")
+ ? getBadgeSVG(translations.template[lang] || "Template")
: isArchived
- ? getBadgeSVG("Archived")
+ ? getBadgeSVG(translations.archived[lang] || "Archived")
: ""
}
diff --git a/src/cards/stats-card.js b/src/cards/stats-card.js
index 4954c719..87f77c34 100644
--- a/src/cards/stats-card.js
+++ b/src/cards/stats-card.js
@@ -66,6 +66,7 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
bg_color,
theme = "default",
custom_title,
+ lang = "en",
} = options;
const lheight = parseInt(line_height, 10);
@@ -79,17 +80,87 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
theme,
});
+ const apostrophe = ["x", "s"].includes(name.slice(-1)) ? "" : "s";
+ const translations = {
+ title: {
+ cn: `${encodeHTML(name)}的GitHub统计`,
+ de: `${encodeHTML(name) + apostrophe} GitHub-Statistiken`,
+ en: `${encodeHTML(name)}'${apostrophe} GitHub Stats`,
+ es: `Estadísticas de GitHub de ${encodeHTML(name)}`,
+ fr: `Statistiques GitHub de ${encodeHTML(name)}`,
+ it: `Statistiche GitHub di ${encodeHTML(name)}`,
+ ja: `${encodeHTML(name)}のGitHub統計`,
+ kr: `${encodeHTML(name)}의 GitHub 통계`,
+ "pt-br": `Estatísticas do GitHub de ${encodeHTML(name)}`,
+ },
+ stars: {
+ cn: "总星数",
+ de: "Insgesamt Sterne",
+ en: "Total Stars",
+ es: "Estrellas totales",
+ fr: "Total d'étoiles",
+ it: "Stelle totali",
+ ja: "星の合計",
+ kr: "총 별",
+ "pt-br": "Total de estrelas",
+ },
+ commits: {
+ cn: "总承诺",
+ de: "Total Commits",
+ en: "Total Commits",
+ es: "Compromisos totales",
+ fr: "Total des engagements",
+ it: "Impegni totali",
+ ja: "総コミット",
+ kr: "총 커밋",
+ "pt-br": "Total de compromissos",
+ },
+ prs: {
+ cn: "总公关",
+ de: "PRs insgesamt",
+ en: "Total PRs",
+ es: "RP totales",
+ fr: "Total des PR",
+ it: "PR totali",
+ ja: "合計PR",
+ kr: "총 PR",
+ "pt-br": "Total de PRs",
+ },
+ issues: {
+ cn: "总发行量",
+ de: "Gesamtausgaben",
+ en: "Total Issues",
+ es: "Problemas totales",
+ fr: "Nombre total de problèmes",
+ it: "Problemi totali",
+ ja: "総問題",
+ kr: "총 문제",
+ "pt-br": "Total de problemas",
+ },
+ contribs: {
+ cn: "有助于",
+ de: "Beigetragen zu",
+ en: "Contributed to",
+ es: "Contribuido a",
+ fr: "Contribué à",
+ it: "Ha contribuito a",
+ ja: "に貢献しました",
+ kr: "에 기여하다",
+ "pt-br": "Contribuiu para",
+ }
+ }
+
// Meta data for creating text nodes with createTextNode function
const STATS = {
stars: {
icon: icons.star,
- label: "Total Stars",
+ label: translations.stars[lang] || "Total Stars",
value: totalStars,
id: "stars",
},
commits: {
icon: icons.commits,
- label: `Total Commits${
+ label: `${translations.commits[lang] || "Total Commits"}${
include_all_commits ? "" : ` (${new Date().getFullYear()})`
}`,
value: totalCommits,
@@ -97,19 +168,19 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
},
prs: {
icon: icons.prs,
- label: "Total PRs",
+ label: translations.prs[lang] || "Total PRs",
value: totalPRs,
id: "prs",
},
issues: {
icon: icons.issues,
- label: "Total Issues",
+ label: translations.issues[lang] || "Total Issues",
value: totalIssues,
id: "issues",
},
contribs: {
icon: icons.contribs,
- label: "Contributed to",
+ label: translations.contribs[lang] || "Contributed to",
value: contributedTo,
id: "contribs",
},
@@ -166,10 +237,9 @@ const renderStatsCard = (stats = {}, options = { hide: [] }) => {
progress,
});
- const apostrophe = ["x", "s"].includes(name.slice(-1)) ? "" : "s";
const card = new Card({
customTitle: custom_title,
- defaultTitle: `${encodeHTML(name)}'${apostrophe} GitHub Stats`,
+ defaultTitle: translations.title[lang] || `${encodeHTML(name)}'${apostrophe} GitHub Stats`,
width: 495,
height,
colors: {
diff --git a/src/cards/top-languages-card.js b/src/cards/top-languages-card.js
index 8e85b72a..1c17bbec 100644
--- a/src/cards/top-languages-card.js
+++ b/src/cards/top-languages-card.js
@@ -70,11 +70,26 @@ const renderTopLanguages = (topLangs, options = {}) => {
theme,
layout,
custom_title,
+ lang= "en",
} = options;
let langs = Object.values(topLangs);
let langsToHide = {};
+ const translations = {
+ title: {
+ cn: "最常用的语言",
+ de: "Meist verwendete Sprachen",
+ en: "Most Used Languages",
+ es: "Idiomas más usados",
+ fr: "Langues les plus utilisées",
+ it: "Lingue più utilizzate",
+ ja: "最もよく使われる言語",
+ kr: "가장 많이 사용되는 언어",
+ "pt-br": "Línguas Mais Usadas",
+ },
+ }
+
// populate langsToHide map for quick lookup
// while filtering out
if (hide) {
@@ -172,7 +187,7 @@ const renderTopLanguages = (topLangs, options = {}) => {
const card = new Card({
customTitle: custom_title,
- defaultTitle: "Most Used Languages",
+ defaultTitle: translations.title[lang] || "Most Used Languages",
width,
height,
colors: {
diff --git a/src/cards/wakatime-card.js b/src/cards/wakatime-card.js
index bf103f50..0c0e5559 100644
--- a/src/cards/wakatime-card.js
+++ b/src/cards/wakatime-card.js
@@ -3,9 +3,9 @@ const { getStyles } = require("../getStyles");
const { getCardColors, FlexLayout } = require("../common/utils");
const { createProgressNode } = require("../common/createProgressNode");
-const noCodingActivityNode = ({ color }) => {
+const noCodingActivityNode = ({ color, text }) => {
return `
- No coding activity this week
+ ${text}
`;
};
@@ -60,8 +60,34 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
theme = "default",
hide_progress,
custom_title,
+ lang = "en",
} = options;
+ const translations = {
+ title: {
+ cn: "Wakatime周统计",
+ de: "Wakatime Week Stats",
+ en: "Wakatime Week Stats",
+ es: "Estadísticas de la semana de Wakatime",
+ fr: "Statistiques de la semaine Wakatime",
+ it: "Statistiche della settimana di Wakatime",
+ ja: "ワカタイムウィーク統計",
+ kr: "Wakatime 주간 통계",
+ "pt-br": "Estatísticas da semana Wakatime",
+ },
+ noCodingActivity: {
+ cn: "本周没有编码活动",
+ de: "Keine Codierungsaktivität diese Woche",
+ en: "No coding activity this week",
+ es: "No hay actividad de codificación esta semana",
+ fr: "Aucune activité de codage cette semaine",
+ it: "Nessuna attività di codifica questa settimana",
+ ja: "今週のコーディング活動はありません",
+ kr: "이번 주 코딩 활동 없음",
+ "pt-br": "Nenhuma atividade de codificação esta semana",
+ },
+ }
+
const lheight = parseInt(line_height, 10);
// returns theme based colors with proper overrides and defaults
@@ -101,7 +127,7 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
const card = new Card({
customTitle: custom_title,
- defaultTitle: "Wakatime Week Stats",
+ defaultTitle: translations.title[lang] || "Wakatime Week Stats",
width: 495,
height,
colors: {
@@ -126,7 +152,7 @@ const renderWakatimeCard = (stats = {}, options = { hide: [] }) => {
${FlexLayout({
items: statItems.length
? statItems
- : [noCodingActivityNode({ color: textColor })],
+ : [noCodingActivityNode({ color: textColor, text: translations.noCodingActivity[lang] || "No coding activity this week" })],
gap: lheight,
direction: "column",
}).join("")}