> ## Documentation Index
> Fetch the complete documentation index at: https://buttercms.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Fetching localized content via API

> Code examples for fetching content for a specific locale using the ButterCMS API in JavaScript, Python, PHP, Ruby, and more.

<Info>
  Make sure locales are configured first. See [Setting Up Locales](../../create-content/localization/publishing-localized-content).
</Info>

# Fetching localized content via API

After enabling Localization, you will need to update all API calls to include the locale parameter. The `locale` parameter tells the ButterCMS API which localized version of your content to return.

## API endpoint patterns

### Single Page

```
https://api.buttercms.com/v2/pages/<page_type_slug>/<page_slug>/?locale=en&auth_token=your_api_token
```

### Multiple Pages

```
https://api.buttercms.com/v2/pages/*/?locale=en&page=1&page_size=10&auth_token=your_api_token
```

### Page Types

```
https://api.buttercms.com/v2/pages/<page_type>/?locale=en&page=1&page_size=10&auth_token=your_api_token
```

### Collections

```
https://api.buttercms.com/v2/content/<collection>/?locale=en&page=1&page_size=10&auth_token=your_api_token
```

### Blog Posts

```
https://api.buttercms.com/v2/posts/?locale=en&auth_token=your_api_token
```

### Single Blog Post

```
https://api.buttercms.com/v2/posts/<post_slug>/?locale=en&auth_token=your_api_token
```

### Blog Post Search

```
https://api.buttercms.com/v2/posts/search/?locale=en&query=search_term&auth_token=your_api_token
```

## JavaScript / Node.js examples

### Basic setup

```javascript theme={null}
import ButterCMS from "buttercms";

const butterCMSClient = ButterCMS("your_api_token");
```

### Fetching a single Page

```javascript theme={null}
// Fetch page in a specific locale
const { data } = await butterCMSClient.page.retrieve(
  "landing_page",      // page type
  "home",              // page slug
  {
    locale: "es",      // locale parameter
    preview: 1         // optional: include draft content
  }
);

const { fields } = data.data;
console.log(fields.headline); // Spanish headline
```

### Fetching multiple Pages

```javascript theme={null}
// Fetch all pages of a type in Spanish
const response = await butterCMSClient.page.list("blog_posts", {
  locale: "es",
  page: 1,
  page_size: 10,
  order: "-published"
});

const pages = response.data.data;
pages.forEach(page => {
  console.log(page.fields.title);
});
```

### Fetching Collections

```javascript theme={null}
// Fetch collection items in French
const { data } = await butterCMSClient.content.retrieve(
  ["team_members", "testimonials"],
  {
    locale: "fr",
    page: 1,
    page_size: 20
  }
);

const teamMembers = data.data.team_members;
const testimonials = data.data.testimonials;
```

### Dynamic locale selection

```javascript theme={null}
// Function to fetch content based on user's locale
async function getLocalizedPage(pageType, slug, userLocale) {
  const supportedLocales = ['en', 'es', 'fr', 'de'];
  const locale = supportedLocales.includes(userLocale)
    ? userLocale
    : 'en'; // fallback

  try {
    const response = await butterCMSClient.page.retrieve(pageType, slug, {
      locale
    });
    return response.data.data;
  } catch (error) {
    // Fallback to default locale if content not found
    if (error.response?.status === 404) {
      const fallback = await butterCMSClient.page.retrieve(pageType, slug, {
        locale: 'en'
      });
      return { ...fallback.data.data, _fallback: true };
    }
    throw error;
  }
}
```

## Python examples

### Basic setup

```python theme={null}
from butter_cms import ButterCMS

client = ButterCMS('your_api_token')
```

### Fetching a single Page

```python theme={null}
# Fetch page in Spanish
response = client.pages.get(
    'landing_page',
    'home',
    params={'locale': 'es'}
)

page = response['data']
print(page['fields']['headline'])
```

### Fetching multiple Pages

