Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
hpolthof committed Jun 10, 2015
1 parent e31cf22 commit 99a2e9e
Show file tree
Hide file tree
Showing 7 changed files with 314 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/vendor
composer.lock
.idea
29 changes: 29 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "hpolthof/laravel-translations-db",
"description": "A database translations implementation for Laravel 5.",
"license": "GPL2",
"keywords": ["laravel", "translation", "localization", "database"],
"authors": [
{
"name": "Paul Olthof",
"email": "[email protected]"
}
],
"require": {
"php": ">=5.4.0",
"illuminate/translation": "5.*",
"illuminate/database": "5.*",
"illuminate/cache": "5.*"
},

"autoload": {
"psr-4": {
"Hpolthof\\Translation\\": "src"
}
},
"extra": {
"branch-alias": {
"dev-master": "0.1.x-dev"
}
}
}
40 changes: 40 additions & 0 deletions database/migrations/2015_06_10_144817_add_translations_table.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class AddTranslationsTable extends Migration {

/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('translations', function(Blueprint $table)
{
$table->increments('id');
$table->string('locale');
$table->string('group');
$table->string('name');
$table->text('value')->nullable();
$table->timestamp('viewed_at')->nullable();
$table->timestamps();

$table->index(['locale', 'group']);
$table->unique(['locale', 'group', 'name']);
});
}

/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('translations');
}

}
77 changes: 77 additions & 0 deletions src/DatabaseLoader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
<?php namespace Hpolthof\Translation;

use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Translation\LoaderInterface;

class DatabaseLoader implements LoaderInterface {

/**
* Load the messages for the given locale.
*
* @param string $locale
* @param string $group
* @param string $namespace
* @return array
*/
public function load($locale, $group, $namespace = null)
{
return \DB::table('translations')
->where('locale', $locale)
->where('group', $group)
->lists('value', 'name');
}

/**
* Add a new namespace to the loader.
* This function will not be used but is required
* due to the LoaderInterface.
* We'll just leave it here as is.
*
* @param string $namespace
* @param string $hint
* @return void
*/
public function addNamespace($namespace, $hint) {}

/**
* Adds a new translation to the database or
* updates an existing record if the viewed_at
* updates are allowed.
*
* @param string $locale
* @param string $group
* @param string $name
* @return void
*/
public function addTranslation($locale, $group, $key)
{
if(!\Config::get('app.debug')) return;

// Extract the real key from the translation.
if (preg_match("/^{$group}\.(.*?)$/sm", $key, $match)) {
$name = $match[1];
} else {
throw new TranslationException('Could not extract key from translation.');
}

$item = \DB::table('translations')
->where('locale', $locale)
->where('group', $group)
->where('name', $name)->first();

$data = compact('locale', 'group', 'name');
$data = array_merge($data, [
'viewed_at' => date_create(),
'updated_at' => date_create(),
]);

if($item === null) {
$data = array_merge($data, [
'created_at' => date_create(),
]);
\DB::table('translations')->insert($data);
} else {
\DB::table('translations')->where('id', $item->id)->update($data);
}
}
}
80 changes: 80 additions & 0 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php namespace Hpolthof\Translation;

use Illuminate\Translation\FileLoader;

class ServiceProvider extends \Illuminate\Translation\TranslationServiceProvider {

/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = true;

/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerDatabase();
$this->registerLoader();

$this->app->singleton('translator', function($app)
{
$loader = $app['translation.loader'];
$database = $app['translation.database'];

// When registering the translator component, we'll need to set the default
// locale as well as the fallback locale. So, we'll grab the application
// configuration so we can easily get both of these values from there.
$locale = $app['config']['app.locale'];

$trans = new Translator($database, $loader, $locale);

$trans->setFallback($app['config']['app.fallback_locale']);

return $trans;
});
}

public function boot()
{
$this->publishes([
__DIR__.'/../database/migrations/' => database_path('/migrations')
], 'migrations');
}

/**
* Register the translation line loader.
*
* @return void
*/
protected function registerLoader()
{
$this->app->singleton('translation.loader', function($app)
{
return new FileLoader($app['files'], $app['path.lang']);
});
}

protected function registerDatabase()
{
$this->app->singleton('translation.database', function($app)
{
return new DatabaseLoader();
});
}

/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return array('translator', 'translation.loader', 'translation.database');
}

}
5 changes: 5 additions & 0 deletions src/TranslationException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<?php namespace Hpolthof\Translation;;

class TranslationException extends \RuntimeException {

}
80 changes: 80 additions & 0 deletions src/Translator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
<?php namespace Hpolthof\Translation;;

use Illuminate\Translation\LoaderInterface;
use Symfony\Component\Translation\TranslatorInterface;

class Translator extends \Illuminate\Translation\Translator implements TranslatorInterface {

public function __construct(LoaderInterface $database, LoaderInterface $loader, $locale)
{
$this->database = $database;
parent::__construct($loader, $locale);
}

protected static function isNamespaced($namespace)
{
return !(is_null($namespace) || $namespace == '*');
}

/**
* Get the translation for the given key.
*
* @param string $key
* @param array $replace
* @param string $locale
* @return string
*/
public function get($key, array $replace = array(), $locale = null)
{
list($namespace, $group, $item) = $this->parseKey($key);

// Here we will get the locale that should be used for the language line. If one
// was not passed, we will use the default locales which was given to us when
// the translator was instantiated. Then, we can load the lines and return.
foreach ($this->parseLocale($locale) as $locale)
{
if(!self::isNamespaced($namespace)) {
// Database stuff
$this->database->addTranslation($locale, $group, $key);
}

$this->load($namespace, $group, $locale);

$line = $this->getLine(
$namespace, $group, $locale, $item, $replace
);

if ( ! is_null($line)) break;
}

// If the line doesn't exist, we will return back the key which was requested as
// that will be quick to spot in the UI if language keys are wrong or missing
// from the application's language files. Otherwise we can return the line.
if ( ! isset($line)) return $key;

return $line;
}

public function load($namespace, $group, $locale)
{
if ($this->isLoaded($namespace, $group, $locale)) return;

// If a Namespace is give the Filesystem will be used
// otherwise we'll use our database.
// This will allow legacy support.
if(!self::isNamespaced($namespace)) {
// If debug is off then cache the result forever to ensure high performance.
if(!\Config::get('app.debug')) {
$that = $this;
$lines = \Cache::rememberForever('__translations.'.$locale.'.'.$group, function() use ($that, $locale, $group, $namespace) {
return $this->database->load($locale, $group, $namespace);
});
} else {
$lines = $this->database->load($locale, $group, $namespace);
}
} else {
$lines = $this->loader->load($locale, $group, $namespace);
}
$this->loaded[$namespace][$group][$locale] = $lines;
}
}

0 comments on commit 99a2e9e

Please sign in to comment.