Skip to content
This repository has been archived by the owner on Jun 18, 2019. It is now read-only.

Commit

Permalink
Merge pull request #169 from dimsav/country-locales
Browse files Browse the repository at this point in the history
Country locales
  • Loading branch information
dimsav committed Oct 23, 2015
2 parents 3afa42a + 5bd54f2 commit d38db2e
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 12 deletions.
38 changes: 36 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ class Country extends Eloquent
### Available methods

```php
// This is how we determine the current locale.
// Before we get started, this is how we determine the current locale.
// It is set by laravel or other packages.
App::getLocale(); // 'fr'

Expand Down Expand Up @@ -307,7 +307,7 @@ $germany->{'name:de'} // 'Deutschland'
If you want to fallback to a default translation when a translation has not been found, enable this in the configuration
using the `use_fallback` key. And to select the default locale, use the `fallback_locale` key.

Example:
Configuration example:

```php
return [
Expand All @@ -327,6 +327,40 @@ class Country {
}
```

#### Country based fallback

Since version v5.3 it is possible to use country based locales. For example, you can have the following locales:

- English: `en`
- Spanish: `es`
- Mexican Spanish: `es-MX`
- Colombian Spanish: `es-CO`

To configuration for these locales looks like this:

```php
'locales' => [
'en',
'es' => [
'MX',
'CO',
],
];
```

We can also configure the "glue" between the language and country. If for instance we prefer the format `es_MX` instead of `es-MX`,
the configuration should look like this:

```php
'locale_separator' => '_',
```

What applies for the fallback of the locales using the `en-MX` format?

Let's say our fallback locale is `en`. Now, when we try to fetch from the database the translation for the
locale `es-MX` but it doesn't exist, we won't get as fallback the translation for `en`. Translatable will use as a
fallback `es` (the first part of `es-MX`) and only if nothing is found, the translation for `en` is returned.

## FAQ

#### I need some example code!
Expand Down
66 changes: 57 additions & 9 deletions src/Translatable/Translatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait Translatable
/**
* Alias for getTranslation()
*
* @param strign|null $locale
* @param string|null $locale
* @param bool $withFallback
*
* @return \Illuminate\Database\Eloquent\Model|null
Expand Down Expand Up @@ -55,16 +55,16 @@ public function translateOrNew($locale)
public function getTranslation($locale = null, $withFallback = null)
{
$locale = $locale ?: $this->locale();

$withFallback = $withFallback === null ? $this->useFallback() : $withFallback;
$fallbackLocale = $this->getFallbackLocale($locale);

if ($this->getTranslationByLocaleKey($locale)) {
$translation = $this->getTranslationByLocaleKey($locale);
} elseif ($withFallback
&& $this->getFallbackLocale()
&& $this->getTranslationByLocaleKey($this->getFallbackLocale())
&& $fallbackLocale
&& $this->getTranslationByLocaleKey($fallbackLocale)
) {
$translation = $this->getTranslationByLocaleKey($this->getFallbackLocale());
$translation = $this->getTranslationByLocaleKey($fallbackLocale);
} else {
$translation = null;
}
Expand Down Expand Up @@ -266,13 +266,43 @@ private function getTranslationByLocaleKey($key)
}

/**
* @param null $locale
*
* @return string
*/
private function getFallbackLocale()
private function getFallbackLocale($locale = null)
{
if ($locale && $this->isLocaleCountryBased($locale)) {
if ($fallback = $this->getLanguageFromCountryBasedLocale($locale)) {
return $fallback;
}
}

return App::make('config')->get('translatable.fallback_locale');
}

/**
* @param $locale
*
* @return bool
*/
private function isLocaleCountryBased($locale)
{
return strpos($locale, $this->getLocaleSeparator()) !== false;
}

/**
* @param $locale
*
* @return string
*/
private function getLanguageFromCountryBasedLocale($locale)
{
$parts = explode($this->getLocaleSeparator(), $locale);

return array_get($parts, 0);
}

/**
* @return bool|null
*/
Expand Down Expand Up @@ -316,17 +346,35 @@ protected function isKeyALocale($key)
*/
protected function getLocales()
{
$config = App::make('config');
$locales = (array) $config->get('translatable.locales', []);
$localesConfig = (array) App::make('config')->get('translatable.locales');

if (empty($locales)) {
if (empty($localesConfig)) {
throw new LocalesNotDefinedException('Please make sure you have run "php artisan config:publish dimsav/laravel-translatable" '.
' and that the locales configuration is defined.');
}

$locales = [];
foreach ($localesConfig as $key => $locale) {
if (is_array($locale)) {
$locales[] = $key;
foreach ($locale as $countryLocale) {
$locales[] = $key.$this->getLocaleSeparator().$countryLocale;
}
} else {
$locales[] = $locale;
}
}

return $locales;
}

/**
* @return string
*/
protected function getLocaleSeparator() {
return App::make('config')->get('translatable.locale_separator', '-');
}

/**
* @return bool
*/
Expand Down
21 changes: 20 additions & 1 deletion src/config/translatable.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,26 @@
| Contains an array with the applications available locales.
|
*/
'locales' => ['en', 'es'],
'locales' => [
'en',
'fr',
'es' => [
'MX', // mexican spanish
'CO', // colombian spanish
],
],

/*
|--------------------------------------------------------------------------
| Locale separator
|--------------------------------------------------------------------------
|
| This is a string used to glue the language and the country when defining
| the available locales. Example: if set to '-', then the locale for
| colombian spanish will be saved as 'es-CO' into the database.
|
*/
'locale_separator' => '-',

/*
|--------------------------------------------------------------------------
Expand Down
46 changes: 46 additions & 0 deletions tests/TranslatableTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use Dimsav\Translatable\Test\Model\Country;
use Dimsav\Translatable\Test\Model\CountryStrict;
use Dimsav\Translatable\Test\Model\CountryWithCustomLocaleKey;
use Dimsav\Translatable\Test\Model\Food;

class TranslatableTest extends TestsBase
{
Expand Down Expand Up @@ -365,4 +366,49 @@ public function test_config_overrides_apps_locale()

$this->assertSame('Griechenland', $country->name);
}

public function test_locales_as_array_keys_are_properly_detected()
{
$this->app->config->set('translatable.locales', ['en' => ['US','GB']]);

$data = [
'en' => ['name' => 'French fries'],
'en-US' => ['name' => 'American french fries'],
'en-GB' => ['name' => 'Chips'],
];
$frenchFries = Food::create($data);

$this->assertSame('French fries', $frenchFries->getTranslation('en')->name);
$this->assertSame('Chips', $frenchFries->getTranslation('en-GB')->name);
$this->assertSame('American french fries', $frenchFries->getTranslation('en-US')->name);
}

public function test_locale_separator_can_be_configured()
{
$this->app->config->set('translatable.locales', ['en' => ['GB']]);
$this->app->config->set('translatable.locale_separator', '_');
$data = [
'en_GB' => ['name' => 'Chips'],
];
$frenchFries = Food::create($data);

$this->assertSame('Chips', $frenchFries->getTranslation('en_GB')->name);
}

public function test_fallback_for_country_based_locales()
{
$this->app->config->set('translatable.use_fallback', true);
$this->app->config->set('translatable.fallback_locale', 'fr');
$this->app->config->set('translatable.locales', ['en' => ['US', 'GB'], 'fr']);
$this->app->config->set('translatable.locale_separator', '-');
$data = [
'id' => 1,
'fr' => ['name' => 'frites'],
'en-GB' => ['name' => 'chips'],
'en' => ['name' => 'french fries'],
];
Food::create($data);
$fries = Food::find(1);
$this->assertSame('french fries', $fries->getTranslation('en-US')->name);
}
}
17 changes: 17 additions & 0 deletions tests/migrations/2013_11_28_152610_create_tables.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ public function up()
$table->timestamps();
});

Schema::create('foods', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
});

Schema::create('food_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('food_id')->unsigned();
$table->string('name');
$table->string('locale')->index();

$table->unique(['food_id', 'locale']);
$table->foreign('food_id')->references('id')->on('foods')->onDelete('cascade');
});

Schema::create('continent_translations', function (Blueprint $table) {
$table->increments('id');
$table->integer('continent_id')->unsigned();
Expand All @@ -80,5 +95,7 @@ public function down()

Schema::dropIfExists('continent_translations');
Schema::dropIfExists('continents');
Schema::dropIfExists('food_translations');
Schema::dropIfExists('foods');
}
}
49 changes: 49 additions & 0 deletions tests/models/Food.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php namespace Dimsav\Translatable\Test\Model;

use Dimsav\Translatable\Translatable;
use Illuminate\Database\Eloquent\Model as Eloquent;

class Food extends Eloquent
{
use Translatable;

/**
* Array with the fields translated in the Translation table.
*
* @var array
*/
public $translatedAttributes = ['name'];

/**
* Set $translationModel if you want to overwrite the convention
* for the name of the translation Model. Use full namespace if applied.
*
* The convention is to add "Translation" to the name of the class extending Translatable.
* Example: Country => CountryTranslation
*/
public $translationModel;

/**
* This is the foreign key used to define the translation relationship.
* Set this if you want to overwrite the laravel default for foreign keys.
*
* @var
*/
public $translationForeignKey;

/**
* Add your translated attributes here if you want
* fill them with mass assignment.
*
* @var array
*/
public $fillable = ['name'];

/**
* The database field being used to define the locale parameter in the translation model.
* Defaults to 'locale'.
*
* @var string
*/
public $localeKey;
}
8 changes: 8 additions & 0 deletions tests/models/FoodTranslation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php namespace Dimsav\Translatable\Test\Model;

use Illuminate\Database\Eloquent\Model as Eloquent;

class FoodTranslation extends Eloquent
{
public $timestamps = false;
}

0 comments on commit d38db2e

Please sign in to comment.