Skip to content

Commit 93f4de5

Browse files
authored
feat: Add support for locale translations (DenverCoder1#232)
* feat: Add locale option * fix: catch errors in demo preview
1 parent 376d4fa commit 93f4de5

File tree

9 files changed

+257
-79
lines changed

9 files changed

+257
-79
lines changed

README.md

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -58,23 +58,24 @@ The `user` field is the only required option. All other fields are optional.
5858

5959
If the `theme` parameter is specified, any color customizations specified will be applied on top of the theme, overriding the theme's values.
6060

61-
| Parameter | Details | Example |
62-
| :---------------: | :--------------------------------------------: | :---------------------------------------------------: |
63-
| `user` | GitHub username to show stats for | `DenverCoder1` |
64-
| `theme` | The theme to apply (Default: `default`) | `dark`, `radical`, etc. [🎨➜](./docs/themes/README.md) |
65-
| `hide_border` | Make the border transparent (Default: `false`) | `true` or `false` |
66-
| `background` | Background color | **hex code** without `#` or **css color** |
67-
| `border` | Border color | **hex code** without `#` or **css color** |
68-
| `stroke` | Stroke line color between sections | **hex code** without `#` or **css color** |
69-
| `ring` | Color of the ring around the current streak | **hex code** without `#` or **css color** |
70-
| `fire` | Color of the fire in the ring | **hex code** without `#` or **css color** |
71-
| `currStreakNum` | Current streak number | **hex code** without `#` or **css color** |
72-
| `sideNums` | Total and longest streak numbers | **hex code** without `#` or **css color** |
73-
| `currStreakLabel` | Current streak label | **hex code** without `#` or **css color** |
74-
| `sideLabels` | Total and longest streak labels | **hex code** without `#` or **css color** |
75-
| `dates` | Date range text color | **hex code** without `#` or **css color** |
76-
| `date_format` | Date format (Default: `M j[, Y]`) | See note below on [Date Formats](#date-formats) |
77-
| `type` | Output format (Default: `svg`) | Current options: `svg`, `png` or `json` |
61+
| Parameter | Details | Example |
62+
| :---------------: | :--------------------------------------------: | :---------------------------------------------------------------: |
63+
| `user` | GitHub username to show stats for | `DenverCoder1` |
64+
| `theme` | The theme to apply (Default: `default`) | `dark`, `radical`, etc. [🎨➜](./docs/themes/README.md) |
65+
| `hide_border` | Make the border transparent (Default: `false`) | `true` or `false` |
66+
| `background` | Background color | **hex code** without `#` or **css color** |
67+
| `border` | Border color | **hex code** without `#` or **css color** |
68+
| `stroke` | Stroke line color between sections | **hex code** without `#` or **css color** |
69+
| `ring` | Color of the ring around the current streak | **hex code** without `#` or **css color** |
70+
| `fire` | Color of the fire in the ring | **hex code** without `#` or **css color** |
71+
| `currStreakNum` | Current streak number | **hex code** without `#` or **css color** |
72+
| `sideNums` | Total and longest streak numbers | **hex code** without `#` or **css color** |
73+
| `currStreakLabel` | Current streak label | **hex code** without `#` or **css color** |
74+
| `sideLabels` | Total and longest streak labels | **hex code** without `#` or **css color** |
75+
| `dates` | Date range text color | **hex code** without `#` or **css color** |
76+
| `date_format` | Date format (Default: `M j[, Y]`) | See note below on [Date Formats](#date-formats) |
77+
| `locale` | Locale to use for labels (Default: `en`) | ISO 639-1 code (See [`translations.php`](./src/translations.php)) |
78+
| `type` | Output format (Default: `svg`) | Current options: `svg`, `png` or `json` |
7879

7980
### Date Formats
8081

src/card.php

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,27 @@ function getRequestedTheme(array $params): array
9090
* @param array<string, string>|NULL $params Request parameters
9191
*
9292
* @return string The generated SVG Streak Stats card
93+
*
94+
* @throws InvalidArgumentException If a locale does not exist
9395
*/
9496
function generateCard(array $stats, array $params = null): string
9597
{
96-
// get requested theme, use $_REQUEST if no params array specified
97-
$theme = getRequestedTheme($params ?? $_REQUEST);
98+
$params = $params ?? $_REQUEST;
99+
100+
// get requested theme
101+
$theme = getRequestedTheme($params);
102+
103+
// get the labels from the translations file
104+
$labels = include "translations.php";
105+
// get requested locale, default to English
106+
$locale = $params["locale"] ?? "en";
107+
// if the locale does not exist in the first value of the labels array, throw an exception
108+
if (!isset(reset($labels)[$locale])) {
109+
throw new InvalidArgumentException("That locale is not supported. You can help by adding it to the translations file.");
110+
}
98111

99112
// get date format
100-
$dateFormat = isset(($params ?? $_REQUEST)["date_format"])
101-
? ($params ?? $_REQUEST)["date_format"]
102-
: "M j[, Y]";
113+
$dateFormat = $params["date_format"] ?? "M j[, Y]";
103114

104115
// total contributions
105116
$totalContributions = $stats["totalContributions"];
@@ -167,7 +178,7 @@ function generateCard(array $stats, array $params = null): string
167178
<g transform='translate(1,84)'>
168179
<rect width='163' height='50' stroke='none' fill='none'></rect>
169180
<text x='81.5' y='32' stroke-width='0' text-anchor='middle' style='font-family:Segoe UI, Ubuntu, sans-serif;font-weight:400;font-size:14px;font-style:normal;fill:{$theme["sideLabels"]};stroke:none; opacity: 0; animation: fadein 0.5s linear forwards 0.7s;'>
170-
Total Contributions
181+
{$labels["totalContributions"][$locale]}
171182
</text>
172183
</g>
173184
@@ -192,7 +203,7 @@ function generateCard(array $stats, array $params = null): string
192203
<g transform='translate(166,108)'>
193204
<rect width='163' height='50' stroke='none' fill='none'></rect>
194205
<text x='81.5' y='32' stroke-width='0' text-anchor='middle' style='font-family:Segoe UI, Ubuntu, sans-serif;font-weight:700;font-size:14px;font-style:normal;fill:{$theme["currStreakLabel"]};stroke:none;opacity: 0; animation: fadein 0.5s linear forwards 0.9s;'>
195-
Current Streak
206+
{$labels["currentStreak"][$locale]}
196207
</text>
197208
</g>
198209
@@ -228,7 +239,7 @@ function generateCard(array $stats, array $params = null): string
228239
<g transform='translate(331,84)'>
229240
<rect width='163' height='50' stroke='none' fill='none'></rect>
230241
<text x='81.5' y='32' stroke-width='0' text-anchor='middle' style='font-family:Segoe UI, Ubuntu, sans-serif;font-weight:400;font-size:14px;font-style:normal;fill:{$theme["sideLabels"]};stroke:none;opacity: 0; animation: fadein 0.5s linear forwards 1.3s;'>
231-
Longest Streak
242+
{$labels["longestStreak"][$locale]}
232243
</text>
233244
</g>
234245
@@ -255,8 +266,10 @@ function generateCard(array $stats, array $params = null): string
255266
*/
256267
function generateErrorCard(string $message, array $params = null): string
257268
{
269+
$params = $params ?? $_REQUEST;
270+
258271
// get requested theme, use $_REQUEST if no params array specified
259-
$theme = getRequestedTheme($params ?? $_REQUEST);
272+
$theme = getRequestedTheme($params);
260273

261274
return "<svg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' style='isolation:isolate' viewBox='0 0 495 195' width='495px' height='195px'>
262275
<style>

src/demo/index.php

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
<?php $THEMES = include "../themes.php"; ?>
1+
<?php
2+
3+
$THEMES = include "../themes.php";
4+
$TRANSLATIONS = include "../translations.php";
5+
// Get the keys of the first value in the translations array
6+
$LOCALES = array_keys(reset($TRANSLATIONS));
7+
8+
?>
29

310
<!DOCTYPE html>
411
<html lang="en">
@@ -79,6 +86,13 @@ function gtag() {
7986
<option value="[Y.]n.j">2016.8.10</option>
8087
</select>
8188

89+
<label for="locale">Locale</label>
90+
<select class="param" id="locale" name="locale">
91+
<?php foreach ($LOCALES as $locale) : ?>
92+
<option value="<?php echo $locale; ?>"><?php echo Locale::getDisplayLanguage($locale, $locale) . " (" . $locale . ")"; ?></option>
93+
<?php endforeach; ?>
94+
</select>
95+
8296
<details class="advanced">
8397
<summary>⚙ Advanced Options</summary>
8498
<div class="content parameters">
@@ -122,4 +136,4 @@ function gtag() {
122136
</a>
123137
</body>
124138

125-
</html>
139+
</html>

src/demo/js/script.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ let preview = {
22
// default values
33
defaults: {
44
theme: "default",
5+
locale: "en",
56
hide_border: "false",
67
},
78
// update the preview

src/demo/preview.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,8 @@
2323
// set content type to SVG image
2424
header("Content-Type: image/svg+xml");
2525

26-
// echo SVG data for demo stats
27-
echo generateCard($demoStats);
26+
try {
27+
renderOutput($demoStats);
28+
} catch (InvalidArgumentException | AssertionError $error) {
29+
renderOutput($error->getMessage(), $error->getCode());
30+
}

src/themes.php

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
// mapping of theme colors given a theme name
4-
return array(
4+
return [
55
"default" => [
66
"background" => "#fffefe",
77
"border" => "#e4e2e2",
@@ -831,54 +831,54 @@
831831
"dates" => "#9e9e9e",
832832
],
833833
"github-light" => [
834-
"background" => "#FFFFFF",
835-
"border" => "#39D353",
836-
"stroke" => "#39D353",
837-
"ring" => "#39D353",
838-
"currStreakNum" => "#39D353",
839-
"fire" => "#39D353",
840-
"sideNums" => "#39D353",
841-
"currStreakLabel" => "#24292F",
842-
"sideLabels" => "#24292F",
843-
"dates" => "#1F6FEB",
844-
],
834+
"background" => "#FFFFFF",
835+
"border" => "#39D353",
836+
"stroke" => "#39D353",
837+
"ring" => "#39D353",
838+
"currStreakNum" => "#39D353",
839+
"fire" => "#39D353",
840+
"sideNums" => "#39D353",
841+
"currStreakLabel" => "#24292F",
842+
"sideLabels" => "#24292F",
843+
"dates" => "#1F6FEB",
844+
],
845845
"elegant" => [
846-
"background" => "#03071e",
847-
"border" => "#abcdef",
848-
"stroke" => "#abcdef",
849-
"ring" => "#ca6702",
850-
"currStreakNum" => "#abcdef",
851-
"fire" => "#e85d04",
852-
"sideNums" => "#abdcfe",
853-
"currStreakLabel" => "#abcdef",
854-
"sideLabels" => "#fedcba",
855-
"dates" => "#ff7b00",
856-
],
857-
"leafy" => [
858-
"background" => "#081c15",
859-
"border" => "#abcdef",
860-
"stroke" => "#081c15",
861-
"ring" => "#abcdef",
862-
"currStreakNum" => "#ff5400",
863-
"fire" => "#abcdef",
864-
"sideNums" => "#ff5400",
865-
"currStreakLabel" => "#ff5400",
866-
"sideLabels" => "#abcabc",
867-
"dates" => "#fecfec",
868-
],
869-
"navy-gear" => [
870-
"background" => "#000021",
871-
"border" => "#FFFFFF",
872-
"stroke" => "#FFFFFF",
873-
"ring" => "#1FA0DD",
874-
"fire" => "#1FA0DD",
875-
"currStreakNum" => "#C3DD00",
876-
"sideNums" => "#C3DD00",
877-
"currStreakLabel" => "#C3DD00",
878-
"sideLabels" => "#C3DD00",
879-
"dates" => "#1FA0DD",
880-
],
881-
"hacker" => [
846+
"background" => "#03071e",
847+
"border" => "#abcdef",
848+
"stroke" => "#abcdef",
849+
"ring" => "#ca6702",
850+
"currStreakNum" => "#abcdef",
851+
"fire" => "#e85d04",
852+
"sideNums" => "#abdcfe",
853+
"currStreakLabel" => "#abcdef",
854+
"sideLabels" => "#fedcba",
855+
"dates" => "#ff7b00",
856+
],
857+
"leafy" => [
858+
"background" => "#081c15",
859+
"border" => "#abcdef",
860+
"stroke" => "#081c15",
861+
"ring" => "#abcdef",
862+
"currStreakNum" => "#ff5400",
863+
"fire" => "#abcdef",
864+
"sideNums" => "#ff5400",
865+
"currStreakLabel" => "#ff5400",
866+
"sideLabels" => "#abcabc",
867+
"dates" => "#fecfec",
868+
],
869+
"navy-gear" => [
870+
"background" => "#000021",
871+
"border" => "#FFFFFF",
872+
"stroke" => "#FFFFFF",
873+
"ring" => "#1FA0DD",
874+
"fire" => "#1FA0DD",
875+
"currStreakNum" => "#C3DD00",
876+
"sideNums" => "#C3DD00",
877+
"currStreakLabel" => "#C3DD00",
878+
"sideLabels" => "#C3DD00",
879+
"dates" => "#1FA0DD",
880+
],
881+
"hacker" => [
882882
"background" => "#000000",
883883
"border" => "#20C20E",
884884
"stroke" => "#20C20E",
@@ -902,4 +902,4 @@
902902
"sideLabels" => "#6FDD6C",
903903
"dates" => "#6FDD6C",
904904
],
905-
);
905+
];

src/translations.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
return [
4+
"currentStreak" => [
5+
"en" => "Current Streak",
6+
"ja" => "現在のストリーク",
7+
],
8+
"totalContributions" => [
9+
"en" => "Total Contributions",
10+
"ja" => "総貢献数",
11+
],
12+
"longestStreak" => [
13+
"en" => "Longest Streak",
14+
"ja" => "最長ストリーク",
15+
],
16+
];

tests/RenderTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,18 @@ public function testDateFormatRender(): void
7373
$this->assertEquals($expected, $render);
7474
}
7575

76+
/**
77+
* Test locale parameter in render
78+
*/
79+
public function testLocaleRender(): void
80+
{
81+
$this->testParams["locale"] = "ja";
82+
// Check that the card is rendered as expected
83+
$render = generateCard($this->testStats, $this->testParams);
84+
$expected = file_get_contents("tests/expected/test_locale_card.svg");
85+
$this->assertEquals($expected, $render);
86+
}
87+
7688
/**
7789
* Test JSON render
7890
*/

0 commit comments

Comments
 (0)