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:

locales/en.json
{
  "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:

config/siteConfig.ts
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

components/Hero.tsx
import locale from '@/locales/en.json';

export function Hero() {
  const hero = locale?.homePage?.heroSection;
  return <h1>{hero?.title}</h1>;
}
components/Footer.tsx
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 →

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:

Example prompt
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:

Example prompt
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:

Update specific section
Based on my product.md, update only the homePage.heroSection in locales/en.json with a compelling headline and description.
Adjust tone
Make the pricing section copy more urgent and action-oriented.
Simplify copy
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

  1. Open locales/en.json
  2. Find the section (e.g., homePage.heroSection)
  3. Replace placeholder text with your copy
  4. Save (hot reloads automatically)

Update site config

  1. Open config/siteConfig.ts
  2. Update properties (siteName, emails, metadata)
  3. 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    # Spanish

Create a locale loader utility:

lib/getLocale.ts
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:

components/Hero.tsx
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

How is this guide ?

Last updated on

On this page