---
title: Translations and Snippets in Shopware | Shopware Community Hub
description: >-
  Learn about the two different systems for handling multilingual content in
  Shopware: translations for dynamic content and snippets for static UI
  elements.
canonical_url: 'https://hub.shopware.com/learn/unit/translations-and-snippets'
---

# Translations and Snippets in Shopware

<LearningObjectives>

- Understand the key differences between translations and snippets in Shopware.
- Learn how to manage translations for dynamic content.
- Learn how to manage snippets for static UI elements.
- Master the process of implementing both in your custom extensions.
  
</LearningObjectives>

# Translations and Snippets in Shopware

Shopware provides two distinct systems for handling multilingual content: translations and snippets.

Understanding the difference between these systems and knowing when to use each is crucial for creating a properly internationalized e-commerce platform.

## Translations vs Snippets

### Translations

Translations are used for dynamic content that changes frequently and is specific to individual entities. They are stored in the database and can be managed through the Admin API.

**Use cases for translations:**

- Product descriptions and names
- Category names and descriptions
- Manufacturer information
- Custom entity content
- Any content that varies between different instances of the same entity type

**Example in Twig templates (Storefront):**

```twig
{{ product.translated.name }}
{{ category.translated.description }}
```

### Snippets

Snippets are used for static text elements that remain consistent across the storefront. They are managed through the snippet system in the admin panel and are typically used for UI elements.

**Use cases for snippets:**

- Button labels
- Form field labels
- Navigation items
- System messages
- Error messages
- Any text that should be consistent across the entire storefront

**Example in Vue templates (Administration):**

```js
{{ $t('general.home') }}
{{ $t('checkout.cartTitle') }}
```

### Administration Snippets vs. Storefront Snippets

Shopware uses two separate snippet systems, depending on **where the text is rendered and resolved**.

