More work on Translations. Added an admin-page for them-
parent
c33f8004e6
commit
36c711ec6e
32
Router.php
32
Router.php
|
@ -1,14 +1,6 @@
|
|||
<?php
|
||||
|
||||
const PRODUCTION = false;
|
||||
const DEBUG = true;
|
||||
|
||||
if(DEBUG){
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
|
||||
|
||||
// Composer autoload
|
||||
require_once 'vendor/autoload.php';
|
||||
|
@ -35,8 +27,20 @@ $loader = new Twig\Loader\FilesystemLoader(__dir__ . '/templates/'.Config::get('
|
|||
$twig = new Twig\Environment($loader, $twigSettings);
|
||||
|
||||
$filter = new Twig\TwigFilter('t', function ($string) {
|
||||
return _(strip_tags($string));
|
||||
});
|
||||
if(strstr($string, "\n")){
|
||||
$lines = explode("\n", $string);
|
||||
foreach($lines as $line){
|
||||
$line = trim(strip_tags($line));
|
||||
if(!empty($line)){
|
||||
$string = str_replace($line, __($line), $string);
|
||||
}
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
else {
|
||||
return __(strip_tags($string));
|
||||
}
|
||||
}, ['is_safe' => ['html']]);
|
||||
|
||||
$twig->addFilter($filter);
|
||||
|
||||
|
@ -64,6 +68,14 @@ class Config {
|
|||
}
|
||||
}
|
||||
|
||||
define("DEBUG", Config::get('system', 'debug', false));
|
||||
|
||||
if(DEBUG){
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
}
|
||||
|
||||
function model($name){
|
||||
return;
|
||||
if(file_exists(__DIR__ . "/models/" . $name . ".php")){
|
||||
|
|
|
@ -105,6 +105,9 @@ class DB {
|
|||
}
|
||||
}
|
||||
catch (mysqli_sql_exception $e){
|
||||
if($mode == 1){
|
||||
Utils::debug("Database / SQL error: \n". $e->getMessage());
|
||||
}
|
||||
throw new DatabaseException($e->getMessage(), $e->getCode());
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +1,66 @@
|
|||
<?php
|
||||
|
||||
class Translator {
|
||||
public function __construct(){
|
||||
$this->language = "nb";
|
||||
$this->country = "NO";
|
||||
$this->charset = "utf8";
|
||||
use Gettext\Loader\PoLoader; // remove eventually
|
||||
use Gettext\Generator\PoGenerator;
|
||||
use Gettext\Generator\MoGenerator;
|
||||
//use Gettext\Loader\
|
||||
//use Gettext\Translation;
|
||||
use Gettext\Translations;
|
||||
|
||||
$this->locale = $this->language."_".$this->country.".".$this->charset;
|
||||
class Translator {
|
||||
public $language;
|
||||
public $country;
|
||||
public $charset;
|
||||
public $locale;
|
||||
|
||||
public function __construct($language = 'nb', $region = 'NO', $charset = 'utf8'){
|
||||
$this->language = $language;
|
||||
$this->country = $region;
|
||||
$this->charset = $charset;
|
||||
|
||||
$this->locale = $this->language."_".$this->country.".".$this->charset;
|
||||
|
||||
if (defined('LC_MESSAGES')) {
|
||||
setlocale(LC_MESSAGES, $this->locale);
|
||||
|
||||
if(!file_exists(__dir__."/../locale/".$this->locale."/LC_MESSAGES/domain1.mo") || isset($_GET['reloadmo'])){
|
||||
$this::createMo();
|
||||
}
|
||||
|
||||
bindtextdomain("domain1", __dir__."/../locale/nocache");
|
||||
bindtextdomain("domain1", __dir__."/../locale/");
|
||||
} else {
|
||||
echo "IS IN THE ELSE - PART";
|
||||
echo "LC_MESSAGES IS NOT DEFINED...";
|
||||
}
|
||||
|
||||
textdomain("domain1");
|
||||
}
|
||||
|
||||
function createMo(){
|
||||
$translations = Translations::create('domain1');
|
||||
|
||||
foreach(Translation::forLanguage( $this->language ) as $row){
|
||||
$tr = \Gettext\Translation::create($row['context'], $row['original']);
|
||||
$tr->translate($row['localized']);
|
||||
|
||||
$translations->add($tr);
|
||||
}
|
||||
|
||||
$translations->getHeaders()->set('Content-Type', 'text/plain; charset=UTF-8');
|
||||
|
||||
$generator = new MoGenerator();
|
||||
$generator->generateFile($translations, __dir__."/../locale/".$this->locale."/LC_MESSAGES/domain1.mo");
|
||||
|
||||
if(DEBUG){
|
||||
$generator = new PoGenerator();
|
||||
$generator->generateFile($translations, __dir__."/../locale/".$this->locale."/LC_MESSAGES/domain1.po");
|
||||
}
|
||||
}
|
||||
|
||||
static function updateMo($lang, $region){
|
||||
$t = new self($lang, $region);
|
||||
$t->createMo();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -97,9 +141,7 @@ class Translator {
|
|||
*/
|
||||
|
||||
use Gettext\Scanner\PhpScanner;
|
||||
use Gettext\Translations;
|
||||
use Gettext\Generator\PoGenerator;
|
||||
use Gettext\Generator\MoGenerator;
|
||||
//use Gettext\Translations;
|
||||
|
||||
|
||||
class TranslatorScanning {
|
||||
|
@ -159,10 +201,16 @@ class TranslatorScanning {
|
|||
|
||||
|
||||
function __($string, ...$values): string {
|
||||
if(DEBUG){
|
||||
$contexts = array("verb");
|
||||
if(count($values) >= 1 && in_array($string, $contexts)){
|
||||
$string = $string . "\004" . array_shift($values);
|
||||
}
|
||||
|
||||
$newString = gettext($string);
|
||||
if(DEBUG && $string == $newString){
|
||||
logTranslationKey($string);
|
||||
}
|
||||
return sprintf( _($string), $values);
|
||||
return sprintf($newString, $values);
|
||||
}
|
||||
|
||||
function logTranslationKey($string){
|
||||
|
|
|
@ -27,7 +27,7 @@ class Utils {
|
|||
else {
|
||||
echo print_r($arg, true);
|
||||
}
|
||||
echo "</pre>\n";
|
||||
echo "</pre><br />\n";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ class WebPage {
|
|||
|
||||
|
||||
public function __construct(){
|
||||
new Translator();
|
||||
$t = new Translator();
|
||||
|
||||
$this->pr = Config::get('system', 'projectroot', '');
|
||||
$this->loggedIn = Auth::checkLogin();
|
||||
|
@ -89,6 +89,7 @@ class WebPage {
|
|||
function doPost(){ throw new Exception("Incomplete implementation"); }
|
||||
|
||||
function vars(): array {
|
||||
$this->debug = DEBUG;
|
||||
return (array) $this;
|
||||
}
|
||||
|
||||
|
@ -96,9 +97,9 @@ class WebPage {
|
|||
$this->activePage = str_replace('index.php', '', $_SERVER['REQUEST_URI']);
|
||||
|
||||
$this->navbar['links'] = array_merge([
|
||||
["href"=>"/", "name"=>"Home", "active"=>$this->activePage=="/"?'active':''],
|
||||
["href"=>"/plan/", "name"=>"Plan", "active"=>$this->activePage=="/plan/"?'active':''],
|
||||
["href"=>"/review/", "name"=>"Review", "active"=>$this->activePage=="/review/"?'active':'']
|
||||
["href"=>"/", "name"=>__('Home'), "active"=>$this->activePage=="/" ? 'active' : '' ],
|
||||
["href"=>"/plan/", "name"=>__('verb', 'Plan'), "active"=>$this->activePage=="/plan/" ? 'active' : '' ],
|
||||
["href"=>"/review/", "name"=>__('Review'), "active"=>$this->activePage=="/review/" ? 'active' : '' ]
|
||||
], $this->navbar ?? []);
|
||||
}
|
||||
|
||||
|
|
115
models/Model.php
115
models/Model.php
|
@ -1,9 +1,122 @@
|
|||
<?php
|
||||
|
||||
namespace models;
|
||||
//namespace models;
|
||||
|
||||
define("DATABASE", Config::get('database', "database"));
|
||||
|
||||
abstract class Model {
|
||||
protected static $database = DATABASE;
|
||||
protected static $table;
|
||||
protected static $tableExtends = null;
|
||||
protected static $fields;
|
||||
|
||||
public function __construct(){
|
||||
foreach (static::$fields as $field => $type){
|
||||
switch ($type){
|
||||
case "INT":
|
||||
$this->{$field} = 0;
|
||||
break;
|
||||
case "VARCHAR":
|
||||
case "TEXT":
|
||||
default:
|
||||
$this->{$field} = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseException
|
||||
*/
|
||||
public static function get($filter = null){
|
||||
if(!self::verify()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fields = array_keys(static::$fields);
|
||||
|
||||
if(is_array( static::$tableExtends) ){
|
||||
$ext = new static::$tableExtends['model']();
|
||||
|
||||
$fields = array_merge(
|
||||
$fields,
|
||||
array_keys($ext::$fields)
|
||||
);
|
||||
|
||||
$duplicateKeys = array_intersect(array_keys(static::$fields), array_keys($ext::$fields));
|
||||
foreach ($duplicateKeys as $dkey){
|
||||
$fieldsKey = array_search($dkey, $fields);
|
||||
$fields[$fieldsKey] = "t1`.`".$fields[$fieldsKey];
|
||||
|
||||
$fieldsKey = array_search($dkey, $fields);
|
||||
$fields[$fieldsKey] = "t2`.`".$fields[$fieldsKey];
|
||||
}
|
||||
|
||||
$extendSql = sprintf(
|
||||
" LEFT JOIN %s.%s t2 ON t2.%s = t1.%s",
|
||||
$ext::$database,
|
||||
$ext::$table,
|
||||
static::$tableExtends['internalKey'],
|
||||
static::$tableExtends['foreignKey']
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
$args = array();
|
||||
|
||||
$sql = "SELECT `".implode("`, `", $fields)."`";
|
||||
$sql .= " FROM ".static::$database.".".static::$table . " t1";
|
||||
|
||||
$sql .= $extendSql ?? '';
|
||||
|
||||
if(!empty($filter)){
|
||||
$filterSql = array();
|
||||
foreach ($filter as $key => $value){
|
||||
if(is_array($value)){
|
||||
$filterSql[] = sprintf("%s %s ?", $key, $value[0]);
|
||||
$args[] = $value[1];
|
||||
}
|
||||
else {
|
||||
$filterSql[] = "$key = ?";
|
||||
$args[] = $value;
|
||||
}
|
||||
}
|
||||
$sql .= ' WHERE '. implode(',', $filterSql);
|
||||
}
|
||||
|
||||
// if(DEBUG){
|
||||
// $q = DB::queryTest($sql, $args);
|
||||
// }
|
||||
// else {
|
||||
$q = DB::query($sql, $args);
|
||||
// }
|
||||
|
||||
$result = array();
|
||||
while($row = $q->fetch_assoc()){
|
||||
$res = new static();
|
||||
|
||||
/* Alternative for non-joined queries:
|
||||
foreach (static::$fields as $key => $ignore){
|
||||
$res->{ $key } = $row[$key];
|
||||
} /* */
|
||||
|
||||
foreach (array_keys($row) as $col){
|
||||
$res->{ $col } = $row[$col];
|
||||
}
|
||||
$result[] = $res;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function verify(): bool {
|
||||
if(is_array(static::$fields) && !empty(static::$table)){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// public function set($value, )
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
//namespace models;
|
||||
|
||||
class Translation extends Model {
|
||||
// protected static $database = "i18n";
|
||||
protected static $table = "translation";
|
||||
protected static $fields = [
|
||||
"translation_id" => "INT",
|
||||
"original" => "TEXT",
|
||||
"context" => "TEXT",
|
||||
"added" => "DATETIME",
|
||||
];
|
||||
|
||||
static public function forLanguage($lang){
|
||||
$q = DB::query(
|
||||
"SELECT t.context, t.original, ts.localized, ts.added
|
||||
FROM translation_string ts
|
||||
LEFT JOIN translation t on t.translation_id = ts.translation_id
|
||||
WHERE ts.language = ?", $lang);
|
||||
|
||||
$result = array();
|
||||
|
||||
while($row = $q->fetch_assoc()){
|
||||
// $res = new static();
|
||||
// foreach (static::$fields as $key => $ignore){
|
||||
// $res->{ $key } = $row[$key];
|
||||
// }
|
||||
$result[] = $row;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
//namespace models;
|
||||
|
||||
class TranslationString extends Model {
|
||||
protected static $table = "translation_string";
|
||||
protected static $tableExtends = [
|
||||
'model' => 'Translation',
|
||||
'internalKey' => 'translation_id',
|
||||
'foreignKey' => 'translation_id'
|
||||
];
|
||||
|
||||
protected static $fields = [
|
||||
"translation_id" => "INT",
|
||||
"language" => "TEXT",
|
||||
"localized" => "TEXT",
|
||||
"author" => "TEXT",
|
||||
"added" => "DATETIME",
|
||||
"updated" => "DATETIME"
|
||||
];
|
||||
|
||||
public $lang;
|
||||
|
||||
/*static function get($filter){
|
||||
|
||||
return
|
||||
}*/
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
{% extends "assets/base.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container-md">
|
||||
<table class="table bg-white table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{{ 'Context'|t }}</th>
|
||||
<th>{{ 'Original'|t }}</th>
|
||||
<th>{{ 'Localized'|t }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
{% for tr in translations %}
|
||||
<tr>
|
||||
<td>{{ tr.context }}</td>
|
||||
<td>{{ tr.original }}</td>
|
||||
<td>{{ tr.localized }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td><input type="text" class="form-control" /></td>
|
||||
<td>
|
||||
<input type="text" class="form-control" />
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" class="form-control" />
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block endContent %}
|
||||
<script>
|
||||
$("document").ready(()=>{
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -1,7 +1,7 @@
|
|||
{% extends "assets/base.html.twig" %}
|
||||
|
||||
{% block content %}
|
||||
<h1 class="headline text-center"><img src='paperbag_small.svg' style="width: 4rem;" alt='Logo' /> PaperBag</h1>
|
||||
<h1 class="headline text-center"><img src='paperbag_small.svg' style="height: 4rem;" alt='Logo' /> PaperBag</h1>
|
||||
<div class="container-sm" style="padding-top: 5px;">
|
||||
|
||||
<div class="card-group" style="text-align: center;">
|
||||
|
@ -10,12 +10,12 @@
|
|||
<a href='./plan'>
|
||||
<!-- <img src="#" class="card-img-top" alt="Plan">-->
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Plan shopping</h5>
|
||||
<h5 class="card-title">{{ 'Plan shopping'|t }}</h5>
|
||||
<p class="card-text"></p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
{% apply t %}
|
||||
<div class="card h-100" style="">
|
||||
<!-- <img src="#" class="card-img-top" alt="Review">-->
|
||||
<div class="card-body">
|
||||
|
@ -23,18 +23,19 @@
|
|||
<p class="card-text">Coming soon</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endapply %}
|
||||
</div>
|
||||
|
||||
<div class="card-group" style="text-align: center;">
|
||||
<div class="card" style="">
|
||||
<div class="card-body">
|
||||
{% apply t %}
|
||||
<h5 class="card-title">Recent changes</h5>
|
||||
{% endapply %}
|
||||
<pre class="card-text" style="text-align: left; width: min-content; max-width: 100%; margin: auto; max-height: 150px; overflow-y: auto; padding: 0 15px;">{{ changes }}</pre>
|
||||
</div>
|
||||
<div class="card-footer">For more details see the <a href="https://useg.it/eirik/PaperBag/commits/branch/master">commits</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<?php } ?>
|
||||
</div>
|
||||
{% endblock %}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
require '../../Router.php';
|
||||
|
||||
|
||||
class TranslateAdminPage extends WebPage implements RequireAuth {
|
||||
public $pagekey = "translate";
|
||||
public $title = "Translate - PaperBag - Plan & Execute Your Shopping";
|
||||
// public $template = "admin/translate";
|
||||
|
||||
function load(){
|
||||
$this->title = _("Translate - PaperBag - Plan & Execute Your Shopping");
|
||||
|
||||
$this->translations = TranslationString::get([ 'language' => 'nb' ]);
|
||||
}
|
||||
}
|
||||
|
||||
if(false){
|
||||
|
||||
}
|
||||
else {
|
||||
$a = new TranslateAdminPage();
|
||||
}
|
Loading…
Reference in New Issue