Content Customization Overview

PreLaunch allows you to easily customize all the text content in your application. This document will guide you through the different ways to modify content, from simple text changes to creating custom content components.

Translation Files

The primary way to customize text content is through the translation files located in the locales/ directory:

locales/
├── en/              # English translations
│   ├── common.json  # Shared translations
│   ├── home.json    # Home page translations
│   └── ...          # Other page/component translations
└── zh/              # Chinese translations (if you use multilanguage)
    ├── common.json
    ├── home.json
    └── ...

Customizing Text Content

To modify text content, edit the appropriate JSON file in the locales/en/ directory:

// locales/en/home.json
{
  "hero": {
    "title": "Validate Your Product Idea",
    "subtitle": "Build a professional landing page, collect user feedback, and validate your product before launch.",
    "cta": "Get Started"
  },
  "features": {
    "title": "Key Features",
    "list": [
      {
        "title": "User Feedback",
        "description": "Collect valuable feedback from potential users."
      },
      // More features...
    ]
  }
}

Page Content

Editing Page Content

Each page in your application has its own content. To modify page content, edit the corresponding page component:

// app/page.tsx
import { useTranslations } from 'next-intl';

export default function HomePage() {
  const t = useTranslations('home');
  
  return (
    <div className="home-page">
      <section className="hero">
        <h1>{t('hero.title')}</h1>
        <p>{t('hero.subtitle')}</p>
        <Button>{t('hero.cta')}</Button>
      </section>
      
      {/* More page content... */}
    </div>
  );
}

Creating Custom Pages

You can create new pages by adding files to the app/ directory:

// app/custom-page/page.tsx
import { useTranslations } from 'next-intl';

export default function CustomPage() {
  const t = useTranslations('custom');
  
  return (
    <div className="custom-page">
      <h1>{t('title')}</h1>
      <div className="content">
        {/* Your custom content here */}
      </div>
    </div>
  );
}

Don’t forget to add corresponding translations in locales/en/custom.json.

Components Content

Reusable Content Components

For content that appears in multiple places, you can create reusable components:

// components/content/FeatureCard.tsx
import { useTranslations } from 'next-intl';

interface FeatureCardProps {
  featureKey: string;
  icon?: React.ReactNode;
}

export function FeatureCard({ featureKey, icon }: FeatureCardProps) {
  const t = useTranslations('features');
  
  return (
    <div className="feature-card">
      {icon && <div className="icon">{icon}</div>}
      <h3>{t(`${featureKey}.title`)}</h3>
      <p>{t(`${featureKey}.description`)}</p>
    </div>
  );
}

Then use it in your pages:

<FeatureCard featureKey="waitlist" icon={<ListIcon />} />

Dynamic Content

Content from API

For dynamic content that comes from an API, you can fetch data in your page components:

// app/blog/page.tsx
import { fetchBlogPosts } from '@/libs/api';

export default async function BlogPage() {
  // Fetch blog posts
  const posts = await fetchBlogPosts();
  
  return (
    <div className="blog-page">
      <h1>Blog</h1>
      <div className="posts-grid">
        {posts.map((post) => (
          <BlogPostCard key={post.id} post={post} />
        ))}
      </div>
    </div>
  );
}

Content from CMS

If you’re using a CMS like Contentful, Sanity, or Strapi, you can integrate it to manage your content:

// libs/cms.ts
import { createClient } from 'contentful';

const client = createClient({
  space: process.env.CONTENTFUL_SPACE_ID!,
  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
});

export async function getHomepageContent() {
  const entry = await client.getEntry('homepage');
  return entry.fields;
}

// Use in your component
// app/page.tsx
import { getHomepageContent } from '@/libs/cms';

export default async function HomePage() {
  const content = await getHomepageContent();
  
  return (
    <div className="home-page">
      <h1>{content.title}</h1>
      <p>{content.subtitle}</p>
      {/* More content... */}
    </div>
  );
}

Markdown Content

PreLaunch supports Markdown content rendering for rich text content:

// components/content/MarkdownContent.tsx
import ReactMarkdown from 'react-markdown';

interface MarkdownContentProps {
  content: string;
}

export function MarkdownContent({ content }: MarkdownContentProps) {
  return (
    <div className="markdown-content">
      <ReactMarkdown>{content}</ReactMarkdown>
    </div>
  );
}

You can then use this component to display Markdown content:

<MarkdownContent content={`
# Welcome to PreLaunch

This is a **rich text** content block with:
- Bullet points
- _Italic text_
- And more formatting options
`} />

SEO Content

Page Metadata

To customize SEO metadata for your pages, modify the metadata export in your page files:

// app/about/page.tsx
import type { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'About Us | PreLaunch',
  description: 'Learn more about PreLaunch and our mission to help validate product ideas.',
  openGraph: {
    title: 'About PreLaunch',
    description: 'Learn more about PreLaunch and our mission to help validate product ideas.',
    images: ['/images/about-og.jpg'],
  },
};

export default function AboutPage() {
  // Your page content...
}

Default Metadata

Default metadata is configured in the app/layout.tsx file and is derived from the config.ts file:

// app/layout.tsx
import { Metadata } from 'next';
import config from '@/config';

export const metadata: Metadata = {
  title: {
    default: config.appName,
    template: `%s | ${config.appName}`,
  },
  description: config.appDescription,
  // More metadata...
};

Privacy Policy and Terms of Service

For legal pages like Privacy Policy and Terms of Service, you can create dedicated page components:

// app/privacy-policy/page.tsx
import { Metadata } from 'next';

export const metadata: Metadata = {
  title: 'Privacy Policy | PreLaunch',
  description: 'Our privacy policy and data practices.',
};

export default function PrivacyPolicyPage() {
  return (
    <div className="privacy-policy-page">
      <h1>Privacy Policy</h1>
      <div className="content">
        {/* Your privacy policy content here */}
        <h2>1. Information We Collect</h2>
        <p>...</p>
        
        <h2>2. How We Use Your Information</h2>
        <p>...</p>
        
        {/* More sections... */}
      </div>
    </div>
  );
}

Common Questions