@zoyth/simple-site-framework 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +572 -0
- package/bin/create-simple-site.js +390 -0
- package/bin/simple-site.js +664 -0
- package/dist/client.js +135 -0
- package/dist/client.js.map +1 -0
- package/dist/client.mjs +107 -0
- package/dist/client.mjs.map +1 -0
- package/dist/components/index.d.mts +3936 -0
- package/dist/components/index.d.ts +3936 -0
- package/dist/components/index.js +38265 -0
- package/dist/components/index.js.map +1 -0
- package/dist/components/index.mjs +38173 -0
- package/dist/components/index.mjs.map +1 -0
- package/dist/config/index.d.mts +298 -0
- package/dist/config/index.d.ts +298 -0
- package/dist/config/index.js +19 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/index.mjs +1 -0
- package/dist/config/index.mjs.map +1 -0
- package/dist/index.d.mts +2184 -0
- package/dist/index.d.ts +2184 -0
- package/dist/index.js +1713 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +1605 -0
- package/dist/index.mjs.map +1 -0
- package/dist/lib/i18n/index.js +665 -0
- package/dist/lib/i18n/index.js.map +1 -0
- package/dist/lib/i18n/index.mjs +621 -0
- package/dist/lib/i18n/index.mjs.map +1 -0
- package/docs/DOCUMENTATION-STRUCTURE.md +1156 -0
- package/docs/EXPORTS.md +125 -0
- package/docs/PERFORMANCE.md +757 -0
- package/docs/POLICY-PAGES.md +867 -0
- package/docs/ROADMAP.md +334 -0
- package/docs/SEO.md +455 -0
- package/docs/SITEMAP.md +708 -0
- package/docs/STRUCTURED-DATA.md +671 -0
- package/docs/accessibility/common-patterns.md +529 -0
- package/docs/accessibility/keyboard-navigation.md +263 -0
- package/docs/accessibility/overview.md +122 -0
- package/docs/accessibility/screen-readers.md +311 -0
- package/docs/accessibility/wcag-compliance.md +159 -0
- package/docs/api/README.md +164 -0
- package/docs/api/components/Accessibility.md +356 -0
- package/docs/api/components/Button.md +240 -0
- package/docs/api/components/HeroSection.md +306 -0
- package/docs/architecture/decisions.md +449 -0
- package/docs/components/AnalyticsTracker.md +58 -0
- package/docs/components/AnimatedCounter.md +48 -0
- package/docs/components/AnimatedSection.md +56 -0
- package/docs/components/BlogCard.md +42 -0
- package/docs/components/Checkbox.md +56 -0
- package/docs/components/CodeBlock.md +52 -0
- package/docs/components/ComparisonTable.md +40 -0
- package/docs/components/ComponentDemo.md +38 -0
- package/docs/components/CountdownTimer.md +51 -0
- package/docs/components/ExitIntentModal.md +56 -0
- package/docs/components/FAQAccordion.md +66 -0
- package/docs/components/FeaturesGrid.md +55 -0
- package/docs/components/FileUpload.md +54 -0
- package/docs/components/I18nMetaTags.md +55 -0
- package/docs/components/Icon.md +53 -0
- package/docs/components/LazySection.md +46 -0
- package/docs/components/LiveProof.md +53 -0
- package/docs/components/LoadingSpinner.md +46 -0
- package/docs/components/MultiStepForm.md +48 -0
- package/docs/components/PolicyLayout.md +55 -0
- package/docs/components/PricingTable.md +49 -0
- package/docs/components/Radio.md +59 -0
- package/docs/components/SEOMetaTags.md +58 -0
- package/docs/components/ScriptInjector.md +50 -0
- package/docs/components/Select.md +72 -0
- package/docs/components/Skeleton.md +47 -0
- package/docs/components/StatsSection.md +48 -0
- package/docs/components/StickyBar.md +62 -0
- package/docs/components/StructuredData.md +99 -0
- package/docs/components/StyleGuide.md +46 -0
- package/docs/components/TableOfContents.md +47 -0
- package/docs/components/TestimonialCarousel.md +42 -0
- package/docs/components/Timeline.md +51 -0
- package/docs/components/Toast.md +59 -0
- package/docs/components/TrackedLink.md +62 -0
- package/docs/components/TrustBadges.md +44 -0
- package/docs/components/conversion/MobileCTA.md +363 -0
- package/docs/components/forms/ContactForm.md +75 -0
- package/docs/components/forms/FormField.md +74 -0
- package/docs/components/layout/Footer.md +601 -0
- package/docs/components/layout/Header.md +549 -0
- package/docs/components/layout/LanguageSelector.md +54 -0
- package/docs/components/layout/LanguageSwitcher.md +24 -0
- package/docs/components/overview.md +447 -0
- package/docs/components/sections/AboutSection.md +48 -0
- package/docs/components/sections/CTASection.md +596 -0
- package/docs/components/sections/CaseStudySection.md +47 -0
- package/docs/components/sections/ContactSection.md +599 -0
- package/docs/components/sections/FeatureSection.md +44 -0
- package/docs/components/sections/HeroSection.md +404 -0
- package/docs/components/sections/LogosSection.md +47 -0
- package/docs/components/sections/PersonalTaxesSection.md +23 -0
- package/docs/components/sections/RecruitingSection.md +23 -0
- package/docs/components/sections/SecurePortalSection.md +23 -0
- package/docs/components/sections/ServicePageLayout.md +52 -0
- package/docs/components/sections/ServicesSection.md +49 -0
- package/docs/components/sections/TestimonialSection.md +44 -0
- package/docs/components/sections/WhyChooseUsSection.md +54 -0
- package/docs/components/ui/Breadcrumb.md +70 -0
- package/docs/components/ui/Button.md +514 -0
- package/docs/components/ui/Card.md +501 -0
- package/docs/components/ui/Input.md +54 -0
- package/docs/components/ui/MobileLinks.md +43 -0
- package/docs/components/ui/Modal.md +60 -0
- package/docs/components/ui/Tabs.md +62 -0
- package/docs/components/ui/Textarea.md +52 -0
- package/docs/core-concepts/configuration-driven.md +552 -0
- package/docs/core-concepts/overview.md +351 -0
- package/docs/features/accessibility/README.md +73 -0
- package/docs/features/accessibility/aria-support.md +177 -0
- package/docs/features/accessibility/color-contrast.md +155 -0
- package/docs/features/accessibility/focus-management.md +187 -0
- package/docs/features/accessibility/testing.md +196 -0
- package/docs/features/analytics/README.md +51 -0
- package/docs/features/analytics/ab-testing.md +171 -0
- package/docs/features/analytics/conversion-tracking.md +207 -0
- package/docs/features/analytics/custom-events.md +219 -0
- package/docs/features/analytics/privacy.md +198 -0
- package/docs/features/analytics/setup.md +114 -0
- package/docs/features/analytics/tracking-events.md +224 -0
- package/docs/features/i18n/README.md +51 -0
- package/docs/features/i18n/best-practices.md +273 -0
- package/docs/features/i18n/configuration.md +84 -0
- package/docs/features/i18n/formatting.md +133 -0
- package/docs/features/i18n/locale-detection.md +122 -0
- package/docs/features/i18n/routing.md +99 -0
- package/docs/features/i18n/rtl-support.md +191 -0
- package/docs/features/i18n/translations.md +129 -0
- package/docs/features/internationalization.md +595 -0
- package/docs/features/performance/README.md +77 -0
- package/docs/features/performance/bundle-size.md +134 -0
- package/docs/features/performance/caching.md +131 -0
- package/docs/features/performance/code-splitting.md +121 -0
- package/docs/features/performance/image-optimization.md +110 -0
- package/docs/features/performance/lazy-loading.md +92 -0
- package/docs/features/performance/monitoring.md +148 -0
- package/docs/features/seo/README.md +51 -0
- package/docs/features/seo/best-practices.md +184 -0
- package/docs/features/seo/canonical-urls.md +182 -0
- package/docs/features/seo/meta-tags.md +126 -0
- package/docs/features/seo/open-graph.md +166 -0
- package/docs/features/seo/robots-txt.md +146 -0
- package/docs/features/seo/sitemaps.md +162 -0
- package/docs/features/seo/structured-data.md +166 -0
- package/docs/getting-started/installation.md +292 -0
- package/docs/getting-started/introduction.md +195 -0
- package/docs/getting-started/quick-start.md +460 -0
- package/docs/guides/analytics-setup.md +616 -0
- package/docs/i18n/CONFIGURATION.md +353 -0
- package/docs/i18n/EXAMPLES.md +402 -0
- package/docs/i18n/MIGRATION.md +260 -0
- package/docs/i18n/SEO.md +392 -0
- package/docs/i18n/STATIC-GENERATION-FIX.md +71 -0
- package/docs/migration/changelog.md +136 -0
- package/docs/migration/overview.md +233 -0
- package/docs/recipes/adding-animations.md +475 -0
- package/docs/recipes/forms-with-validation.md +393 -0
- package/package.json +152 -0
package/docs/i18n/SEO.md
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
# i18n SEO Best Practices
|
|
2
|
+
|
|
3
|
+
Guide to optimizing multi-language sites for search engines.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
Add `I18nMetaTags` to your layout:
|
|
8
|
+
|
|
9
|
+
```tsx
|
|
10
|
+
import { I18nMetaTags } from 'simple-site-framework';
|
|
11
|
+
|
|
12
|
+
export default function Layout({ children, params }) {
|
|
13
|
+
return (
|
|
14
|
+
<html lang={params.locale}>
|
|
15
|
+
<head>
|
|
16
|
+
<I18nMetaTags
|
|
17
|
+
currentLocale={params.locale}
|
|
18
|
+
pathname="/about"
|
|
19
|
+
baseUrl="https://yoursite.com"
|
|
20
|
+
/>
|
|
21
|
+
</head>
|
|
22
|
+
<body>{children}</body>
|
|
23
|
+
</html>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
This generates:
|
|
29
|
+
- ✅ hreflang tags for all languages
|
|
30
|
+
- ✅ Canonical URL
|
|
31
|
+
- ✅ OpenGraph locale tags
|
|
32
|
+
- ✅ x-default for language selection
|
|
33
|
+
|
|
34
|
+
## hreflang Tags
|
|
35
|
+
|
|
36
|
+
### What They Do
|
|
37
|
+
|
|
38
|
+
Tell Google which language versions exist for each page.
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<!-- Generated by I18nMetaTags -->
|
|
42
|
+
<link rel="alternate" hreflang="en" href="https://example.com/about" />
|
|
43
|
+
<link rel="alternate" hreflang="fr" href="https://example.com/fr/about" />
|
|
44
|
+
<link rel="alternate" hreflang="es" href="https://example.com/es/about" />
|
|
45
|
+
<link rel="alternate" hreflang="x-default" href="https://example.com/about" />
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Best Practices
|
|
49
|
+
|
|
50
|
+
1. **Include all language versions** of each page
|
|
51
|
+
2. **Use x-default** for language selection page
|
|
52
|
+
3. **Be consistent** across all pages
|
|
53
|
+
4. **Use correct codes** (ISO 639-1)
|
|
54
|
+
|
|
55
|
+
### Common Issues
|
|
56
|
+
|
|
57
|
+
**❌ Wrong:** Different base URLs
|
|
58
|
+
```html
|
|
59
|
+
<link rel="alternate" hreflang="en" href="https://en.example.com/about" />
|
|
60
|
+
<link rel="alternate" hreflang="fr" href="https://example.fr/about" />
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**✅ Right:** Same domain, different paths
|
|
64
|
+
```html
|
|
65
|
+
<link rel="alternate" hreflang="en" href="https://example.com/about" />
|
|
66
|
+
<link rel="alternate" hreflang="fr" href="https://example.com/fr/about" />
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Canonical URLs
|
|
70
|
+
|
|
71
|
+
### What They Do
|
|
72
|
+
|
|
73
|
+
Tell search engines which URL is the "main" version.
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<!-- Current page canonical -->
|
|
77
|
+
<link rel="canonical" href="https://example.com/fr/about" />
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Best Practices
|
|
81
|
+
|
|
82
|
+
1. **Always use absolute URLs** (include domain)
|
|
83
|
+
2. **Match current page** locale
|
|
84
|
+
3. **Consistent with hreflang**
|
|
85
|
+
4. **Use lowercase** URLs
|
|
86
|
+
|
|
87
|
+
### Locale Prefix Modes
|
|
88
|
+
|
|
89
|
+
**'as-needed' (Recommended for SEO):**
|
|
90
|
+
```
|
|
91
|
+
Default locale: https://example.com/about
|
|
92
|
+
Other locales: https://example.com/fr/about
|
|
93
|
+
https://example.com/es/about
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
✅ **Benefits:**
|
|
97
|
+
- Cleaner URLs for primary market
|
|
98
|
+
- Shorter URLs (better for sharing)
|
|
99
|
+
- Natural for users in primary market
|
|
100
|
+
|
|
101
|
+
**'always':**
|
|
102
|
+
```
|
|
103
|
+
All locales: https://example.com/en/about
|
|
104
|
+
https://example.com/fr/about
|
|
105
|
+
https://example.com/es/about
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
✅ **Benefits:**
|
|
109
|
+
- Explicit language in URL
|
|
110
|
+
- Consistent pattern
|
|
111
|
+
- Good for equal-weight markets
|
|
112
|
+
|
|
113
|
+
## URL Structure
|
|
114
|
+
|
|
115
|
+
### Best Practices
|
|
116
|
+
|
|
117
|
+
1. **Use subdirectories** (not subdomains)
|
|
118
|
+
- ✅ `example.com/fr/about`
|
|
119
|
+
- ❌ `fr.example.com/about`
|
|
120
|
+
|
|
121
|
+
2. **Keep URLs short**
|
|
122
|
+
- ✅ `example.com/fr/contact`
|
|
123
|
+
- ❌ `example.com/fr-FR/nous-contacter`
|
|
124
|
+
|
|
125
|
+
3. **Translate slugs** (optional but good UX)
|
|
126
|
+
- ✅ `example.com/fr/a-propos`
|
|
127
|
+
- ⚠️ `example.com/fr/about`
|
|
128
|
+
|
|
129
|
+
4. **Use lowercase**
|
|
130
|
+
- ✅ `example.com/fr/about`
|
|
131
|
+
- ❌ `example.com/FR/About`
|
|
132
|
+
|
|
133
|
+
## OpenGraph Tags
|
|
134
|
+
|
|
135
|
+
### What They Do
|
|
136
|
+
|
|
137
|
+
Control how pages appear when shared on social media.
|
|
138
|
+
|
|
139
|
+
```html
|
|
140
|
+
<!-- Generated by I18nMetaTags -->
|
|
141
|
+
<meta property="og:locale" content="fr" />
|
|
142
|
+
<meta property="og:locale:alternate" content="en" />
|
|
143
|
+
<meta property="og:locale:alternate" content="es" />
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Best Practices
|
|
147
|
+
|
|
148
|
+
Add these manually per page:
|
|
149
|
+
|
|
150
|
+
```tsx
|
|
151
|
+
export default function Page({ params }) {
|
|
152
|
+
return (
|
|
153
|
+
<>
|
|
154
|
+
<head>
|
|
155
|
+
<I18nMetaTags {...} />
|
|
156
|
+
{/* Add page-specific OG tags */}
|
|
157
|
+
<meta property="og:title" content={pageTitle} />
|
|
158
|
+
<meta property="og:description" content={pageDescription} />
|
|
159
|
+
<meta property="og:image" content={pageImage} />
|
|
160
|
+
<meta property="og:url" content={currentUrl} />
|
|
161
|
+
</head>
|
|
162
|
+
<body>{children}</body>
|
|
163
|
+
</>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Sitemap
|
|
169
|
+
|
|
170
|
+
### Generate Per-Locale Sitemaps
|
|
171
|
+
|
|
172
|
+
```xml
|
|
173
|
+
<!-- sitemap_index.xml -->
|
|
174
|
+
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
175
|
+
<sitemap>
|
|
176
|
+
<loc>https://example.com/sitemap_en.xml</loc>
|
|
177
|
+
</sitemap>
|
|
178
|
+
<sitemap>
|
|
179
|
+
<loc>https://example.com/sitemap_fr.xml</loc>
|
|
180
|
+
</sitemap>
|
|
181
|
+
<sitemap>
|
|
182
|
+
<loc>https://example.com/sitemap_es.xml</loc>
|
|
183
|
+
</sitemap>
|
|
184
|
+
</sitemapindex>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
```xml
|
|
188
|
+
<!-- sitemap_en.xml -->
|
|
189
|
+
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
|
190
|
+
xmlns:xhtml="http://www.w3.org/1999/xhtml">
|
|
191
|
+
<url>
|
|
192
|
+
<loc>https://example.com/about</loc>
|
|
193
|
+
<xhtml:link rel="alternate" hreflang="en" href="https://example.com/about" />
|
|
194
|
+
<xhtml:link rel="alternate" hreflang="fr" href="https://example.com/fr/about" />
|
|
195
|
+
<xhtml:link rel="alternate" hreflang="es" href="https://example.com/es/about" />
|
|
196
|
+
</url>
|
|
197
|
+
</urlset>
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Implementation
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
// src/app/sitemap.ts
|
|
204
|
+
import { i18nConfig } from './config/i18n';
|
|
205
|
+
|
|
206
|
+
export default async function sitemap() {
|
|
207
|
+
const pages = ['/', '/about', '/contact', '/pricing'];
|
|
208
|
+
|
|
209
|
+
return pages.flatMap((page) =>
|
|
210
|
+
i18nConfig.locales.map((locale) => ({
|
|
211
|
+
url: `https://example.com${locale === i18nConfig.defaultLocale ? '' : `/${locale}`}${page}`,
|
|
212
|
+
lastModified: new Date(),
|
|
213
|
+
alternates: {
|
|
214
|
+
languages: Object.fromEntries(
|
|
215
|
+
i18nConfig.locales.map((loc) => [
|
|
216
|
+
loc,
|
|
217
|
+
`https://example.com${loc === i18nConfig.defaultLocale ? '' : `/${loc}`}${page}`,
|
|
218
|
+
])
|
|
219
|
+
),
|
|
220
|
+
},
|
|
221
|
+
}))
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Content Guidelines
|
|
227
|
+
|
|
228
|
+
### Don't Auto-Translate
|
|
229
|
+
|
|
230
|
+
❌ **Bad:** Machine-translated content
|
|
231
|
+
- Lower quality
|
|
232
|
+
- Weird phrasing
|
|
233
|
+
- Hurts SEO
|
|
234
|
+
|
|
235
|
+
✅ **Good:** Human-translated or native content
|
|
236
|
+
- Natural language
|
|
237
|
+
- Better user experience
|
|
238
|
+
- Better rankings
|
|
239
|
+
|
|
240
|
+
### Duplicate Content
|
|
241
|
+
|
|
242
|
+
**Not an issue with proper hreflang:**
|
|
243
|
+
- Same content in different languages is OK
|
|
244
|
+
- hreflang tells Google they're related
|
|
245
|
+
- Each language ranks independently
|
|
246
|
+
|
|
247
|
+
**Avoid:**
|
|
248
|
+
- Same language, different regions without differentiation
|
|
249
|
+
- Mixing languages on same page
|
|
250
|
+
|
|
251
|
+
## Language Detection
|
|
252
|
+
|
|
253
|
+
### User Experience
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
// Good: Respect user choice
|
|
257
|
+
localeDetection: true // Detect but allow override
|
|
258
|
+
|
|
259
|
+
// Bad for SEO: Force based on IP
|
|
260
|
+
// Don't do this - let users choose
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Cookie Persistence
|
|
264
|
+
|
|
265
|
+
Framework automatically persists user choice in cookie:
|
|
266
|
+
- User selects language → cookie set
|
|
267
|
+
- Return visit → same language shown
|
|
268
|
+
- Share link → recipient sees URL language
|
|
269
|
+
|
|
270
|
+
## Google Search Console
|
|
271
|
+
|
|
272
|
+
### Setup
|
|
273
|
+
|
|
274
|
+
1. **Add all language versions** as properties
|
|
275
|
+
2. **Submit sitemaps** for each language
|
|
276
|
+
3. **Monitor** hreflang errors
|
|
277
|
+
4. **Check** index coverage
|
|
278
|
+
|
|
279
|
+
### Common Errors
|
|
280
|
+
|
|
281
|
+
**"No return tag"**
|
|
282
|
+
- Each hreflang must reference back to itself
|
|
283
|
+
- I18nMetaTags handles this automatically
|
|
284
|
+
|
|
285
|
+
**"Duplicate content"**
|
|
286
|
+
- Ensure proper canonicals
|
|
287
|
+
- Check hreflang points to correct URLs
|
|
288
|
+
|
|
289
|
+
## Testing
|
|
290
|
+
|
|
291
|
+
### Validate hreflang
|
|
292
|
+
|
|
293
|
+
Use Google's tools:
|
|
294
|
+
- [hreflang Tags Testing Tool](https://technicalseo.com/tools/hreflang/)
|
|
295
|
+
- [Google Search Console](https://search.google.com/search-console)
|
|
296
|
+
|
|
297
|
+
### Manual Check
|
|
298
|
+
|
|
299
|
+
1. **View source** on each language version
|
|
300
|
+
2. **Verify** all hreflang tags present
|
|
301
|
+
3. **Check** canonical points to correct URL
|
|
302
|
+
4. **Test** language switching
|
|
303
|
+
|
|
304
|
+
### Test Checklist
|
|
305
|
+
|
|
306
|
+
- [ ] All pages have hreflang tags
|
|
307
|
+
- [ ] x-default points to language selector or default
|
|
308
|
+
- [ ] Canonical URLs are absolute
|
|
309
|
+
- [ ] OpenGraph locale tags present
|
|
310
|
+
- [ ] Language selector works
|
|
311
|
+
- [ ] Cookie persists choice
|
|
312
|
+
- [ ] Sitemap includes all language versions
|
|
313
|
+
- [ ] No mixed-language content on same page
|
|
314
|
+
|
|
315
|
+
## Performance
|
|
316
|
+
|
|
317
|
+
### Static Generation
|
|
318
|
+
|
|
319
|
+
Pre-render all language versions:
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
export async function generateStaticParams() {
|
|
323
|
+
return i18nConfig.locales.map((locale) => ({ locale }));
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Edge Functions
|
|
328
|
+
|
|
329
|
+
Middleware runs on edge for fast redirects:
|
|
330
|
+
- Cookie check: instant
|
|
331
|
+
- Header parsing: < 1ms
|
|
332
|
+
- Redirect: fast CDN response
|
|
333
|
+
|
|
334
|
+
## Common Mistakes
|
|
335
|
+
|
|
336
|
+
### 1. Missing hreflang
|
|
337
|
+
|
|
338
|
+
❌ **Don't:**
|
|
339
|
+
```html
|
|
340
|
+
<!-- Only French page -->
|
|
341
|
+
<link rel="alternate" hreflang="fr" href="..." />
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
✅ **Do:**
|
|
345
|
+
```html
|
|
346
|
+
<!-- Include all versions -->
|
|
347
|
+
<link rel="alternate" hreflang="en" href="..." />
|
|
348
|
+
<link rel="alternate" hreflang="fr" href="..." />
|
|
349
|
+
<link rel="alternate" hreflang="es" href="..." />
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### 2. Wrong Canonical
|
|
353
|
+
|
|
354
|
+
❌ **Don't:**
|
|
355
|
+
```html
|
|
356
|
+
<!-- French page pointing to English -->
|
|
357
|
+
<link rel="canonical" href="https://example.com/about" />
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
✅ **Do:**
|
|
361
|
+
```html
|
|
362
|
+
<!-- Point to current language -->
|
|
363
|
+
<link rel="canonical" href="https://example.com/fr/about" />
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 3. Mixing Languages
|
|
367
|
+
|
|
368
|
+
❌ **Don't:**
|
|
369
|
+
```
|
|
370
|
+
Header: English
|
|
371
|
+
Content: French
|
|
372
|
+
Footer: English
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
✅ **Do:**
|
|
376
|
+
```
|
|
377
|
+
Entire page: French
|
|
378
|
+
Language selector: All languages
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Resources
|
|
382
|
+
|
|
383
|
+
- [Google Multi-Regional Guide](https://developers.google.com/search/docs/specialty/international)
|
|
384
|
+
- [hreflang Guide](https://ahrefs.com/blog/hreflang-tags/)
|
|
385
|
+
- [OpenGraph Protocol](https://ogp.me/)
|
|
386
|
+
- [Schema.org International](https://schema.org/docs/gs.html#international)
|
|
387
|
+
|
|
388
|
+
## See Also
|
|
389
|
+
|
|
390
|
+
- [Configuration](./CONFIGURATION.md)
|
|
391
|
+
- [Examples](./EXAMPLES.md)
|
|
392
|
+
- [Migration Guide](./MIGRATION.md)
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Static Generation Fix for i18n
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
During Next.js static generation, components are rendered before layout code runs, causing "i18n configuration not initialized" errors.
|
|
6
|
+
|
|
7
|
+
## Solution Options
|
|
8
|
+
|
|
9
|
+
### Option 1: Initialize in instrumentation.ts (Recommended)
|
|
10
|
+
|
|
11
|
+
Create `src/instrumentation.ts` which runs before static generation:
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
// src/instrumentation.ts
|
|
15
|
+
export async function register() {
|
|
16
|
+
if (process.env.NEXT_RUNTIME === 'nodejs') {
|
|
17
|
+
const { setI18nConfig } = await import('simple-site-framework/lib/i18n');
|
|
18
|
+
const { i18nConfig } = await import('./config/i18n');
|
|
19
|
+
|
|
20
|
+
setI18nConfig(i18nConfig);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Enable instrumentation in `next.config.js`:
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
/** @type {import('next').NextConfig} */
|
|
29
|
+
const nextConfig = {
|
|
30
|
+
experimental: {
|
|
31
|
+
instrumentationHook: true,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
module.exports = nextConfig;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Option 2: Pass config to components
|
|
39
|
+
|
|
40
|
+
Instead of global config, pass it to components that need it:
|
|
41
|
+
|
|
42
|
+
```typescript
|
|
43
|
+
// Not implemented yet - would require framework changes
|
|
44
|
+
<HeroSection config={i18nConfig} locale={locale} />
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Option 3: Environment variable fallback
|
|
48
|
+
|
|
49
|
+
Add to `.env.local`:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
NEXT_PUBLIC_DEFAULT_LOCALE=en
|
|
53
|
+
NEXT_PUBLIC_LOCALES=en,fr,es
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then update framework to use env vars as fallback when config not initialized.
|
|
57
|
+
|
|
58
|
+
## Testing
|
|
59
|
+
|
|
60
|
+
After implementing Option 1:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npm run build
|
|
64
|
+
# Should succeed with static generation
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Notes
|
|
68
|
+
|
|
69
|
+
- Global state in Next.js is tricky with static generation
|
|
70
|
+
- Each page generation might run in a separate worker process
|
|
71
|
+
- `instrumentation.ts` runs once per worker, ensuring config is available
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to the Simple Site Framework will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Accessibility documentation and testing utilities (#28)
|
|
12
|
+
- Migration guides and version upgrade documentation (#29)
|
|
13
|
+
|
|
14
|
+
## [0.1.0] - 2024-01-31
|
|
15
|
+
|
|
16
|
+
Initial release of the Simple Site Framework.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
#### Phase 1: Core Foundation
|
|
21
|
+
- ✨ Hero section with multiple variants (dark, light, split)
|
|
22
|
+
- ✨ Header with logo, navigation, and mobile menu
|
|
23
|
+
- ✨ Footer with links and social media
|
|
24
|
+
- ✨ Button component with multiple variants
|
|
25
|
+
- ✨ Toast notification system
|
|
26
|
+
- ✨ AnimatedSection with intersection observer
|
|
27
|
+
|
|
28
|
+
#### Phase 2: Content & Features
|
|
29
|
+
- ✨ FAQ accordion with search and categories
|
|
30
|
+
- ✨ Animated counter for statistics
|
|
31
|
+
- ✨ StatsSection for key metrics display
|
|
32
|
+
- ✨ Trust badges with customizable variants
|
|
33
|
+
- ✨ Pricing table with feature comparison
|
|
34
|
+
- ✨ Testimonial carousel with autoplay
|
|
35
|
+
|
|
36
|
+
#### Phase 3: Forms & Engagement
|
|
37
|
+
- ✨ Select component with grouped options
|
|
38
|
+
- ✨ Checkbox and CheckboxGroup components
|
|
39
|
+
- ✨ Radio and RadioGroup components
|
|
40
|
+
- ✨ File upload with drag & drop
|
|
41
|
+
- ✨ Multi-step form with progress tracking
|
|
42
|
+
- ✨ Countdown timer with multiple display formats
|
|
43
|
+
- ✨ Exit-intent modal for engagement
|
|
44
|
+
|
|
45
|
+
#### Phase 4: Content & SEO
|
|
46
|
+
- ✨ Tabs component with URL synchronization
|
|
47
|
+
- ✨ Timeline component (vertical & horizontal)
|
|
48
|
+
- ✨ Comparison table for features/plans
|
|
49
|
+
- ✨ Blog card with multiple variants
|
|
50
|
+
- ✨ SEO metadata utilities for Next.js
|
|
51
|
+
- ✨ Structured data (JSON-LD) components
|
|
52
|
+
|
|
53
|
+
#### Phase 5: Polish & Developer Experience
|
|
54
|
+
- ✨ LazySection for code-splitting
|
|
55
|
+
- ✨ CLI tools for project scaffolding
|
|
56
|
+
- ✨ StyleGuide component for documentation
|
|
57
|
+
- ✨ CodeBlock with syntax highlighting
|
|
58
|
+
- ✨ ComponentDemo for showcasing components
|
|
59
|
+
- ✨ Icon library integration with Lucide React
|
|
60
|
+
|
|
61
|
+
#### Enhancements
|
|
62
|
+
- ✨ Button: Loading/success states, icons, ripple effects, new variants (ghost, link, destructive), new sizes (xs, xl), disabled tooltips (#31)
|
|
63
|
+
- ✨ HeroSection: Entrance animations, scroll indicator, video lazy loading, sticky CTA, trust badges, parallax scrolling, split variant hover effects (#30)
|
|
64
|
+
- ✨ ContactSection: Working form with validation, spam protection, file uploads, click-to-action, office hours with status, multiple locations, Google Maps integration (#33)
|
|
65
|
+
- ✨ Icon: Type-safe wrapper for Lucide React with common presets (#32)
|
|
66
|
+
- ✨ FeaturesGrid: Locale support for bilingual labels
|
|
67
|
+
|
|
68
|
+
### Configuration
|
|
69
|
+
- 🎨 Comprehensive theme configuration
|
|
70
|
+
- 🌍 Bilingual support (English/French)
|
|
71
|
+
- 📝 Content schema with TypeScript validation
|
|
72
|
+
- 🔧 CLI commands for scaffolding and components
|
|
73
|
+
|
|
74
|
+
### Documentation
|
|
75
|
+
- 📖 Accessibility guides and WCAG compliance
|
|
76
|
+
- 📖 Migration guides and changelog
|
|
77
|
+
- 📖 Component API documentation
|
|
78
|
+
- 📖 Keyboard navigation patterns
|
|
79
|
+
- 📖 Screen reader testing guides
|
|
80
|
+
|
|
81
|
+
### Dependencies
|
|
82
|
+
- ⚛️ React 18/19
|
|
83
|
+
- ⚡ Next.js 14/15/16
|
|
84
|
+
- 🎨 Tailwind CSS 3/4
|
|
85
|
+
- 🎭 Framer Motion 11+
|
|
86
|
+
- 📋 React Hook Form 7+
|
|
87
|
+
- ✅ Zod 3+
|
|
88
|
+
- 🎯 Radix UI primitives
|
|
89
|
+
- 🖼️ Lucide React icons
|
|
90
|
+
|
|
91
|
+
### Developer Tools
|
|
92
|
+
- 🛠️ TypeScript support with full type definitions
|
|
93
|
+
- 🚀 Tree-shaking for optimal bundle size
|
|
94
|
+
- 📦 Modular architecture
|
|
95
|
+
- 🧪 Testing utilities
|
|
96
|
+
- 🎨 Customizable theming system
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## Version Legend
|
|
101
|
+
|
|
102
|
+
- 🔥 **Breaking Change** - Requires code changes
|
|
103
|
+
- ✨ **New Feature** - New functionality added
|
|
104
|
+
- 🐛 **Bug Fix** - Fixed incorrect behavior
|
|
105
|
+
- ⚡ **Performance** - Improved performance
|
|
106
|
+
- 📦 **Dependencies** - Dependency updates
|
|
107
|
+
- ⚠️ **Deprecated** - Feature deprecated, will be removed
|
|
108
|
+
- 🔒 **Security** - Security vulnerability fixed
|
|
109
|
+
- 📖 **Documentation** - Documentation changes only
|
|
110
|
+
- 🎨 **Style** - Code style/formatting changes
|
|
111
|
+
- ♿ **Accessibility** - Accessibility improvements
|
|
112
|
+
|
|
113
|
+
## Support Timeline
|
|
114
|
+
|
|
115
|
+
| Version | Release Date | End of Support | Status |
|
|
116
|
+
|---------|--------------|----------------|--------|
|
|
117
|
+
| 0.1.x | 2024-01-31 | TBD | Active |
|
|
118
|
+
|
|
119
|
+
## Breaking Changes History
|
|
120
|
+
|
|
121
|
+
### v0.1.0 (Initial Release)
|
|
122
|
+
- No breaking changes - initial release
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## Upcoming Features
|
|
127
|
+
|
|
128
|
+
See our [roadmap](https://github.com/zoyth/simple-site-framework/issues/35) for planned features.
|
|
129
|
+
|
|
130
|
+
## Reporting Issues
|
|
131
|
+
|
|
132
|
+
Found a bug or have a feature request? [Open an issue](https://github.com/zoyth/simple-site-framework/issues) on GitHub.
|
|
133
|
+
|
|
134
|
+
## Contributing
|
|
135
|
+
|
|
136
|
+
See our [contributing guidelines](https://github.com/zoyth/simple-site-framework/blob/main/CONTRIBUTING.md) for how to contribute.
|