): string {
+ const raw = this.raw(key);
+ let value = (raw as ToStringable)?.toString?.() ?? `N/A`;
+
+ if (map) {
+ for (const [placeholder, replacement] of Object.entries(map)) {
+ value = value.replace(new RegExp(`{%${placeholder}%}`, 'g'), replacement.toString());
+ }
+ }
+
+ return value;
+ }
+}
\ No newline at end of file
diff --git a/src/language/pl-PL.json b/src/language/pl-PL.json
new file mode 100644
index 0000000..2ed8bcb
--- /dev/null
+++ b/src/language/pl-PL.json
@@ -0,0 +1,50 @@
+{
+ "hello": "Cześć",
+ "about": "Nazywam się Franek. Mam {%years%} lat, {%months%} miesięcy i {%days%} dni.",
+ "switch_theme": "Zmień motyw na {%theme%}",
+ "broad_music_spectrum": "Tak, zdaję sobie sprawę z tego, że słucham szerokiego spektrum muzyki",
+ "headers": {
+ "facts": "Kilka faktów o mnie",
+ "skills": "Potrafię...",
+ "music": "Moje ulubione gatunki muzyczne to:",
+ "bands": "Lubię tych wykonawców:"
+ },
+ "skills": [
+ "grać na pianinie/organach",
+ "majstrować przy komputerach — od oprogramowania po sprzęt",
+ "tworzyć różne aplikacje i skrypty"
+ ],
+ "about_me": [
+ "introwertyk",
+ "entuzjasta IT",
+ "pasjonat motoryzacji"
+ ],
+ "section": {
+ "fediverse": "Fediverse...",
+ "contact": "Skontaktuj się ze mną...",
+ "links": "Kilka linków..."
+ },
+ "fediverse": {
+ "pleroma": "Pleroma",
+ "pixelfed": "Pixelfed",
+ "peertube": "PeerTube"
+ },
+ "contact": {
+ "matrix": "Matrix",
+ "signal": "@sadorowo.66"
+ },
+ "link": {
+ "pgp": "PGP",
+ "uptime": "Uptime moich usług",
+ "email": "E-mail",
+ "gitea": "Gitea",
+ "instagram": "Instagram (dezaktywowany)"
+ },
+ "most_used_languages": "Języki, których najczęściej używam:",
+ "favourite_tools": "Świetne narzędzia...",
+ "languages": {
+ "pl": "Polski",
+ "en-US": "Stany Zjednoczone",
+ "en-GB": "Wielka Brytania"
+ }
+}
\ No newline at end of file
diff --git a/src/sections/about.tsx b/src/sections/about.tsx
index b4d5840..5743ed6 100644
--- a/src/sections/about.tsx
+++ b/src/sections/about.tsx
@@ -1,40 +1,53 @@
import styled from "styled-components";
-import { useTheme } from "../style/themes";
-import { calculateAge } from "../utils/math";
+import { useTheme } from "../style/themes";
+import { useLanguage } from "../language/context";
+
+import { calculateAge } from "../utils/math";
import { asCardStack } from "../components/card-stack";
const About: React.FC = () => {
- const { years, months, days } = calculateAge(new Date(2007, 6, 25));
+ const age = calculateAge(new Date(2007, 6, 25));
const { theme, toggleTheme } = useTheme();
+ const { $, setLanguage } = useLanguage();
return <>
- Hello.
- My name is Franek. I'm {years} years, {months} months and {days} days old.
+ {$.tr("hello")}.
+ {$.tr("about", age)}
{asCardStack([
{
- content: `switch theme to ${theme.type === "light" ? "dark" : "light"}`,
+ content: $.tr("switch_theme", { theme: theme.type === "light" ? "dark" : "light" }),
icon: "/icons/" + (theme.type === "light" ? "moon" : "sun") + ".svg",
primary: theme.type === "light",
onClick: toggleTheme
+ },
+ {
+ content: $.tr("languages.pl"),
+ icon: "/icons/countries/pl.svg",
+ noeffects: true,
+ onClick: () => setLanguage('pl-PL')
+ },
+ {
+ content: $.tr("languages.en-US"),
+ icon: "/icons/countries/us.svg",
+ noeffects: true,
+ onClick: () => setLanguage('en-US')
+ },
+ {
+ content: $.tr("languages.en-GB"),
+ icon: "/icons/countries/uk.svg",
+ noeffects: true,
+ onClick: () => setLanguage('en-GB')
}
])}
- Some facts about me
- {asCardStack([
- "introvert",
- "IT enthusiast",
- "automotive enthusiast"
- ])}
+ {$.tr("headers.facts")}
+ {asCardStack($.raw("about_me") as string[])}
- I can...
- {asCardStack([
- "play keyboard/organ",
- "mess with PCs from software to hardware",
- "code various apps and scripts"
- ])}
+ {$.tr("headers.skills")}
+ {asCardStack($.raw("skills") as string[])}
- My favourite music genres are:
+ {$.tr("headers.music")}
{asCardStack([
"black metal",
"doom metal",
@@ -43,7 +56,8 @@ const About: React.FC = () => {
"hard rock"
])}
- I like these bands/singers:
+ {$.tr("headers.bands")}
+ {$.tr("broad_music_spectrum")}
{asCardStack([
"Mgła",
"Behemoth",
@@ -60,7 +74,6 @@ const About: React.FC = () => {
"ABBA",
"Evanescence"
])}
- yeah I know, I listen to a broad spectrum of music
>;
}
diff --git a/src/sections/links.tsx b/src/sections/links.tsx
index a0e7810..41f2eb6 100644
--- a/src/sections/links.tsx
+++ b/src/sections/links.tsx
@@ -1,81 +1,80 @@
-import styled from "styled-components";
import { asCardStack } from "../components/card-stack";
+import { useLanguage } from "../language/context";
+import LanguageManager from "../language/manager";
const Links: React.FC = () => {
+ const { $ } = useLanguage();
+
return <>
- Fediverse...
- {asCardStack(FEDIVERSE_LINKS)}
+ {$.tr("section.fediverse")}
+ {asCardStack(FEDIVERSE_LINKS($))}
- Contact ways...
- {asCardStack(CONTACT_WAYS)}
+ {$.tr("section.contact")}
+ {asCardStack(CONTACT_WAYS($))}
- Some links...
- {asCardStack(LINKS)}
+ {$.tr("section.links")}
+ {asCardStack(LINKS($))}
>;
}
-const Heading = styled.h1`
- font-family: "Pacifico", serif;
-`;
-
-const FEDIVERSE_LINKS = [
+const FEDIVERSE_LINKS = ($: LanguageManager) => [
{
- content: "Pleroma",
+ content: $.tr("fediverse.pleroma"),
icon: "/icons/fediverse/pleroma.svg",
link: "https://social.sador.me/@boss"
},
{
- content: "Pixelfed",
+ content: $.tr("fediverse.pixelfed"),
icon: "/icons/fediverse/pixelfed.svg",
link: "https://pix.sador.me/boss"
},
{
- content: "PeerTube",
+ content: $.tr("fediverse.peertube"),
icon: "/icons/fediverse/peertube.svg",
link: "https://tube.sador.me/c/sador"
}
].map(link => Object.assign(link, { primary: true }));
-const CONTACT_WAYS = [
+const CONTACT_WAYS = ($: LanguageManager) => [
{
- content: "Matrix",
+ content: $.tr("contact.matrix"),
icon: "/icons/matrix.svg",
link: "https://matrix.to/#/@boss:sador.me"
},
{
- content: "@sadorowo.66",
+ content: $.tr("contact.signal"),
icon: "/icons/signal.svg"
}
];
-const LINKS = [
+const LINKS = ($: LanguageManager) => [
{
- content: "PGP",
+ content: $.tr("link.pgp"),
icon: "/icons/pgp.svg",
link: "/pgp.asc",
primary: true
},
{
- content: "Uptime of my services",
+ content: $.tr("link.uptime"),
icon: "/icons/uptime.svg",
link: "https://health.sador.me/status/aio"
},
{
- content: "E-mail",
+ content: $.tr("link.email"),
icon: "/icons/email.svg",
link: "mailto:contact@sador.me?subject=[sador.me] ..."
},
{
- content: "Gitea",
+ content: $.tr("link.gitea"),
icon: "/icons/gitea.svg",
link: "https://git.sador.me"
},
{
- content: "Instagram (deactivated)",
+ content: $.tr("link.instagram"),
icon: "/icons/instagram.svg",
disabled: true,
link: "https://instagram.com/sadorowo"
}
];
-export default Links;
+export default Links;
\ No newline at end of file
diff --git a/src/sections/tools.tsx b/src/sections/tools.tsx
index 3dcb961..0e11167 100644
--- a/src/sections/tools.tsx
+++ b/src/sections/tools.tsx
@@ -1,11 +1,14 @@
import { asCardStack } from "../components/card-stack";
+import { useLanguage } from "../language/context";
const Tools: React.FC = () => {
+ const { $ } = useLanguage();
+
return <>
- Languages that I use the most:
+ {$.tr("most_used_languages")}
{asCardStack(LANGUAGES)}
- My favourite tools...
+ {$.tr("favourite_tools")}
{asCardStack(TOOLS)}
>;
}
diff --git a/src/style/index.css b/src/style/index.css
index da28eba..8fc8be9 100644
--- a/src/style/index.css
+++ b/src/style/index.css
@@ -12,4 +12,8 @@ body {
h1, h2, h3, h4, h5, h6 {
text-transform: lowercase;
+}
+
+p {
+ margin-top: 0;
}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index 7ed3b84..95e69d2 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -5,6 +5,7 @@
"module": "commonjs",
"esModuleInterop": true,
"noEmit": true,
+ "resolveJsonModule": true,
"allowImportingTsExtensions": true,
"forceConsistentCasingInFileNames": true,
"strict": true,