Translation (i18n)

Cresenity Framework has a built-in translation service for storing strings in multiple languages. Language lines are stored in PHP files that return a key/value array, one folder per locale.


Language Files

Translation files live in default/i18n/{locale}/{group}.php. Each file returns an associative array where the key is looked up by c::__() and the value is the translated string.

default/i18n/
├── en_US/
│   ├── core.php
│   └── accounting.php
└── id_ID/
    ├── core.php
    └── accounting.php
<?php
// default/i18n/id_ID/core.php
return [
    'Invoice' => 'Invoice',
    'Search Supplier' => 'Cari Supplier',
];

The {group} is just the filename without .php — you can split lines into as many files as you like (core.php, accounting.php, shop.php, etc). Group them by module/feature to keep files manageable.


Using Translations

Use c::__($key) (or its alias c::trans($key)) to resolve a string:

c::__('Invoice');            // resolves 'Invoice' from the 'core' group
c::__('accounting.Journal'); // resolves 'Journal' from the 'accounting' group
Key format Group Item
'Invoice' (no dot) core Invoice
'accounting.Journal' (dotted) accounting Journal

A key with no dot always resolves against the core group. To pull from a different file, prefix the key with {group}..

If a key is not found in any language file, c::__() returns the key itself (with placeholders replaced) — this makes missing translations easy to spot in the UI, since you'll see the raw English key instead of a blank string or an error.

Placeholders

Pass an array of replacements as the second argument. Placeholders in the language line are written with a leading colon:

// language file
'Welcome, :name!' => 'Selamat datang, :name!',

// usage
c::__('Welcome, :name!', ['name' => $user->name]);

Replacement is case-aware: :name, :NAME, and :Name in the line are replaced with the lower/upper/ucfirst form of the value respectively.

In Blade Views

<h5>@lang('Invoice')</h5>
<h5>@lang('accounting.Journal')</h5>

@lang(...) compiles down to c::__(...) — it accepts the same key format and placeholder array.


Pluralization

For strings that change based on a count, separate the singular/plural forms with | and use c::trans()->choice($key, $count), or the @choice Blade directive:

// language file
'There is one apple|There are many apples' => 'Ada satu apel|Ada banyak apel',
c::trans()->choice('There is one apple|There are many apples', $count);
@choice('There is one apple|There are many apples', $count)

You can also use explicit ranges with {n} / [n,m] conditions, which take priority over the plain | segments:

'{0} No apples|{1} One apple|[2,*] :count apples' => '{0} Tidak ada apel|{1} Satu apel|[2,*] :count apel',

The :count placeholder is automatically available inside a choice() string and is filled in with the number passed.


Switching Locale

The active locale is read from config/app.php:

return [
    // ...
    'locale' => 'en_US',           // default locale
    'fallback_locale' => 'en_US',  // used when a key is missing in the active locale
];

To switch the locale at runtime (e.g. based on the logged-in user's preference), call CF::setLocale():

CF::setLocale('id_ID');

This updates the translator's active locale, switches CCarbon's locale (so date formatting follows suit), and dispatches a cf.locale.updated event that other parts of the app can hook into.

CF::getLocale(); // get the currently active locale

A typical place to call CF::setLocale() is early in the request lifecycle (e.g. in a bootstrap file or middleware), based on the user's stored language preference.


Multiple Search Paths

When resolving a group's language file, the loader searches every registered framework path (CF::paths()) and merges the results — paths registered later win on key conflicts. This lets an application override or extend a language file that a shared/base module already ships with, without having to duplicate the entire file.


Checking for Missing Translations

Run the following command to verify every locale has the same set of language files and keys:

phpcf translations:check

It scans default/i18n/, reports any locale that is missing a whole file another locale has, and reports any individual key that exists in one locale's file but not in the others. This is useful before a release to make sure a newly-added string was translated for every supported language.