Skip to content

Commit d02c25e

Browse files
committed
feature: added translations into json files and fixed i18n parser
1 parent f4be39e commit d02c25e

File tree

9 files changed

+108
-60
lines changed

9 files changed

+108
-60
lines changed

i18next-parser.config.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
export default {
2+
input: [
3+
"src/**/*.{js,ts,jsx,tsx,astro}",
4+
],
25
contextSeparator: ":",
36
// Key separator used in your translation keys
47
createOldCatalogs: false,
@@ -18,6 +21,12 @@ export default {
1821
lexers: {
1922
ts: ["JavascriptLexer"],
2023
tsx: ["JsxLexer"],
24+
astro: [
25+
{
26+
lexer: "JavascriptLexer",
27+
functions: ["t"]
28+
}
29+
],
2130
default: ["JavascriptLexer"],
2231
},
2332
lineEnding: "auto",
@@ -31,7 +40,6 @@ export default {
3140
// Supports $LOCALE and $NAMESPACE injection
3241
// Supports JSON (.json) and YAML (.yml) file formats
3342
// Where to write the locale files relative to process.cwd()
34-
input: undefined,
3543
// An array of globs that describe where to look for source files
3644
// relative to the location of the configuration file
3745
sort: true,

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"preview": "astro preview",
99
"astro": "astro",
1010
"i18n": "npm-run-all --parallel i18n:*",
11-
"i18n:craftserve": "i18next './src/**/*.{ts,tsx}' -c ./i18next-parser.config.js"
11+
"i18n:craftserve": "i18next --config ./i18next-parser.config.js"
1212
},
1313
"dependencies": {
1414
"@iconify-json/tabler": "^1.2.22",

public/static/locales/de.json

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
{
2-
"about": "__NOT_TRANSLATED__",
3-
"aboutUrl": "__NOT_TRANSLATED__",
4-
"contact": "__NOT_TRANSLATED__",
5-
"contactUrl": "__NOT_TRANSLATED__"
2+
"hero": {
3+
"header": "__NOT_TRANSLATED__"
4+
},
5+
"iconsSection": {
6+
"perfect": "__NOT_TRANSLATED__",
7+
"time": "__NOT_TRANSLATED__"
8+
},
9+
"links": {
10+
"about": "__NOT_TRANSLATED__",
11+
"aboutus": "__NOT_TRANSLATED__",
12+
"contact": "__NOT_TRANSLATED__",
13+
"joinus": "__NOT_TRANSLATED__",
14+
"learnmore": "__NOT_TRANSLATED__"
15+
},
16+
"urls": {
17+
"about": "__NOT_TRANSLATED__",
18+
"contact": "__NOT_TRANSLATED__"
19+
}
620
}

public/static/locales/en.json

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
{
2-
"about": "__NOT_TRANSLATED__",
3-
"aboutUrl": "__NOT_TRANSLATED__",
4-
"contact": "__NOT_TRANSLATED__",
5-
"contactUrl": "__NOT_TRANSLATED__"
2+
"hero": {
3+
"header": "Today is your| day to grow| in ideas."
4+
},
5+
"iconsSection": {
6+
"perfect": "Perfect for freelancers",
7+
"time": "Quick service delivery time"
8+
},
9+
"links": {
10+
"about": "About",
11+
"aboutus": "About us",
12+
"contact": "Contact",
13+
"joinus": "Join us",
14+
"learnmore": "learn more"
15+
},
16+
"urls": {
17+
"about": "about",
18+
"contact": "contact"
19+
}
620
}

public/static/locales/pl.json

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
{
2-
"about": "__NOT_TRANSLATED__",
3-
"aboutUrl": "__NOT_TRANSLATED__",
4-
"contact": "__NOT_TRANSLATED__",
5-
"contactUrl": "__NOT_TRANSLATED__"
2+
"hero": {
3+
"header": "Dziś jest Twój| dzień, aby urosnąć| w ideach."
4+
},
5+
"iconsSection": {
6+
"perfect": "Idealne dla freelancerów",
7+
"time": "Szybki czas realizacji usług"
8+
},
9+
"links": {
10+
"about": "Dlaczego my",
11+
"aboutus": "Więcej o nas",
12+
"contact": "Kontakt",
13+
"joinus": "Dołącz do nas",
14+
"learnmore": "dowiedz się"
15+
},
16+
"urls": {
17+
"about": "o-nas",
18+
"contact": "kontakt"
19+
}
620
}

src/i18n/ui.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1 @@
11
export const defaultLang = "pl-PL";
2-
3-
export const ui = {
4-
"en": {
5-
"example": "test",
6-
"about": "About",
7-
"contact": "Contact",
8-
"joinus": "Join us",
9-
"learnmore": "learn more",
10-
"aboutus": "About us",
11-
"header": "Today is your| day to grow| in ideas.",
12-
13-
"aboutUrl": "about",
14-
"contactUrl": "contact",
15-
},
16-
"pl-PL": {
17-
"example": "test po polsku",
18-
"about": "Dlaczego my",
19-
"contact": "Kontakt",
20-
"joinus": "Dołącz do nas",
21-
"learnmore": "dowiedz się",
22-
"aboutus": "Więcej o nas",
23-
"header": "Dziś jest Twój| dzień, aby urosnąć| w ideach.",
24-
25-
"aboutUrl": "o-nas",
26-
"contactUrl": "kontakt",
27-
}
28-
} as const;

src/i18n/utils.ts

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
import { ui, defaultLang } from './ui';
1+
import { defaultLang } from './ui';
2+
import en from "../../public/static/locales/en.json";
3+
import pl from "../../public/static/locales/pl.json";
4+
5+
const ui = {
6+
"en": en,
7+
"pl-PL": pl
8+
}
29

310
export function getLangFromUrl(url: URL) {
411
const [, lang] = url.pathname.split('/');
@@ -11,9 +18,17 @@ export function getLangForRedirect(url: URL) {
1118
if(lang in ui) return lang as keyof typeof ui;
1219
}
1320

21+
function getNestedValue(obj: any, path: string): string | undefined {
22+
return path.split('.').reduce((acc, part) => acc?.[part], obj);
23+
}
24+
1425
export function useTranslations(lang: keyof typeof ui) {
15-
return function t(key: keyof typeof ui[typeof defaultLang]) {
16-
return ui[lang][key] || ui[defaultLang][key];
26+
return function t(path: string) {
27+
return (
28+
getNestedValue(ui[lang], path) ??
29+
getNestedValue(ui[defaultLang], path) ??
30+
path
31+
);
1732
}
1833
}
1934

@@ -23,12 +38,12 @@ export function getRoutes(url: URL){
2338

2439
return [
2540
{
26-
name: t("contact"),
27-
url: `/${lang != defaultLang ? lang+"/" : ""}${t("contactUrl")}`
41+
name: t("links.contact"),
42+
url: `/${lang != defaultLang ? lang+"/" : ""}${t("urls.contact")}`
2843
},
2944
{
30-
name: t("about"),
31-
url: `/${lang != defaultLang ? lang+"/" : ""}${t("aboutUrl")}`
45+
name: t("links.about"),
46+
url: `/${lang != defaultLang ? lang+"/" : ""}${t("urls.about")}`
3247
}
3348
]
3449
}

src/sections/Hero.astro

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,13 @@ const t = useTranslations(lang);
1010
1111
const routes = getRoutes(Astro.url);
1212
13-
const headerContent = t("header").split("|");
13+
const headerContent = t("hero.header").split("|");
14+
15+
const mapping = {
16+
join: t("links.joinus"),
17+
learn: t("links.learnmore"),
18+
about: t("links.aboutus"),
19+
}
1420
---
1521

1622
<div class="wrapper">
@@ -29,13 +35,13 @@ const headerContent = t("header").split("|");
2935
<div class="buttonsContainer">
3036
<Link variant="primary" href={routes[0].url}>
3137
<Icon name="uil:phone" width={30} height={30} />
32-
{t("joinus")}
38+
{mapping.join}
3339
</Link>
3440
<Link variant="outlined" href={routes[1].url}>
3541
<Icon name="uil:info-circle" width={30} height={30} />
3642
<div style="display: flex; flex-direction: column;">
37-
<span style="font-weight: 400; font-size: 10pt;">{t("learnmore")}</span>
38-
<span style="font-weight: 700">{t("aboutus")}</span>
43+
<span style="font-weight: 400; font-size: 10pt;">{mapping.learn}</span>
44+
<span style="font-weight: 700">{mapping.about}</span>
3945
</div>
4046
</Link>
4147
</div>

src/sections/Icons.astro

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { Icon } from "astro-icon/components";
33
import Image from "astro/components/Image.astro";
44
import star from "../assets/star.svg";
5+
import { getLangFromUrl, useTranslations } from "../i18n/utils";
56
67
type IconItem = {
78
type: "icon";
@@ -15,46 +16,49 @@ type ImageItem = {
1516
text: string;
1617
};
1718
19+
const lang = getLangFromUrl(Astro.url);
20+
const t = useTranslations(lang);
21+
1822
const contentData: (IconItem | ImageItem)[] = [
1923
{
2024
type: "icon",
2125
iconName: "tabler:infinity",
22-
text: "Idealne dla freelancerów",
26+
text: t("iconsSection.perfect"),
2327
},
2428
{
2529
type: "icon",
2630
iconName: "tabler:clock",
27-
text: "Szybki czas realizacji usług",
31+
text: t("iconsSection.time"),
2832
},
2933
{
3034
type: "icon",
3135
iconName: "tabler:infinity",
32-
text: "Idealne dla freelancerów",
36+
text: t("iconsSection.perfect"),
3337
},
3438
{
3539
type: "icon",
3640
iconName: "tabler:clock",
37-
text: "Szybki czas realizacji usług",
41+
text: t("iconsSection.perfect"),
3842
},
3943
{
4044
type: "image",
4145
iconName: star,
42-
text: "Idealne dla freelancerów",
46+
text: t("iconsSection.perfect"),
4347
},
4448
{
4549
type: "icon",
4650
iconName: "tabler:clock",
47-
text: "Szybki czas realizacji usług",
51+
text: t("iconsSection.time"),
4852
},
4953
{
5054
type: "icon",
5155
iconName: "tabler:infinity",
52-
text: "Idealne dla freelancerów",
56+
text: t("iconsSection.perfect"),
5357
},
5458
{
5559
type: "icon",
5660
iconName: "tabler:clock",
57-
text: "Szybki czas realizacji usług",
61+
text: t("iconsSection.time"),
5862
},
5963
];
6064
---

0 commit comments

Comments
 (0)