---
title: "CraftCMS: Smarter Translation Files"
date: "12/20/2020, 1:59 AM"
category: "Development"
topics: ["i18n", "CraftCMS"]
canonical: "https://sveltekit.davidhellmann.com/blog/craftcms-smarter-translation-files"
section: "blog"
---

# CraftCMS: Smarter Translation Files

<p>On my last <a href="https://craftcms.com/">Craft CMS</a> client project at work, I was a bit pissed about our translation file. Long story short: It's messy! We have a lot of static translations in this project, and it's a bit hard to manage them in one big file. So, our first approach was to use generic strings to translate rather than the thing to be translated itself. That looked like this:</p>

```php
<?php
return [
    'translate.component.code.show' => 'Show',
    'translate.component.code.hide' => 'Hide',
    'translate.component.code.copy' => 'Copy',
    'translate.component.code.copied' => '✅ Copied!',
];
```

<p>This helped us have more explicit strings and context in our translation file. All our strings start with: <code>translate</code><strong>,</strong> so it's easy to search against all templates for translations. Great advantage! But it does not solve the problem that you can have a massive file at the end. Yes, working with a file like that is possible, but we don't like it.</p><h2>A much better approach</h2><p>We thought about how we could optimize here. It's pretty simple. Place your files where they belong. That means we say goodbye to one large and messy file and say hello to <strong>component/page-based translations</strong>. Let me explain with a small example. Our folder structure looks like this:</p>

```plaintext
...
templates
-- _components
----- code
------- code.js
------- code.twig
------- translate.de.component.code.php
------- translate.en.component.code.php
...
translations
-- de
---- site.php
-- en
---- site.php
...
```

<p>In our components folder, we find all our components. Each component can have a different set of files. If we have a template file (twig in our case) and need static translations, we also place a PHP file for each language in that folder. Our naming for this file is:</p><p><strong>TRANSLATE.LANG.CONTEXT.COMPONENT.php</strong><br /><strong>translate.en.component.code.php</strong></p><h2>Let's look at a complete example</h2><p>We have two sites (German and English), and we have a code component in our example. That means we need two translation files.</p>

**templates/_components/code/translate.de.component.code.php**

```php
<?php
return [
    'translate.component.code.show' => 'Zeigen',
    'translate.component.code.hide' => 'Verbergen',
    'translate.component.code.copy' => 'Kopieren',
    'translate.component.code.copied' => '✅ Kopiert!',
];
```

**templates/_components/code/translate.en.component.code.php**

```php
<?php
return [
    'translate.component.code.show' => 'Show',
    'translate.component.code.hide' => 'Hide',
    'translate.component.code.copy' => 'Copy',
    'translate.component.code.copied' => '✅ Copied!',
];
```

<p>In our main translation file, we have to include this component translation file and we have to merge it all. In this example, we import our code file and two other components. We also have a global array where we can place global translations like weekdays or stuff like that. In the end, it looks like this:</p>

**translations/de/site.php**

```php
<?php
// Vars
$page = '/../../templates/';
$lang = 'de';

// Global Translations
$globalTranslations = [
    'translate.global.days.monday' => 'Montag',
    'translate.global.days.tuesday' => 'Dienstag',
    'translate.global.days.wednesday' => 'Mittwoch',
    'translate.global.days.thursday' => 'Donnerstag',
    'translate.global.days.friday' => 'Freitag',
    'translate.global.days.saturday' => 'Samstag',
    'translate.global.days.sunday' => 'Sonntag',
];

// Comp Translations
$compTranslations = [];

// Get all Files
$translationFiles = glob(__DIR__ . $page . "**/*/translate." . $lang . "*.php");

// Merge Files
foreach ($translationFiles as $translationFile) {
    $data = include $translationFile;
    if (!is_array($data)) {
        continue;
    }
    $compTranslations[] = $data;
}


// Return All Translations
return array_merge(...$compTranslations, ...[$globalTranslations]);
```

**translations/en/site.php**

```php
<?php
// Vars
$page = '/../../templates/';
$lang = 'en';

// Global Translations
$globalTranslations = [
    'translate.global.days.monday' => 'Monday',
    'translate.global.days.tuesday' => 'Tuesday',
    'translate.global.days.wednesday' => 'Wednesday',
    'translate.global.days.thursday' => 'Thursday',
    'translate.global.days.friday' => 'Friday',
    'translate.global.days.saturday' => 'Saturday',
    'translate.global.days.sunday' => 'Sunday',
];

// Comp Translations
$compTranslations = [];

// Get all Files
$translationFiles = glob(__DIR__ . $page . "**/*/translate." . $lang . "*.php");

// Merge Files
foreach ($translationFiles as $translationFile) {
    $data = include $translationFile;
    if (!is_array($data)) {
        continue;
    }
    $compTranslations[] = $data;
}


// Return All Translations
return array_merge(...$compTranslations, ...[$globalTranslations]);
```

<p>What do you think? Let me know!</p>