```python theme={null}
# Fetch all blog posts in German
response = client.pages.all(
    'blog_posts',
    params={
        'locale': 'de',
        'page': 1,
        'page_size': 10
    }
)

for page in response['data']:
    print(page['fields']['title'])
```

### Fetching Collections

```python theme={null}
# Fetch collections in French
response = client.content_fields.get(
    ['team_members', 'faqs'],
    params={'locale': 'fr'}
)

team_members = response['data']['team_members']
faqs = response['data']['faqs']
```

## PHP / Laravel examples

### Controller setup

```php theme={null}
<?php

namespace App\Http\Controllers;

use ButterCMS\ButterCMS;

class LandingPageController extends Controller
{
    private $client;

    public function __construct() {
        $this->client = new ButterCMS('your_api_token');
    }

    public function showPage(string $type, string $pageSlug, string $locale = 'en')
    {
        // Fetch page with locale parameter
        $params = [
            'locale' => $locale,
            'preview' => 1
        ];

        $page = $this->client->fetchPage($type, $pageSlug, $params);

        return view('page', [
            'fields' => $page->getFields(),
            'locale' => $locale
        ]);
    }
}
```

### Fetching Collections

```php theme={null}
// Fetch navigation items in Spanish
$menuParams = [
    'page' => '1',
    'page_size' => '10',
    'locale' => 'es-es',
    'test' => 1
];

$menuCollection = $this->client->fetchContentFields(
    ['navigation_items'],
    $menuParams
);

$menuItems = $menuCollection['navigation_items'];
```

## Ruby / Rails examples

### Basic setup

```ruby theme={null}
require 'buttercms-ruby'

ButterCMS::api_token = 'your_api_token'
```

### Fetching a single Page

```ruby theme={null}
# Fetch page in Japanese
page = ButterCMS::Page.find('landing_page', 'home', {
  locale: 'ja'
})

puts page['data']['fields']['headline']
```

### Fetching Collections

```ruby theme={null}
# Fetch collection in Portuguese
content = ButterCMS::Content.fetch(['team_members'], {
  locale: 'pt-br',
  page: 1,
  page_size: 10
})

team_members = content['data']['team_members']
```

## cURL examples

### Fetch single Page

```bash theme={null}
curl -X GET "https://api.buttercms.com/v2/pages/landing_page/home/?locale=es&auth_token=YOUR_API_TOKEN"
```

### Fetch multiple Pages

```bash theme={null}
curl -X GET "https://api.buttercms.com/v2/pages/blog_posts/?locale=de&page=1&page_size=10&auth_token=YOUR_API_TOKEN"
```

### Fetch Collections

```bash theme={null}
curl -X GET "https://api.buttercms.com/v2/content/?keys=team_members,faqs&locale=fr&test=1&auth_token=YOUR_API_TOKEN"
```

## Next.js App Router example

### Dynamic locale routing

```typescript theme={null}
// app/[locale]/page/[slug]/page.tsx
import ButterCMS from 'buttercms';

const butter = ButterCMS(process.env.BUTTER_CMS_API_KEY);

interface PageProps {
  params: {
    locale: string;
    slug: string;
  };
}

export default async function Page({ params }: PageProps) {
  const { locale, slug } = params;

  const response = await butter.page.retrieve('*', slug, {
    locale,
    preview: process.env.NODE_ENV === 'development' ? 1 : 0,
  });

  const { fields } = response.data.data;

  return (
    <main>
      <h1>{fields.headline}</h1>
      <div dangerouslySetInnerHTML={{ __html: fields.body }} />
    </main>
  );
}

// Generate static paths for all locales
export async function generateStaticParams() {
  const locales = ['en', 'es', 'fr', 'de'];

  // Fetch all page slugs
  const response = await butter.page.list('*', { page_size: 100 });
  const pages = response.data.data;

  // Generate params for each locale + page combination
  return locales.flatMap(locale =>
    pages.map(page => ({
      locale,
      slug: page.slug,
    }))
  );
}
```

