Introduction

Shopware 6.7 represents a significant evolution in the e-commerce platform's capabilities, offering enhanced developer tools and improved translation management systems. As a developer working with custom plugins, understanding how to properly implement translations is crucial for creating multilingual, user-friendly extensions that can reach a global audience.

This comprehensive guide will walk you through the technical implementation of translations for custom Shopware 6.7 plugins, covering everything from basic setup to advanced configuration patterns. We'll explore both the frontend and backend translation mechanisms, ensuring your plugin seamlessly integrates with Shopware's translation system while maintaining optimal performance.

Understanding Shopware 6.7 Translation Architecture

Before diving into implementation details, it's essential to understand how Shopware 6.7 handles translations. The platform utilizes a sophisticated system that combines database-driven translations with file-based localization, providing developers with multiple approaches to manage multilingual content.

The translation system in Shopware 6.7 operates through several layers:

  • Core system translations stored in the database
  • Plugin-specific translations managed via language files
  • Dynamic translations for runtime content
  • Fallback mechanisms ensuring no translation is lost

Setting Up Translation Files Structure

To begin implementing translations, you need to establish the proper file structure within your plugin. Create a Resources directory at the root of your plugin with the following organization:

your-plugin/
├── Resources/
│   ├── config/
│   │   └── config.xml
│   ├── language/
│   │   ├── de-DE/
│   │   │   └── messages.de-DE.json
│   │   └── en-GB/
│   │       └── messages.en-GB.json
│   └── static/
└── src/

The messages.de-DE.json and messages.en-GB.json files contain your translation key-value pairs, structured as JSON objects. This approach allows for easy maintenance and extension of your plugin's localization capabilities.

Implementing Backend Translations

For backend translations, Shopware 6.7 provides several mechanisms depending on your specific needs. The most common approach involves using the trans() method within your plugin's controllers, services, or administration components.

<?php

namespace YourPlugin\Subscriber;

use Shopware\Core\Framework\Event\ShopwareEvent;
use Symfony\Contracts\Translation\TranslatorInterface;

class TranslationSubscriber
{
    private TranslatorInterface $translator;
    
    public function __construct(TranslatorInterface $translator)
    {
        $this->translator = $translator;
    }
    
    public function onCustomEvent(ShopwareEvent $event): void
    {
        $translatedMessage = $this->translator->trans('your-plugin.custom.message');
        // Use translated message in your logic
    }
}

This approach leverages Symfony's translation component, ensuring compatibility with Shopware's translation system while providing flexibility for complex translation scenarios.

Frontend Translation Implementation

Frontend translations require a slightly different approach, particularly when working with Vue.js components in the administration area. Shopware 6.7's administration interface uses a robust translation system that can be accessed through several methods:

Method 1: Using the trans Filter in Vue Components

<template>
    <div class="custom-plugin-component">
        <h2>{{ $tc('your-plugin.custom.title') }}</h2>
        <p>{{ $t('your-plugin.custom.description') }}</p>
    </div>
</template>

<script>
export default {
    name: 'CustomPluginComponent',
    mounted() {
        console.log(this.$t('your-plugin.custom.message'));
    }
}
</script>

Method 2: Programmatic Translation in JavaScript

import { translate } from '@shopware-ag/meteor-component-library';

const translatedText = translate('your-plugin.custom.text');
console.log(translatedText);

Advanced Translation Patterns

Dynamic Translation Keys

For plugins that generate dynamic content, you may need to implement dynamic translation keys. This approach allows you to maintain translation consistency while adapting to varying content:

<?php

namespace YourPlugin\Service;

class DynamicTranslationService
{
    public function getTranslatedLabel(string $baseKey, array $parameters = []): string
    {
        $key = sprintf('%s.%s', $baseKey, $this->generateDynamicSuffix($parameters));
        return $this->translator->trans($key, $parameters);
    }
    
    private function generateDynamicSuffix(array $parameters): string
    {
        // Generate unique suffix based on parameters
        return implode('_', array_keys($parameters));
    }
}

Context-Specific Translations

Shopware 6.7 supports context-specific translations, which are particularly useful for plugins that might have different meanings for the same word in different contexts:

// In your translation file (messages.de-DE.json)
{
    "your-plugin": {
        "product": {
            "status": "Produktstatus",
            "sales": "Verkaufszahlen"
        }
    }
}

Translation Fallback Mechanisms

Implementing proper fallback mechanisms ensures that users always see meaningful content even when specific translations are missing:

<?php

namespace YourPlugin\Service;

use Symfony\Contracts\Translation\TranslatorInterface;

class TranslationFallbackService
{
    private TranslatorInterface $translator;
    private string $fallbackLocale;
    
    public function __construct(TranslatorInterface $translator, string $fallbackLocale = 'en-GB')
    {
        $this->translator = $translator;
        $this->fallbackLocale = $fallbackLocale;
    }
    
