More work on Translations. Added an admin-page for them-

templating
Eirik Th S 2022-07-23 01:40:57 +02:00
parent c33f8004e6
commit 36c711ec6e
11 changed files with 337 additions and 33 deletions

View File

@ -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")){

View File

@ -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());
}

View File

@ -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){

View File

@ -27,7 +27,7 @@ class Utils {
else {
echo print_r($arg, true);
}
echo "</pre>\n";
echo "</pre><br />\n";
}
}
}

View File

@ -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 ?? []);
}

View File

@ -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, )

34
models/Translation.php Normal file
View File

@ -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;
}
}

View File

@ -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
}*/
}

View File

@ -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 %}

View File

@ -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 %}

23
www/admin/translate.php Normal file
View File

@ -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();
}