| Area           | Snippet System                                                                       | Format | Resolved via                                                                                                                                                                                                                 | Editable via the UI in the Administration   |
|----------------|--------------------------------------------------------------------------------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------|
| Administration | Vue i18n (client-side)                                                               | JSON   | `$t()` across the administration (Twig/HTML, JS, Vue)                                                                                                                                                                        | No                                          |
| Storefront     | [Symfony-Translator](https://symfony.com/doc/current/translation.html) (server-side) | JSON   | PHP: [Symfony Translation component](https://symfony.com/doc/current/translation.html).Twig: uses the [trans](https://symfony.com/doc/current/reference/twig_reference.html#trans) filter provided via `symfony/twig-bridge` | Yes (Settings -> Localisation -> Snippets)  |

## Storage of Translations in Shopware

Translations in Shopware are stored in the database in dedicated translation tables. Each translatable entity has its own corresponding translation table that follows a naming convention:

| Entity        | Translation Table                  |
|---------------|------------------------------------|
| Product       | `product_translation`              |
| Category      | `category_translation`             |
| Customer      | `customer_translation`             |
| Order         | `order_translation`                |
| Media         | `media_translation`                |
| CmsPage       | `cms_page_translation`             |
| Manufacturer  | `product_manufacturer_translation` |
| Custom Entity | `[entity_name]_translation`        |

Each translation table typically contains:

- A foreign key to the main entity
- A language ID reference
- Translatable fields specific to that entity

For example, the `product_translation` table contains fields like:

- `product_id` (foreign key to the product table)
- `language_id` (reference to the language)
- `name` (translated product name)
- `description` (translated product description)
- `meta_title`, `meta_description`, etc.

When you access a translated property using `entity.translated.property`, Shopware automatically retrieves the appropriate translation based on the current context's language ID.

Snippets, on the other hand, are stored in the `snippet` and `snippet_set` tables, which manage the static UI text elements across different languages.

## Managing Translations

### Through the Admin API

Translations can be managed programmatically using the Admin API. Here's an example of how to update a product translation:

```php
$productRepository->update([
    [
        'id' => $productId,
        'translations' => [
            'de-DE' => [
                'name' => 'Produktname',
                'description' => 'Produktbeschreibung'
            ],
            'en-GB' => [
                'name' => 'Product name',
                'description' => 'Product description'
            ]
        ]
    ]
], $context);
```

### Through the Admin Interface

1. Navigate to the entity you want to translate (e.g., Products)
2. Select the entity and switch to the desired language
3. Enter the translated content
4. Save the changes

## Managing Snippets

### Through the Admin Interface

1. Navigate to Settings -> Snippets
2. Select the appropriate snippet set
3. Search for or browse to the snippet you want to modify
4. Edit the snippet content
5. Save the changes

### Creating Custom Snippets

For custom extensions, you can define your own snippets in the `Resources/snippet` directory:

```json
// Resources/snippet/de-DE/my_plugin.de-DE.json
{
  "my_plugin": {
    "custom": {
      "button": "Mein Button",
      "message": "Meine Nachricht"
    }
  }
}
```

## Best Practices

1. **Use translations for:**
   - Content that varies between entities
   - Dynamic content that changes frequently
   - Entity-specific information

2. **Use snippets for:**
   - UI elements and labels
   - System messages
   - Static text that should be consistent
   - Error messages and notifications

3. **General guidelines:**
   - Always provide fallback translations
   - Keep translations and snippets organized
   - Use meaningful keys for snippets
   - Consider cultural differences in translations
   - Test all languages in your storefront

## Implementation in Custom Extensions

When creating custom extensions, you'll often need to implement both translations and snippets:

```php
// Example of a custom entity with translations
class CustomEntityDefinition extends EntityDefinition
{
    public function getEntityClass(): string
    {
        return CustomEntity::class;
    }

    protected function defineFields(): FieldCollection
    {
        return new FieldCollection([
            (new TranslatedField('name'))->addFlags(new Required()),
            (new TranslatedField('description')),
            // ... other fields
        ]);
    }
}
```

For snippets, create the appropriate snippet files in your plugin's Resources directory:

```txt
Resources/
  └── snippet/
      ├── de-DE/
      │   └── my_plugin.de-DE.json
      └── en-GB/
          └── my_plugin.en-GB.json
```

Understanding and properly implementing both translations and snippets will help you create a fully internationalized e-commerce solution that provides a seamless experience for customers in different languages.

### Hierarchy

### Snippet Loading Hierarchy

It's important to understand how Shopware loads snippets:

1. **Database First**: Shopware first checks the database (`snippet` table) for snippets.
   - Snippets are only stored in the database if they were modified through the Administration UI or Admin API.
   - This allows for runtime customization without changing code files.

2. **File Fallback**: If a snippet is not found in the database, Shopware falls back to the JSON files.
   - The original snippet definitions in your plugin's JSON files serve as the default values.
   - These files are the source of truth for snippets that haven't been customized.

This hierarchy provides a flexible system where:

- Developers can provide default translations in code
- Shop administrators can override specific snippets as needed
- Custom snippets remain intact during plugin updates

When developing, remember that newly added snippets in your JSON files will be immediately available, but they won't appear in the database until someone edits them through the Administration or Admin API.

## Example: Using Snippets in PHP

As you may already know how to use translations in Twig templates, you can also use snippets in your PHP code.

Imagine, for example, your snippet looks like this in English:

```json
{
  "myPlugin": {
    "lineItem": {
      "title": {
        "customerIsB2C": "B2C Customer",
        "customerIsB2B": "B2B Customer"
      }
    }
  }
}
```

And in German:

```json
{
  "myPlugin": {
    "lineItem": {
      "title": {
        "customerIsB2C": "B2C Kunde",
        "customerIsB2B": "B2B Kunde"
      }
    }
  }
}
```

Let's see how to use these snippets in PHP.

### Example Without Parameters

To use snippets in PHP code, you rely on Symfony's `TranslatorInterface`, which is injected into your service.

```php
<?php declare(strict_types=1);

namespace MyPlugin\Service;

use Symfony\Contracts\Translation\TranslatorInterface;

class MyService
{
    public function __construct(
        private readonly TranslatorInterface $translator
    ) {
    }
    
    public function getB2CLabel(): string
    {
        return $this->translator->trans('myPlugin.lineItem.customerIsB2C');
    }
    
    public function getB2BLabel(): string
    {
        return $this->translator->trans('myPlugin.lineItem.customerIsB2B');
    }
}
```

You use the `trans` method to retrieve the translated string for a given key. The returned value is already resolved for the current language context.

<Callout title="Storefront Controller" type="info">

When you implement a controller that extends `StorefrontController`, you do not need to inject the `TranslatorInterface` manually. The `StorefrontController` already provides it, so you can directly call `$this->trans`.

</Callout>

### Example With Parameters

Now let's extend the example with parameters.

**English Snippet:**

```json
{
  "myPlugin": {
    "lineItem": {
      "title": {
        "customerIsB2C": "B2C Customer: %percent%% discount",
        "customerIsB2B": "B2B Customer: %percent%% discount"
      }
    }
  }
}
```

**German Snippet:**

```json
{
  "myPlugin": {
    "lineItem": {
      "title": {
        "customerIsB2C": "B2C Kunde: %percent%% Rabatt",
        "customerIsB2B": "B2B Kunde: %percent%% Rabatt"
      }
    }
  }
}
```

**PHP Usage:**

```php
<?php declare(strict_types=1);

namespace MyPlugin\Service;

use Symfony\Contracts\Translation\TranslatorInterface;

class MyService
{
    public function __construct(
        private readonly TranslatorInterface $translator
    )
    {
    }
    
    public function getB2CLabel(): string
    {
        return $this->translator->trans(
            'myPlugin.lineItem.customerIsB2C',
            [
                '%percent%' => 10,
            ],
        );
    }
    public function getB2BLabel(): string
    {
         return $this->translator->trans(
            'myPlugin.lineItem.customerIsB2B',
            [
                '%percent%' => 15,
            ],
        );
    }
}
```

You can pass any number of parameters to the `trans` method. Typical sources for such values are plugin configuration settings, calculated business values, or contextual data (for example, customer groups).

The principle remains the same: define placeholders in your snippet and provide their values at runtime.

## Troubleshooting

If your snippets are not resolved as expected, make sure that:

- The snippet key is correct
- The snippet is defined in the correct language file
- The snippet is **not overridden via the administration**, because **snippets changed through the administration always have a higher priority than snippets defined in code**

## Summary

In this learning unit, you have learned:

- The conceptual difference between translations and snippets in Shopware.
- Use translations for dynamic, entity-based content that is stored in the database.
- Use snippets for static UI text resolved via the snippet system.
- Define and use custom snippets.
- Resolve snippets in Twig, Vue (Administration), and PHP using the Symfony Translator.

With this knowledge, you have a solid overview of how translations and snippets work in Shopware.
