Locales & Site Config
Configure application content and metadata in Plainform
Two centralized files manage all application content and metadata, separating copy from code for easier maintenance and updates.
Why This Approach?
Centralized Content Management
- All text in one place - no hunting through components
- Update copy without touching code
- Easy to review and maintain consistency
AI-Friendly Structure
- AI can read your product.md and generate all copy automatically
- Consistent tone and messaging across the entire app
- Iterate quickly with simple prompts
Developer-Friendly
- Type-safe access to config values
- Optional chaining prevents runtime errors
- Hot reload for instant preview of changes
Translation-Ready
- Add new languages by creating additional locale files
- Same structure across all languages
- Easy to manage with translation services
Files
locales/en.json
All user-facing text in one JSON file:
{
"navigation": {
"primaryCta": { "text": "Get Started", "href": "/" }
},
"homePage": {
"heroSection": {
"title": "Headline goes here\\nwith a strong value proposition",
"description": "Describe what your product does..."
}
}
}Contains: Navigation, hero sections, features, pricing, FAQ, forms, footer
Default state: Instructional placeholder text to guide you
config/siteConfig.ts
Site-wide settings and metadata:
export const siteConfig = {
siteName: 'MyApp',
description: 'Describe what your product does...',
supportEmail: 'support@yourdomain.com',
sendEmailFrom: 'MyApp <noreply@yourdomain.com>',
analytics: {
googleAnalyticsId: 'G-XXXXXXXXXX', // Your GA4 Measurement ID
},
metadata: {
docs: {
title: 'Docs',
description: 'Your docs metadata...',
url: '/docs',
},
},
};Contains: Site name, emails, analytics configuration, page metadata
Default state: Placeholder values like "MyApp", "support@yourdomain.com"
Analytics: Plainform includes Google Analytics 4 and PostHog. Learn how to configure analytics →
Usage
In Components
import locale from '@/locales/en.json';
export function Hero() {
const hero = locale?.homePage?.heroSection;
return <h1>{hero?.title}</h1>;
}import { siteConfig } from '@/config/siteConfig';
export function Footer() {
return <a href={`mailto:${siteConfig.supportEmail}`}>Contact</a>;
}Always use optional chaining (?.) to prevent runtime errors.
Customization
Fastest way to customize: Update .agent/workflows/product.md with your product details, then let AI generate all your copy automatically. Learn more about product.md →
Option 1: AI Generation (Recommended)
The AI generation approach saves hours of copywriting work and ensures consistency across your entire application. Instead of manually updating hundreds of text fields, you describe your product once and let AI handle the rest.
Benefits:
- Generate professional copy in seconds
- Maintain consistent tone and messaging
- Easy to iterate and refine
- No copywriting skills required
Update product.md
Describe your product in .agent/workflows/product.md:
Update .agent/workflows/product.md to describe my product:
Product Name: TaskFlow
Description: A project management SaaS for remote teams
Key Features:
- Real-time collaboration with team workspaces
- Kanban boards and sprint planning
- Time tracking and reporting
- Slack and GitHub integrations
Target Audience: Remote software development teams (5-50 people)
Pricing Model: Tiered subscription ($10/user/month for Pro, $20/user/month for Enterprise)Generate all copy
Ask AI to generate your application copy:
Read .agent/workflows/product.md and update locales/en.json with professional, compelling copy that matches my product. Keep the JSON structure but replace all placeholder text. Also update config/siteConfig.ts with appropriate metadata including siteName, description, and supportEmail.Refine specific sections
Generate or refine specific sections as needed:
Based on my product.md, update only the homePage.heroSection in locales/en.json with a compelling headline and description.Make the pricing section copy more urgent and action-oriented.Simplify the feature descriptions to be more concise.Option 2: Manual Updates
For smaller changes or when you prefer direct control, you can manually edit the files.
Update locales
- Open
locales/en.json - Find the section (e.g.,
homePage.heroSection) - Replace placeholder text with your copy
- Save (hot reloads automatically)
Update site config
- Open
config/siteConfig.ts - Update properties (siteName, emails, metadata)
- Save and restart dev server
When to use manual updates:
- Quick copy tweaks
- A/B testing different headlines
- Fixing typos
- Updating contact information
Internationalization
Add multiple languages by creating additional locale files:
locales/
├── en.json # English
├── fr.json # French
└── es.json # SpanishCreate a locale loader utility:
import en from '@/locales/en.json';
import fr from '@/locales/fr.json';
const locales = { en, fr };
export function getLocale(lang = 'en') {
return locales[lang] || locales.en;
}Use in components:
import { getLocale } from '@/lib/getLocale';
export function Hero({ lang = 'en' }) {
const locale = getLocale(lang);
return <h1>{locale?.homePage?.heroSection?.title}</h1>;
}For full i18n support with routing and automatic language detection, consider using next-intl or next-i18next.
Next Steps
- AI Agents - Use AI to generate copy from product.md
- Environment Variables - Configure API keys
- SEO Overview - Configure metadata
How is this guide ?
Last updated on