## Handling locale in frontend frameworks

### Next.js internationalized routing

Configure `next.config.js` for locale support:

```javascript theme={null}
// next.config.js
module.exports = {
  i18n: {
    locales: ["en", "fr", "es", "de"],
    defaultLocale: "en",
  },
};
```

Then use the locale in your data fetching:

```javascript theme={null}
export const getStaticProps = async ({ locale }) => {
  const { data } = await butterCMSClient.page.retrieve(
    "landing_page",
    "home",
    { locale }
  );

  return {
    props: {
      fields: data.data.fields,
    },
  };
};
```

## Previewing localized content

Use the `preview` parameter to fetch unpublished (draft) content in a specific locale.

### Preview mode

To preview unpublished localized content, include the `preview` parameter:

```bash theme={null}
https://api.buttercms.com/v2/pages/<page_type>/<page_slug>/?locale=es&preview=1&auth_token=your_api_token
```

### Setting up preview URLs

Configure locale-specific preview URLs in your frontend:

```javascript theme={null}
// Preview URL generator
function getPreviewUrl(pageSlug, locale) {
  const baseUrl = process.env.PREVIEW_BASE_URL;
  return `${baseUrl}/${locale}/${pageSlug}?preview=true`;
}

// Example: https://preview.example.com/es/homepage?preview=true
```

## Handling missing locale content

When content doesn't exist in a requested locale, you have several options:

### Option 1: fallback to default locale

```javascript theme={null}
async function getPageWithFallback(pageType, slug, preferredLocale, defaultLocale = 'en') {
  const butter = Butter('your-api-token');

  try {
    // Try preferred locale first
    return await butter.page.retrieve(pageType, slug, { locale: preferredLocale });
  } catch (error) {
    if (error.response?.status === 404) {
      // Fallback to default locale
      const fallbackPage = await butter.page.retrieve(pageType, slug, { locale: defaultLocale });
      return { ...fallbackPage, _fallbackUsed: true };
    }
    throw error;
  }
}
```

### Option 2: show locale not available message

```javascript theme={null}
function LocalizedContent({ locale }) {
  const [content, setContent] = useState(null);
  const [notAvailable, setNotAvailable] = useState(false);

  useEffect(() => {
    fetchContent(locale)
      .then(setContent)
      .catch(() => setNotAvailable(true));
  }, [locale]);

  if (notAvailable) {
    return <div>This content is not yet available in {locale}.</div>;
  }

  return content ? <PageContent data={content} /> : <Loading />;
}
```

### Option 3: redirect to available locale

```javascript theme={null}
// Next.js middleware example
export function middleware(request) {
  const locale = request.nextUrl.locale;
  const availableLocales = ['en', 'es', 'fr'];

  if (!availableLocales.includes(locale)) {
    return NextResponse.redirect(new URL('/en' + request.nextUrl.pathname, request.url));
  }
}
```

For unpublishing and deleting localized content, see [Publishing Localized Content](../../create-content/localization/publishing-localized-content).

## Best practices

### Error handling

Always handle cases where content might not exist in a requested locale:

```javascript theme={null}
async function fetchWithFallback(pageType, slug, locale, defaultLocale = 'en') {
  try {
    return await butter.page.retrieve(pageType, slug, { locale });
  } catch (error) {
    if (error.response?.status === 404 && locale !== defaultLocale) {
      console.warn(`Content not found for locale ${locale}, falling back to ${defaultLocale}`);
      return await butter.page.retrieve(pageType, slug, { locale: defaultLocale });
    }
    throw error;
  }
}
```

### Caching considerations

* Cache responses per locale
* Invalidate cache when content is updated
* Consider using ISR (Incremental Static Regeneration) in Next.js

```javascript theme={null}
export const revalidate = 60; // Revalidate every 60 seconds
```

### Performance tips

* Use the `fields` parameter to request only needed fields
* Implement pagination for large collections
* Pre-fetch content for common locale switches
