Add SEO metadata, fix linter warnings, and update documentation
Co-authored-by: setoelkahfi <1797197+setoelkahfi@users.noreply.github.com>
copilot-swe-agent[bot] committed
Oct 10, 2025 at 06:59 UTC
328f9c87bc551c59c6255437ba679c1e9e40f989
4 files changed
+63
-3
README.md
+52
-1
@@ -1,6 +1,57 @@
1
# PBJ Komplit!
2
3
-Tempat belajar bahasa Jawa.
3
+Tempat belajar bahasa Jawa. / A place to learn Javanese language.
4
+
5
+## Features
6
+
7
+- 🌐 **Bilingual Support**: Full internationalization (i18n) with Indonesian and English
8
+- 📱 **Responsive Design**: Works seamlessly on all devices
9
+- 🎨 **Modern UI**: Clean and intuitive interface
10
+- 🔍 **SEO Optimized**: Proper metadata and language alternates for better search engine visibility
11
+
12
+## Internationalization (i18n)
13
+
14
+This site supports multiple languages:
15
+
16
+- **Indonesian (id)** - Default language, accessible at `/`
17
+- **English (en)** - Accessible at `/en/`
18
+
19
+### Language Structure
20
+
21
+The i18n implementation includes:
22
+
23
+1. **Astro i18n Configuration** (`astro.config.ts`)
24
+ - Configured routing for Indonesian (default) and English
25
+ - Default locale: `id`
26
+ - Supported locales: `id`, `en`
27
+
28
+2. **Translation System** (`src/i18n/`)
29
+ - `ui.ts` - Translation dictionaries for UI strings
30
+ - `utils.ts` - Helper functions for language detection and URL generation
31
+
32
+3. **Content Organization**
33
+ - Indonesian content: `src/content/posts/`, `src/content/about/`
34
+ - English content: `src/content/posts/en/`, `src/content/about/en/`
35
+
36
+4. **Language Switcher**
37
+ - Located in the header for easy language switching
38
+ - Maintains the same page context when switching languages
39
+
40
+### Adding New Translations
41
+
42
+To add translations for UI elements:
43
+
44
+1. Edit `src/i18n/ui.ts`
45
+2. Add the key-value pair in both `en` and `id` sections
46
+3. Use the `t()` function in components to access translations
47
+
48
+### Adding Translated Content
49
+
50
+For blog posts or pages:
51
+
52
+1. Create content in `src/content/posts/en/` for English versions
53
+2. Keep Indonesian versions in `src/content/posts/`
54
+3. Use the same filename for both versions
55
56
## Deploy on smbCloud
57
src/components/layout/BaseHead.astro
+11
@@ -3,9 +3,13 @@
3
// all pages through the use of the <BaseHead /> component.
4
import { SITE } from '@/config'
5
import type { BaseHeadProps } from '@/types/component.types'
6
+import { getLangFromUrl, getAlternateUrl } from '@/i18n/utils'
7
import 'katex/dist/katex.min.css'
8
9
const canonicalURL = new URL(Astro.url.pathname, Astro.site)
10
+const currentLang = getLangFromUrl(Astro.url)
11
+const alternateLang = currentLang === 'id' ? 'en' : 'id'
12
+const alternateUrl = new URL(getAlternateUrl(Astro.url, alternateLang), Astro.site)
13
14
const { title, description } = Astro.props as BaseHeadProps
15
---
@@ -36,6 +40,11 @@ const { title, description } = Astro.props as BaseHeadProps
40
<!-- Canonical URL -->
41
<link rel="canonical" href={canonicalURL} />
42
43
+<!-- Alternate Languages -->
44
+<link rel="alternate" hreflang={currentLang} href={canonicalURL} />
45
+<link rel="alternate" hreflang={alternateLang} href={alternateUrl} />
46
+<link rel="alternate" hreflang="x-default" href={new URL('/', Astro.site)} />
47
+
48
<!-- Primary Meta Tags -->
49
<title>
50
{title || SITE.title}
@@ -49,6 +58,8 @@ const { title, description } = Astro.props as BaseHeadProps
58
<meta property="og:title" content={title} />
59
<meta property="og:description" content={description} />
60
<meta property="og:image" content={new URL('/chiri-og.png', Astro.url)} />
61
+<meta property="og:locale" content={currentLang === 'id' ? 'id_ID' : 'en_US'} />
62
+<meta property="og:locale:alternate" content={currentLang === 'id' ? 'en_US' : 'id_ID'} />
63
64
<!-- Twitter -->
65
<meta property="twitter:card" content="summary_large_image" />
src/components/ui/LanguageSwitcher.astro
-1
@@ -1,6 +1,5 @@
1
---
2
import { getLangFromUrl, getAlternateLanguage, getAlternateUrl, useTranslations } from '@/i18n/utils'
3
-import { languages } from '@/i18n/ui'
3
4
const currentLang = getLangFromUrl(Astro.url)
5
const alternateLang = getAlternateLanguage(currentLang)
src/pages/[...slug].astro
-1
@@ -2,7 +2,6 @@
2
import { type CollectionEntry, getCollection } from 'astro:content'
3
import PostLayout from '@/layouts/PostLayout.astro'
4
import { render } from 'astro:content'
5
-import { getLangFromUrl } from '@/i18n/utils'
5
6
export async function getStaticPaths() {
7
const posts = await getCollection('posts')