diff --git a/README.md b/README.md index c889899..2784065 100644 --- a/README.md +++ b/README.md @@ -122,6 +122,7 @@ A more complex example including database table with multilingual support is bel 'connection' => 'db', // connection identifier 'table' => '{{%language}}', // table name 'columns' => ['name', 'name_ascii'],// names of multilingual fields + 'synchronize' => true, // save translates on changing source value. Translates will have 'pending' status till update. 'category' => 'database-table-name',// the category is the database table name ] ], @@ -582,4 +583,4 @@ The MIT License (MIT). Please see [License File](LICENSE.md) for more informatio [ico-downloads]: https://img.shields.io/packagist/dt/lajax/yii2-translate-manager.svg?style=flat [link-packagist]: https://packagist.org/packages/lajax/yii2-translate-manager -[link-downloads]: https://packagist.org/packages/lajax/yii2-translate-manager \ No newline at end of file +[link-downloads]: https://packagist.org/packages/lajax/yii2-translate-manager diff --git a/assets/javascripts/translate.js b/assets/javascripts/translate.js index 47c6f07..c80b5af 100644 --- a/assets/javascripts/translate.js +++ b/assets/javascripts/translate.js @@ -16,7 +16,7 @@ var translate = (function () { */ function _translateLanguage($this) { var $translation = $this.closest('tr').find('.translation'); - + $this.closest('tr').find('.pending-label').remove(); var data = { id: $translation.data('id'), language_id: $('#language_id').val(), diff --git a/assets/stylesheets/language.css b/assets/stylesheets/language.css index 9a28a81..aecb172 100644 --- a/assets/stylesheets/language.css +++ b/assets/stylesheets/language.css @@ -10,10 +10,18 @@ span.statistic { position:relative; cursor:help; } -span.statistic span { +span.statistic span.done { height:18px; background:#5CB85C; display:block; + float: left; +} + +span.statistic span.pending { + height:18px; + background:#F0D91B; + display:block; + float: left; } span.statistic i { @@ -22,4 +30,4 @@ span.statistic i { top:0; right:5px; font-weight:bold; -} \ No newline at end of file +} diff --git a/controllers/actions/SaveAction.php b/controllers/actions/SaveAction.php index e4c92f7..6c7448e 100644 --- a/controllers/actions/SaveAction.php +++ b/controllers/actions/SaveAction.php @@ -27,12 +27,30 @@ public function run() $id = Yii::$app->request->post('id', 0); $languageId = Yii::$app->request->post('language_id', Yii::$app->language); + $translation = Yii::$app->request->post('translation', ''); + + $languageTranslate = LanguageTranslate::findOne(['id' => $id, 'language' => $languageId]); + + $regenerate = false; + + if (trim($translation) == '') { + if ($languageTranslate && $languageTranslate->delete()) { + $regenerate = true; + } else { + return []; + } + } else { + $languageTranslate = $languageTranslate ?: + new LanguageTranslate(['id' => $id, 'language' => $languageId]); + $languageTranslate->translation = $translation; + $languageTranslate->status = 'done'; + + if ($languageTranslate->validate() && $languageTranslate->save()) { + $regenerate = true; + } + } - $languageTranslate = LanguageTranslate::findOne(['id' => $id, 'language' => $languageId]) ?: - new LanguageTranslate(['id' => $id, 'language' => $languageId]); - - $languageTranslate->translation = Yii::$app->request->post('translation', ''); - if ($languageTranslate->validate() && $languageTranslate->save()) { + if ($regenerate) { $generator = new Generator($this->controller->module, $languageId); $generator->run(); diff --git a/controllers/actions/ScanAction.php b/controllers/actions/ScanAction.php index 54e5d40..abaa7a4 100644 --- a/controllers/actions/ScanAction.php +++ b/controllers/actions/ScanAction.php @@ -36,10 +36,12 @@ public function run() $scanner->run(); $newDataProvider = $this->controller->createLanguageSourceDataProvider($scanner->getNewLanguageElements()); + $updatedDataProvider = $this->_createLanguageSourceDataProvider($scanner->getUpdatedLanguageSourceIds()); $oldDataProvider = $this->_createLanguageSourceDataProvider($scanner->getRemovableLanguageSourceIds()); return $this->controller->render('scan', [ 'newDataProvider' => $newDataProvider, + 'updatedDataProvider' => $updatedDataProvider, 'oldDataProvider' => $oldDataProvider, ]); } diff --git a/migrations/m200811_080242_synchronization.php b/migrations/m200811_080242_synchronization.php new file mode 100644 index 0000000..8ebcedc --- /dev/null +++ b/migrations/m200811_080242_synchronization.php @@ -0,0 +1,22 @@ + + * + * @since 1.0 + */ +class m200811_080242_synchronization extends Migration +{ + public function up() + { + $this->addColumn('language_source', 'sync_id', $this->string(256)->defaultValue('')->after('id')); + $this->addColumn('language_translate', 'status', $this->string(15)->defaultValue('done')->after('id')); + } + + public function down() + { + $this->dropColumn('language_source', 'sync_id'); + $this->dropColumn('language_translate', 'status'); + } +} diff --git a/models/Language.php b/models/Language.php index c3add78..58370b3 100644 --- a/models/Language.php +++ b/models/Language.php @@ -174,17 +174,16 @@ public function getGridStatistic() } $languageTranslates = LanguageTranslate::find() - ->select(['language', 'COUNT(*) AS cnt']) + ->select(['language', 'status', 'COUNT(*) AS cnt']) ->andWhere('translation IS NOT NULL') - ->groupBy(['language']) + ->groupBy(['language', 'status']) ->all(); - foreach ($languageTranslates as $languageTranslate) { - $statistics[$languageTranslate->language] = floor(($languageTranslate->cnt / $count) * 100); + $statistics[$languageTranslate->language][$languageTranslate->status] = floor(($languageTranslate->cnt / $count) * 100); } } - return isset($statistics[$this->language_id]) ? $statistics[$this->language_id] : 0; + return isset($statistics[$this->language_id]) ? array_merge(['done' => 0, 'pending' => 0], $statistics[$this->language_id]) : ['done' => 0, 'pending' => 0]; } /** diff --git a/models/LanguageSource.php b/models/LanguageSource.php index 25a916e..5ac87db 100644 --- a/models/LanguageSource.php +++ b/models/LanguageSource.php @@ -14,6 +14,7 @@ * This is the model class for table "language_source". * * @property string $id + * @property string $sync_id * @property string $category * @property string $message * @property string $source @@ -54,6 +55,7 @@ public function rules() return [ [['message'], 'string'], [['category'], 'string', 'max' => 32], + [['sync_id'], 'string', 'max' => 256], ]; } @@ -64,6 +66,7 @@ public function attributeLabels() { return [ 'id' => Yii::t('model', 'ID'), + 'sync_id' => Yii::t('model', 'Sync ID'), 'category' => Yii::t('model', 'Category'), 'message' => Yii::t('model', 'Message'), ]; @@ -80,10 +83,11 @@ public function insertLanguageItems($languageItems) { $data = []; foreach ($languageItems as $category => $messages) { - foreach (array_keys($messages) as $message) { + foreach ($messages as $message => $sync_id) { $data[] = [ + $sync_id === true ? '' : $sync_id, $category, - $message, + $message ]; } } @@ -92,7 +96,7 @@ public function insertLanguageItems($languageItems) for ($i = 0; $i < $count; $i += self::INSERT_LANGUAGE_ITEMS_LIMIT) { static::getDb() ->createCommand() - ->batchInsert(static::tableName(), ['category', 'message'], array_slice($data, $i, self::INSERT_LANGUAGE_ITEMS_LIMIT)) + ->batchInsert(static::tableName(), ['sync_id', 'category', 'message'], array_slice($data, $i, self::INSERT_LANGUAGE_ITEMS_LIMIT)) ->execute(); } diff --git a/models/LanguageTranslate.php b/models/LanguageTranslate.php index 4d9cd75..54f9a49 100644 --- a/models/LanguageTranslate.php +++ b/models/LanguageTranslate.php @@ -14,6 +14,7 @@ * This is the model class for table "language_translate". * * @property string $id + * @property string $status * @property string $language * @property string $translation * @property LanguageSource $LanguageSource @@ -58,6 +59,7 @@ public function rules() [['language'], 'exist', 'targetClass' => '\lajax\translatemanager\models\Language', 'targetAttribute' => 'language_id'], [['translation'], 'string'], [['language'], 'string', 'max' => 5], + [['status'], 'string', 'max' => 15], ]; } @@ -68,6 +70,7 @@ public function attributeLabels() { return [ 'id' => Yii::t('model', 'ID'), + 'status' => Yii::t('model', 'Status'), 'language' => Yii::t('model', 'Language'), 'translation' => Yii::t('model', 'Translation'), ]; diff --git a/services/Optimizer.php b/services/Optimizer.php index 65e525f..c692656 100644 --- a/services/Optimizer.php +++ b/services/Optimizer.php @@ -4,6 +4,7 @@ use yii\helpers\Console; use lajax\translatemanager\models\LanguageSource; +use lajax\translatemanager\models\LanguageTranslate; /** * Optimizer class for optimizing database tables @@ -53,6 +54,9 @@ public function run() LanguageSource::deleteAll(['id' => $languageSourceIds]); + $numberOfDeletetRows = LanguageTranslate::deleteAll(['translation' => '']); + $this->_scanner->stdout('Removed empty elements - ' . $numberOfDeletetRows, Console::FG_RED); + $this->_scanner->stdout('Deleted language elements - END', Console::FG_RED); return count($languageSourceIds); diff --git a/services/Scanner.php b/services/Scanner.php index 7061590..92491cd 100644 --- a/services/Scanner.php +++ b/services/Scanner.php @@ -45,6 +45,16 @@ class Scanner */ private $_languageElements = []; + /** + * @var array for storing updatable LanguageSource ids. + */ + private $_updatableLanguageSourceIds = []; + + /** + * @var array for storing updated LanguageSource ids. + */ + private $_updatedLanguageSourceIds = []; + /** * @var array for storing removabla LanguageSource ids. */ @@ -104,7 +114,17 @@ public function getNewLanguageElements() */ public function getRemovableLanguageSourceIds() { - return $this->_removableLanguageSourceIds; + return array_diff_key($this->_removableLanguageSourceIds, $this->_updatableLanguageSourceIds); + } + + /** + * Returns removable LanguageSource ids. + * + * @return array + */ + public function getUpdatedLanguageSourceIds() + { + return $this->_updatedLanguageSourceIds; } /** @@ -133,7 +153,7 @@ private function _initLanguageArrays() foreach ($languageSources as $languageSource) { if (isset($this->_languageElements[$languageSource->category][$languageSource->message])) { unset($this->_languageElements[$languageSource->category][$languageSource->message]); - } else { + } elseif(empty($this->_updatableLanguageSourceIds[$languageSource->id])) { $this->_removableLanguageSourceIds[$languageSource->id] = $languageSource->id; } } @@ -156,9 +176,29 @@ private function _scanningProject() * @param string $category * @param string $message */ - public function addLanguageItem($category, $message) + public function addLanguageItem($category, $message, $sync_id = true) { - $this->_languageElements[$category][$message] = true; + $updated = false; + if($sync_id !== true) { + $LanguageSource = LanguageSource::findOne(['sync_id' => $sync_id, 'category' => $category]); + if($LanguageSource) { + $updated = true; + if($LanguageSource->message !== $message) { + $LanguageSource->message = $message; + if($LanguageSource->save()) { + $this->_updatedLanguageSourceIds[$LanguageSource->id] = $LanguageSource->id; + foreach($LanguageSource->languageTranslates as $LanguageTranslate) { + $LanguageTranslate->status = 'pending'; + $LanguageTranslate->save(); + } + } + } + $this->_updatableLanguageSourceIds[$LanguageSource->id] = $LanguageSource->id; + } + } + if($sync_id === true || !$updated) { + $this->_languageElements[$category][$message] = $sync_id; + } $coloredCategory = Console::ansiFormat($category, [Console::FG_YELLOW]); $coloredMessage = Console::ansiFormat($message, [Console::FG_YELLOW]); @@ -176,11 +216,12 @@ public function addLanguageItem($category, $message) * [ * [ * 'category' => 'language', - * 'message' => 'Active' + * 'message' => 'Active', * ], * [ * 'category' => 'language', * 'message' => 'Inactive' + * 'sync_id' => 'blog_title_8436', * ], * ] * ~~~ @@ -188,7 +229,7 @@ public function addLanguageItem($category, $message) public function addLanguageItems($languageItems) { foreach ($languageItems as $languageItem) { - $this->addLanguageItem($languageItem['category'], $languageItem['message']); + $this->addLanguageItem($languageItem['category'], $languageItem['message'], $languageItem['sync_id'] ?? true); } } diff --git a/services/scanners/ScannerDatabase.php b/services/scanners/ScannerDatabase.php index 419a121..3904f9b 100644 --- a/services/scanners/ScannerDatabase.php +++ b/services/scanners/ScannerDatabase.php @@ -90,15 +90,27 @@ private function _scanningTable($tables) { $this->_scanner->stdout('Extracting mesages from ' . $tables['table'] . '.' . implode(',', $tables['columns']), Console::FG_GREEN); $query = new \yii\db\Query(); - $data = $query->select($tables['columns']) + $selectColumns = $tables['columns']; + + if($tables['synchronize']) { + $pkFields = Yii::$app->{$tables['connection']} + ->createCommand('SHOW INDEX FROM '.$tables['table'].' WHERE Key_name = \'PRIMARY\' ')->queryAll(); + $pkFields = array_map(function ($e) { + return $e['Column_name']; + }, $pkFields); + $selectColumns = array_merge($pkFields, $selectColumns); + } + + $data = $query->select($selectColumns) ->from($tables['table']) ->createCommand(Yii::$app->{$tables['connection']}) ->queryAll(); $category = $this->_getCategory($tables); - foreach ($data as $columns) { - $columns = array_map('trim', $columns); - foreach ($columns as $column) { - $this->_scanner->addLanguageItem($category, $column); + foreach ($data as $dataRow) { + $dataRow = array_map('trim', $dataRow); + foreach ($tables['columns'] as $scanedColumn) { + $sync_id = $tables['synchronize'] ? implode('_', array_slice($dataRow, 0, sizeof($pkFields))).'_'.$scanedColumn : true; + $this->_scanner->addLanguageItem($category, $dataRow[$scanedColumn], $sync_id); } } } diff --git a/views/language/__scanNew.php b/views/language/__scanList.php similarity index 71% rename from views/language/__scanNew.php rename to views/language/__scanList.php index 3e7518f..59a232c 100644 --- a/views/language/__scanNew.php +++ b/views/language/__scanList.php @@ -6,19 +6,19 @@ */ /* @var $this \yii\web\View */ -/* @var $newDataProvider \yii\data\ArrayDataProvider */ +/* @var $dataProvider \yii\data\ArrayDataProvider */ use yii\grid\GridView; ?> -totalCount > 0) : ?> +totalCount > 0) : ?> = GridView::widget([ 'id' => 'added-source', - 'dataProvider' => $newDataProvider, + 'dataProvider' => $dataProvider, 'columns' => [ ['class' => 'yii\grid\SerialColumn'], 'category', diff --git a/views/language/list.php b/views/language/list.php index defccc4..5030633 100644 --- a/views/language/list.php +++ b/views/language/list.php @@ -44,7 +44,11 @@ 'format' => 'raw', 'attribute' => Yii::t('language', 'Statistic'), 'content' => function ($language) { - return '' . $language->gridStatistic . '%'; + return ' + + + ' . $language->gridStatistic['done'] . '% + '; }, ], [ @@ -63,4 +67,4 @@ ]); Pjax::end(); ?> - \ No newline at end of file + diff --git a/views/language/scan.php b/views/language/scan.php index f194122..9c135c2 100644 --- a/views/language/scan.php +++ b/views/language/scan.php @@ -18,8 +18,16 @@ = Yii::t('language', '{n, plural, =0{No new entries} =1{One new entry} other{# new entries}} were added!', ['n' => $newDataProvider->totalCount]) ?> -= $this->render('__scanNew', [ - 'newDataProvider' => $newDataProvider, += $this->render('__scanList', [ + 'dataProvider' => $newDataProvider, +]) ?> + +