sroehrl/php-i18n-translate

Simple yet powerful i18n support for PHP projects

v2.0.2 2023-01-17 01:32 UTC

This package is auto-updated.

Last update: 2024-07-17 04:38:48 UTC


README

Straight forward. Convenient. Fast.

Build Coverage php vegan Maintainability

Installation

composer require sroehrl/php-i18n-translate

require_once 'vendor/autoload.php';

$i18n = new I18nTranslate\Translate();

$i18n->setTranslations('de', [
    'hello' => 'hallo',
    'goose' => ['Gans', 'Gänse']
]);

Quick start:

1. In Code

echo "a: " . $i18n->t('hello') . "<br>"; 
echo "b: " . $i18n->t('goose') . "<br>";
echo "c: " . $i18n->t('goose.plural') . "<br>";

// detect plural by numeric value
foreach([0,1,2] as $number){
    echo $number . " " . $i18n->t('goose', $number) . ", ";
}

Outputs:

a: hallo <br>
b: Gans <br>
c: Gänse <br>
0 Gänse, 1 Gans, 2 Gänse

2. In HTML

main.html

<!-- We haven't provided any locale, so the ACCEPTED LANGUAGE header is used -->
<p i18n-date>03/06/2009</p>

<!-- If no value is present, the current timestamp is used -->
<p i18n-date="\`y H:i"></p>

<!-- If it's not a timestamp, things become smart -->
<p i18n-date="d.m">next monday</p>

