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')