    public function getTranslation(string $key, array $parameters = [], ?string $locale = null): string
    {
        try {
            return $this->translator->trans($key, $parameters, null, $locale);
        } catch (\Exception $e) {
            // Fallback to default locale or return key itself
            return $this->translator->trans($key, $parameters, null, $this->fallbackLocale);
        }
    }
}

Configuration and Registration

Proper configuration ensures that your translation files are properly registered with Shopware's system. Update your plugin's config.xml to include translation definitions:

<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/platform/master/src/Core/System/SystemConfig/Schema/config.xsd">
    <elements>
        <element name="your-plugin.translation" type="text">
            <label>Translation Key</label>
            <helpText>Enter translation key for your plugin</helpText>
        </element>
    </elements>
</config>

Additionally, register your translations in the plugin's main class:

<?php

namespace YourPlugin;

use Shopware\Core\Framework\Plugin;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class YourPlugin extends Plugin
{
    public function build(ContainerBuilder $container): void
    {
        parent::build($container);
        
        // Register translation files
        $container->setParameter('your_plugin.translation_paths', [
            __DIR__ . '/Resources/language'
        ]);
    }
}

Performance Optimization

When dealing with large translation files or complex plugins, performance becomes a critical factor. Shopware 6.7 offers several optimization strategies:

Translation Caching

Implement proper caching mechanisms to reduce database queries during translation lookups:

<?php

namespace YourPlugin\Service;

use Symfony\Contracts\Cache\TagAwareCacheInterface;

class CachedTranslationService
{
    private TagAwareCacheInterface $cache;
    private TranslatorInterface $translator;
    
    public function __construct(
        TagAwareCacheInterface $cache,
        TranslatorInterface $translator
    ) {
        $this->cache = $cache;
        $this->translator = $translator;
    }
    
    public function getTranslation(string $key, array $parameters = []): string
    {
        $cacheKey = 'translation_' . md5($key . serialize($parameters));
        
        return $this->cache->get($cacheKey, function () use ($key, $parameters) {
            return $this->translator->trans($key, $parameters);
        });
    }
}

Lazy Loading Translations

For plugins with extensive translation requirements, consider lazy loading specific translation sets:

<?php

class LazyTranslationService
{
    private array $loadedTranslations = [];
    
    public function loadTranslations(string $locale, string $context): void
    {
        if (!isset($this->loadedTranslations[$context][$locale])) {
            // Load only required translations
            $this->loadedTranslations[$context][$locale] = $this->loadFromDatabase($context, $locale);
        }
    }
    
    public function getTranslation(string $key, string $context, string $locale): string
    {
        $this->loadTranslations($locale, $context);
        return $this->loadedTranslations[$context][$locale][$key] ?? $key;
    }
}

Testing Translation Implementation

Proper testing ensures your translations work correctly across different locales and scenarios:

<?php

namespace YourPlugin\Tests\Unit\Service;

use PHPUnit\Framework\TestCase;
use Symfony\Contracts\Translation\TranslatorInterface;

class TranslationServiceTest extends TestCase
{
    public function testTranslationReturnsCorrectValue(): void
    {
        $translator = $this->createMock(TranslatorInterface::class);
        $translator->expects($this->once())
            ->method('trans')
            ->with('your-plugin.test.key')
            ->willReturn('Translated Value');
            
        $service = new TranslationService($translator);
        $result = $service->getTranslation('your-plugin.test.key');
        
        $this->assertEquals('Translated Value', $result);
    }
}

Best Practices and Common Pitfalls

Key Naming Conventions

Follow consistent naming conventions to maintain organization:

{
    "your-plugin": {
        "module": {
            "title": "Module Title",
            "description": "Module Description"
        },
        "settings": {
            "general": "General Settings",
            "advanced": "Advanced Settings"
        }
    }
}

Avoiding Translation Key Collisions

Use plugin-specific prefixes to prevent conflicts with core translations:

{
    "your-plugin.module.title": "Custom Module Title",
    "your-plugin.settings.save": "Save Configuration"
}

Conclusion

Implementing translations in Shopware 6.7 custom plugins requires understanding both the platform's translation architecture and proper implementation patterns. By following the approaches outlined in this guide, you'll create robust, multilingual plugins that provide excellent user experiences across different locales.

The key to successful plugin localization lies in proper planning, consistent naming conventions, and leveraging Shopware's built-in translation mechanisms while implementing performance optimizations. Whether you're building simple plugins or complex extensions, these techniques will ensure your translations work seamlessly within the Shopware ecosystem.

Remember to test thoroughly across different languages and scenarios, and always consider caching strategies for optimal performance. With proper implementation, your custom plugins will be ready to serve users worldwide while maintaining the quality and consistency that Shopware developers expect.