PHPackages                             tobento/service-translation - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. tobento/service-translation

ActiveLibrary[Localization &amp; i18n](/categories/localization)

tobento/service-translation
===========================

Allowing you to support multiple languages within your application.

2.0(9mo ago)02157MITPHPPHP &gt;=8.4

Since Nov 14Pushed 9mo ago1 watchersCompare

[ Source](https://github.com/tobento-ch/service-translation)[ Packagist](https://packagist.org/packages/tobento/service-translation)[ Docs](https://www.tobento.ch)[ RSS](/packages/tobento-service-translation/feed)WikiDiscussions 2.x Synced today

READMEChangelog (5)Dependencies (5)Versions (7)Used By (7)

Translation Service
===================

[](#translation-service)

With the Translation Service you can translate messages easily.

Table of Contents
-----------------

[](#table-of-contents)

- [Getting started](#getting-started)
    - [Requirements](#requirements)
    - [Highlights](#highlights)
    - [Simple Example](#simple-example)
- [Documentation](#documentation)
    - [Translator](#translator)
        - [Create Translator](#create-translator)
        - [Translate Message](#translate-message)
    - [Resources](#resources)
        - [Create Resources](#create-resources)
        - [Add Resources](#add-resources)
        - [Filter Resources](#filter-resources)
        - [Sort Resources](#sort-resources)
        - [Get Resources / Translations](#get-resources-translations)
    - [Files Resources](#files-resources)
        - [Create Files Resources](#create-files-resources)
        - [Directory Structure](#directory-structure)
        - [Supported Files](#supported-files)
        - [Supporting Other Files](#supporting-other-files)
    - [Modifiers](#modifiers)
        - [Pluralization](#pluralization)
        - [Parameter Replacer](#parameter-replacer)
    - [Missing Translation Handler](#missing-translation-handler)
- [Credits](#credits)

---

Getting started
===============

[](#getting-started)

Add the latest version of the translation service running this command.

```
composer require tobento/service-translation

```

Requirements
------------

[](#requirements)

- PHP 8.4 or greater

Highlights
----------

[](#highlights)

- Framework-agnostic, will work with any project
- Decoupled design

Simple Example
--------------

[](#simple-example)

Here is a simple example of how to use the translation service:

```
use Tobento\Service\Translation\Translator;
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\Modifier\ParameterReplacer;
use Tobento\Service\Translation\Modifier\Pluralization;
use Tobento\Service\Translation\MissingTranslationHandler;

$translator = new Translator(
    new Resources(
        new Resource('*', 'de', [
            'Hello World' => 'Hallo Welt',
        ]),
    ),
    new Modifiers(
        new Pluralization(),
        new ParameterReplacer(),
    ),
    new MissingTranslationHandler(),
    'en',
);

var_dump($translator->trans('Hello World'));
// string(11) "Hello World"

var_dump($translator->trans('Hello World', [], 'de'));
// string(10) "Hallo Welt"
```

Documentation
=============

[](#documentation)

Translator
----------

[](#translator)

### Create Translator

[](#create-translator)

```
use Tobento\Service\Translation\Translator;
use Tobento\Service\Translation\TranslatorInterface;
use Tobento\Service\Translation\LocaleAware;
use Tobento\Service\Translation\ResourcesAware;
use Tobento\Service\Translation\ModifiersAware;
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\Modifier\ParameterReplacer;
use Tobento\Service\Translation\MissingTranslationHandler;

$translator = new Translator(
    resources: new Resources(
        new Resource('*', 'de', [
            'Hello World' => 'Hallo Welt',
        ]),
    ),
    modifiers: new Modifiers(
        new ParameterReplacer(),
    ),
    missingTranslationHandler: new MissingTranslationHandler(),
    locale: 'en',
    localeFallbacks: ['de' => 'en'],
    localeMapping: ['de' => 'de-CH'],
);

var_dump($translator instanceof TranslatorInterface);
// bool(true)

var_dump($translator instanceof LocaleAware);
// bool(true)

var_dump($translator instanceof ResourcesAware);
// bool(true)

var_dump($translator instanceof ModifiersAware);
// bool(true)
```

**Translator Interface**

```
use Tobento\Service\Translation\TranslatorInterface;

$translated = $translator->trans(
    message: 'Hi :name',
    parameters: [':name' => 'John'],
    locale: 'de'
);
```

**Locale Aware**

```
use Tobento\Service\Translation\LocaleAware;

// set the default locale:
$translator->setLocale('de');

// get the default locale:
var_dump($translator->getLocale());
// string(2) "de"

// set the locale fallbacks:
$translator->setLocaleFallbacks(['de' => 'en']);

// get the locale fallbacks:
var_dump($translator->getLocaleFallbacks());
// array(1) { ["de"]=> string(2) "en" }

// set the locale mapping:
$translator->setLocaleMapping(['de' => 'de-CH']);

// get the locale mapping:
var_dump($translator->getLocaleMapping());
// array(1) { ["de"]=> string(5) "de-CH" }
```

**Resources Aware**

See also [Resources](#resources) or [Files Resources](#files-resources) for more details.

```
use Tobento\Service\Translation\ResourcesAware;
use Tobento\Service\Translation\ResourcesInterface;

// get the resources:
var_dump($translator->resources() instanceof ResourcesInterface);
// bool(true)

// returns the translations of the specified resource:
$translations = $translator->getResource(
    name: '*',
    locale: 'de' // or null to use default
);

var_dump($translations);
// array(1) { ["Hello World"]=> string(10) "Hallo Welt" }

// returns a new instance with the specified resources:
$translator = $translator->withResources(
    resources: $resources // ResourcesInterface
);
```

**Modifiers Aware**

See also [Modifiers](#modifiers) for more details.

```
use Tobento\Service\Translation\ModifiersAware;
use Tobento\Service\Translation\ModifiersInterface;

// get the modifiers:
var_dump($translator->modifiers() instanceof ModifiersInterface);
// bool(true)

// returns a new instance with the specified modifiers:
$translator = $translator->withModifiers(
    modifiers: $modifiers // ModifiersInterface
);
```

### Translate Message

[](#translate-message)

```
use Tobento\Service\Translation\Translator;
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\Modifier\Pluralization;
use Tobento\Service\Translation\Modifier\ParameterReplacer;
use Tobento\Service\Translation\MissingTranslationHandler;

$translator = new Translator(
    resources: new Resources(
        new Resource('*', 'de', [
            'Hi :name' => 'Hi :name',
            'It takes :minutes minute|It takes :minutes minutes' => 'Es dauert :minutes Minute|Es dauert :minutes Minuten'
        ]),
    ),
    modifiers: new Modifiers(
        new Pluralization(),
        new ParameterReplacer(),
    ),
    missingTranslationHandler: new MissingTranslationHandler(),
    locale: 'en',
    localeFallbacks: ['de' => 'en'],
);

$translated = $translator->trans(
    message: 'Hi :name',
    parameters: [':name' => 'John'],
    locale: 'de'
);

var_dump($translated);
// string(7) "Hi John"

$translated = $translator->trans(
    message: 'It takes :minutes minute|It takes :minutes minutes',
    parameters: [':minutes' => 5, 'count' => 5],
    locale: 'de'
);

var_dump($translated);
// string(19) "Es dauert 5 Minuten"
```

By default, resources will be sorted by its priority!

**Using specific resource**

Keep in mind that named resources are only loaded on the first resource request.
Resources with "\*" named are always loaded.

```
use Tobento\Service\Translation\Translator;
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\MissingTranslationHandler;

$translator = new Translator(
    resources: new Resources(
        new Resource('shop', 'de', [
            'noProducts' => 'Keine Produkte',
            'No items in your shopping bag.' => 'Keine Artikel sind in deinem Warenkorb.',
        ]),
    ),
    modifiers: new Modifiers(),
    missingTranslationHandler: new MissingTranslationHandler(),
    locale: 'en',
    localeFallbacks: ['de' => 'en'],
);

// with dot notation
$translated = $translator->trans(
    message: 'shop.noProducts',
    locale: 'de'
);

var_dump($translated);
// string(14) "Keine Produkte"

// with src parameter
$translated = $translator->trans(
    message: 'No items in your shopping bag.',
    parameters: ['src' => 'shop'],
    locale: 'de'
);

var_dump($translated);
// string(39) "Keine Artikel sind in deinem Warenkorb."
```

Resources
---------

[](#resources)

### Create Resources

[](#create-resources)

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\ResourcesInterface;
use Tobento\Service\Translation\Resource;

$resources = new Resources(
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        group: 'front',
        priority: 10,
    ),
);

var_dump($resources instanceof ResourcesInterface);
// bool(true)
```

### Add Resources

[](#add-resources)

You may add resources by using the **add** method:

**add resource**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;

$resources = new Resources();

$resources->add(new Resource('*', 'de', [
    'Hello World' => 'Hallo Welt',
]));
```

**add resources**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;

$resources = new Resources();

$resources->add(new Resources(
    new Resource('*', 'de', [
        'Hello World' => 'Hallo Welt',
    ]),
));
```

### Filter Resources

[](#filter-resources)

You may use the filter methods returning a new instance.

**filter**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\ResourceInterface;

$resources = new Resources(
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        group: 'front',
    ),
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        group: 'back',
    ),
);

// filter by group:
$resources = $resources->filter(
    fn(ResourceInterface $r): bool => $r->group() === 'front'
);
```

**locale**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;

$resources = new Resources(
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
    ),
    new Resource(
        name: '*',
        locale: 'de',
        translations: ['Hello World' => 'Hallo Welt'],
    ),
);

// filter by locale:
$resources = $resources->locale('en');
```

**locales**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;

$resources = new Resources(
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
    ),
    new Resource(
        name: '*',
        locale: 'de',
        translations: ['Hello World' => 'Hallo Welt'],
    ),
);

// filter by locales:
$resources = $resources->locales(['en', 'de']);
```

**name**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;

$resources = new Resources(
    new Resource(
        name: 'shop',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
    ),
    new Resource(
        name: 'shop',
        locale: 'de',
        translations: ['Hello World' => 'Hallo Welt'],
    ),
);

// filter by name:
$resources = $resources->name('shop');
```

### Sort Resources

[](#sort-resources)

**sort by priority**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;

$resources = new Resources(
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        priority: 10,
    ),
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        priority: 15,
    ),
);

// sort by priority:
$resources = $resources->sort();
```

**sort by callback**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\ResourceInterface;

$resources = new Resources(
    new Resource(
        name: 'users',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        priority: 10,
    ),
    new Resource(
        name: 'shop',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        priority: 15,
    ),
);

// sort by name:
$resources = $resources->sort(
    fn(ResourceInterface $a, ResourceInterface $b): int => $a->name()  $b->name()
);
```

### Get Resources / Translations

[](#get-resources--translations)

**all**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\ResourceInterface;

$resources = new Resources(
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
    ),
);

foreach($resources->all() as $resource) {
    var_dump($resource instanceof ResourceInterface);
    // bool(true)

    var_dump($resource->name());
    // string(1) "*"

    var_dump($resource->locale());
    // string(2) "en"

    var_dump($resource->group());
    // string(7) "default"

    var_dump($resource->priority());
    // int(0)

    var_dump($resource->translations());
    // array(1) { ["Hello World"]=> string(10) "Hallo Welt" }
}
```

**translations**

```
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;

$resources = new Resources(
    new Resource(
        name: '*',
        locale: 'en',
        translations: ['Hello World' => 'Hallo Welt'],
        priority: 10,
    ),
);

$translations = $resources->locale('en')->translations();
/*Array (
    [Hello World] => Hallo Welt
)*/
```

> ⚠️ **You must call locale() or locales() before all() or translations() method if you have added (sub or lazy) resources, otherwise they will not get created.**

```
foreach($resources->locale('en')->all() as $resource) {
    var_dump($resource instanceof ResourceInterface);
    // bool(true)
}
```

Files Resources
---------------

[](#files-resources)

### Create Files Resources

[](#create-files-resources)

```
use Tobento\Service\Translation\FilesResources;
use Tobento\Service\Dir\Dirs;
use Tobento\Service\Translation\ResourcesInterface;

$resources = new FilesResources(
    new Dirs()->dir(dir: 'private/trans/', group: 'front', priority: 10)
);

var_dump($resources instanceof ResourcesInterface);
// bool(true)
```

### Directory Structure

[](#directory-structure)

Files starting with the locale are stored as `*` resource name. They are all fetched and merged together on the first translations request.
Files not starting with the locale are only loaded on the first resource request. Furthermore, files named like `routes.shop.json` and `routes.blog.json` are merged together as resource name `routes`.

```
private/
    trans/
        en/
            en.php
            en.json
            en-shop.json
            shop.json
            routes.shop.json
            routes.blog.json
        de-CH/
            de-CH.json
            de-CH-shop.json
            shop.json
            routes.shop.json

```

### Supported Files

[](#supported-files)

Currently supported files are json and php.

**json**

```
{
    "Using Real Message": "Using Real Message",
    "usingKeywordMessage": "Using Keyword Message"
}
```

**php**

```
return [
    'Using Real Message' => 'Using Real Message',
    'usingKeywordMessage' => 'Using Keyword Message',
];
```

### Supporting Other Files

[](#supporting-other-files)

You may support others files by providing your own resource factory:

```
use Tobento\Service\Translation\FilesResources;
use Tobento\Service\Dir\Dirs;
use Tobento\Service\Translation\ResourceFactory;
use Tobento\Service\Translation\ResourceInterface;
use Tobento\Service\Filesystem\File;

class CustomResourceFactory extends ResourceFactory
{
    /**
     * Create a new Resource from file.
     *
     * @param string|File $file
     * @param string $locale
     * @param string $group
     * @param int $priority
     * @return ResourceInterface
     */
    public function createResourceFromFile(
        string|File $file,
        string $locale,
        string $group = 'default',
        int $priority = 0,
    ): ResourceInterface {

        // Create your custom resource for the specific file extension

        // Otherwise use parent
        return parent::createResourceFromFile($file, $locale, $group, $priority);
    }
}

$resources = new FilesResources(
    new Dirs()->dir(dir: 'private/trans/', group: 'front', priority: 10),
    new CustomResourceFactory()
);
```

Modifiers
---------

[](#modifiers)

**Create Modifiers**

```
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\ModifiersInterface;
use Tobento\Service\Translation\Modifier\ParameterReplacer;

$modifiers = new Modifiers(
    new ParameterReplacer(),
);

var_dump($modifiers instanceof ModifiersInterface);
// bool(true)
```

**Add Modifier**

```
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\Modifier\ParameterReplacer;

$modifiers = new Modifiers();
$modifiers->add(new ParameterReplacer());
```

**Get all modifiers**

```
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\Modifier\ParameterReplacer;
use Tobento\Service\Translation\ModifierInterface;

$modifiers = new Modifiers(new ParameterReplacer());

$allModifiers = $modifiers->all();
// array
```

**Modify message**

```
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\Modifier\ParameterReplacer;

$modifiers = new Modifiers(
    new ParameterReplacer(),
);

[$message, $parameters] = $modifiers->modify(
    message: 'Hi :name',
    parameters: [':name' => 'John'],
);

var_dump($message);
// string(7) "Hi John"
```

### Pluralization

[](#pluralization)

```
use Tobento\Service\Translation\Modifier\Pluralization;

$modifier = new Pluralization(key: 'count');

[$message, $parameters] = $modifier->modify(
    message: 'There is one apple|There are many apples',
    parameters: ['count' => 5],
);

var_dump($message);
// string(21) "There are many apples"

[$message, $parameters] = $modifier->modify(
    message: 'There is one apple|There are many apples',
    parameters: ['count' => 1],
);

var_dump($message);
// string(18) "There is one apple"
```

### Parameter Replacer

[](#parameter-replacer)

```
use Tobento\Service\Translation\Modifier\ParameterReplacer;

$modifier = new ParameterReplacer();

[$message, $parameters] = $modifier->modify(
    message: 'Hi :name',
    parameters: [':name' => 'John'],
);

var_dump($message);
// string(7) "Hi John"
```

Missing Translation Handler
---------------------------

[](#missing-translation-handler)

You may add a logger to log missing messages:

```
use Tobento\Service\Translation\Translator;
use Tobento\Service\Translation\Resources;
use Tobento\Service\Translation\Resource;
use Tobento\Service\Translation\Modifiers;
use Tobento\Service\Translation\MissingTranslationHandler;
use Psr\Log\LoggerInterface;
use Monolog\Logger;
use Monolog\Handler\StreamHandler;

$logger = new Logger('name');
$logger->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));

$translator = new Translator(
    new Resources(
        new Resource('*', 'de', [
            'Hello World' => 'Hallo Welt',
        ]),
    ),
    new Modifiers(),
    new MissingTranslationHandler($logger), // any PSR-3 logger
);

var_dump($translator->trans('Hello World'));
```

Credits
=======

[](#credits)

- [Tobias Strub](https://www.tobento.ch)
- [All Contributors](../../contributors)

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance57

Moderate activity, may be stable

Popularity12

Limited adoption so far

Community15

Small or concentrated contributor base

Maturity72

Established project with proven stability

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~235 days

Recently: every ~208 days

Total

7

Last Release

282d ago

Major Versions

1.x-dev → 2.02025-09-24

PHP version history (2 changes)1.0.0PHP &gt;=8.0

2.0PHP &gt;=8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/055d6a1b5c2384bb179c75ab0b55914231d898fdc4dffeb30770f81200e52206?d=identicon)[TOBENTOch](/maintainers/TOBENTOch)

---

Top Contributors

[![tobento-ch](https://avatars.githubusercontent.com/u/16684832?v=4)](https://github.com/tobento-ch "tobento-ch (17 commits)")

---

Tags

translationspackagetobento

###  Code Quality

TestsPHPUnit

Static AnalysisPsalm

Type Coverage Yes

### Embed Badge

![Health badge](/badges/tobento-service-translation/health.svg)

```
[![Health](https://phpackages.com/badges/tobento-service-translation/health.svg)](https://phpackages.com/packages/tobento-service-translation)
```

###  Alternatives

[composer/composer

Composer helps you declare, manage and install dependencies of PHP projects. It ensures you have the right stack everywhere.

29.5k196.2M3.1k](/packages/composer-composer)[matomo/matomo

Matomo is the leading Free/Libre open analytics platform

21.7k38.9k](/packages/matomo-matomo)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)[api-platform/metadata

API Resource-oriented metadata attributes and factories

275.0M219](/packages/api-platform-metadata)[dagger/dagger

Dagger PHP SDK

261.1k](/packages/dagger-dagger)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