<div>
    <p>Event starts @ <strong i18n-time>12:30</strong> (That's <span i18n-time-local="hh:mm a">12:30</span> your time)</p>
</div>

<!-- let's translate again, using the t-tag -->
<p><t>goose</t></p>
<p><t>goose.plural</t></p>
...

echo $i18n->translate(file_get_contents('main.html'));

Outputs:

<!-- We haven't provided any locale, so the ACCEPTED LANGUAGE header is used -->
<p>06.03.2009</p>

<!-- In no value is present, the current timestamp is used -->
<p>`22 13:14</p>

<!-- If it's not a timestamp, things become smart -->
<p>22.06</p>

<div>
    <p>Event starts @ <strong>12:30 EDT</strong> (That's <span>9:30 am</span> your time)</p>
</div>

<!-- let's translate again, using the t-tag -->
<p><t>Gans</t></p>
<p><t>Gänse</t></p>

Table of Contents

Initialization

$t = new I18nTranslate(string $locale = null, string $clientTimezone = null)

You can initialize either with or without a ISO-locale (e.g. 'en-US'). If no value is provided, the class first tries to set the locale by the ACCEPT_LANGUAGE header and if that fails defaults to "en-US". If you don't pass a $clientTimeZone (e.g. 'Europe/Paris'), then a guess is made based on the locale. This can potentially lead to time offsets in countries with multiple timezones.

TIPS:

Timezones: There are several "timezone-guessing" mechanisms around. Using JavaScript is usually the most reliable way.

Settings: When dealing with internationalization, setting your server & database to UTC is a battle-tested approach.

Setting up translations

Whether you read your translations from a database or a file: gettext is not required, and you are expected to run the method setTranslations for every language you support.

$t = new I18nTranslate();
$all = [
    ['eo' => ['blue' => 'blua',...]],
    ['jp' => ['blue' => '青い',...]], // BTW: make sure to consider encoding
    ['de' => ['blue' => 'blau',...]],
];
foreach($all as $lang => $translations){
    $t->setTranslations($lang, $translations);
}

$t->setDebug(true)

Will output a missing key message when a translation isn't set, rather than the following default behavior. This can be useful while developing/translating.

  • If the language is not found, the class will default to the first defined language
  • If a key is not found, the class will return the key
  • If the key has a suffix (.plural), it will be removed

About locale-translations: The decision to ignore the country-specification on the locale on translations is intended. While formatting reacts to the differences of country localisation, translations do not. Example en-US vs. en-EN: the date formatting will react to these differences, but translations like 'color' <=> 'colour' are not supported.

Time, Date, Currencies & Numbers

This package includes a formatter for currencies, numbers and dates. If you want to use its functionality outside of an HTML template, you can initialize it yourself.

The following converters are at your disposal:

  • date (accepts optional format)
  • date-local (accepts optional format)
  • time (accepts optional format)
  • time-local (accepts optional format)
  • currency (accepts optional, but recommended, ISO currency code like "USD")
  • number
$locale = 'en-US';
$clientTimeZone = 'America/New_York'; // or null to let the class make an educated guess
$formatter = new I18nTranslate\Formatter(string $locale, $clientTimeZone);

$convertToClientTime = $formatter->format('time-local');

$serverTime = time();
$clientTime = $convertToClientTime($serverTime); // e.g. 09:30 AM EDT
$clientTime = $convertToClientTime($serverTime, 'h:mm'); // e.g. 9:30

In most scenarios the templating attributes will be sufficient to handle your needs:

<section i18n-number>12.34</section>
<!-- with currencies we recommend setting a currency as it otherwise defaults to the user's locale... -->
<section i18n-currency="CAD">12.34</section>
<!-- ... But the following attributes accept formatting, but don't need it -->
<section i18n-date="EEEE">tomorrow</section>
<section i18n-date-local>tomorrow</section>
<section i18n-time>9:30</section>
<section i18n-time-local>9:30</section>

For a better understanding of how to pass values to your HTML, read here

Time & Date formats

This package uses the Intl-extension for PHP but has a fallback mechanisms. If you do not have Intl installed, localized transformation does not work.

Date & Time inputs are interpreted either as UNIX timestamps or strings supported by PHP's strtotime function.

Date & Time formats accepts strings in the format of ISO8601 date format So not PHP's date notation

I kindly ask contributors to find an appropriate list. Until then, this dated Zend list is the best I could find: formats

Default fallback formats:

Numbers and currencies work with or without the Intl-extension, but might not conform to the ISO 8601 standard without the Intl-extension.

The examples at Quick Start should help.

Using i18nTranslate with version 2+ of the neoan3-apps/template engine.

Under the hood this package interprets html-files with the help of neoan3-apps/template. It is therefore already available to you once you installed this package. The following setup allows the template engine to run PRIOR to translations, making dynamic formats and values possible:

use I18nTranslate\Translate;
use Neoan3\Apps\Template\Constants;
use Neoan3\Apps\Template\Template;
...
// your template path
Constants::setPath(__DIR__ . '/view');

// initialize i18n
$t = new Translate('de-DE);
$t->setTranslations('de', [
    'woman' => ['Frau', 'Frauen'],
    'man' => ['Mann', 'Männer']
]);

$regularRenderData = [
    'tomorrow' => time() + 60*60*24,
    'format' => 'dd-MM-Y',
    'iterateMe' => [0,1,2],
    'fromCode' => $t->('man')
];

echo $t->translate(Template::embraceFromFile('/test.html', $regularRenderData));

test.html

<h2>{{fromCode}}</h2>
<p>Hackathon @ <span i18n-date>{{tomorrow}}</span></p>
<p i18n-date="{{format}}">next monday</p>
<div>
    <p n-for="iterateMe as number">{{number}} {{t(woman, {{number}})}}</p>
</div>

Example-output:

<h2>Mann</h2>
<p>Hackathon @ <span>20.08.2022</span></p>
<p>22-08-22</p>
<div>
    <p>0 Frauen</p>
    <p>1 Frau</p>
    <p>2 Frauen</p>
</div>

Placeholders & Dynamic values

Placeholders are written embraced by [% ans %] (e.g. [% my-var %]). They enable dynamic values within a translation.

...
$t->setTranslations('de',[
    'Today I want to talk about [%subject%]' => 'Heute möchte ich über [%subject%] sprechen'
])
$context = [
    'personOfInterest' => 'Mr. T'
]
echo $t->translate(Template::embraceFromFile('/belowHtml.html', $context));
<t>Today I want to talk about [%subject%](% Tom Brady %)</t>

... or when using template values:

<t>Today I want to talk about [%subject%](% {{personOfInterest}} %)</t>

Attributes as functions

When using the attributes within t-tags as functions, they can be referenced as follows:

  • i18n-currency -> [%currency-value%]
  • i18n-time, i18n-time-local -> [%time-value%]
  • i18n-date, i18n-date-local -> [%date-value%]
  • i18n-number -> [%number-value%]

CONTRIBUTION

rules