* Use language files in json format, in new folder

This commit is contained in:
Max Pozdeev 2020-09-04 14:26:28 +03:00
parent a5cc36ea64
commit 827fc92609
8 changed files with 612 additions and 10 deletions

119
src/includes/class.lang.php Normal file
View file

@ -0,0 +1,119 @@
<?php
/*
myTinyTodo language class
*/
class Lang
{
protected static $instance;
protected $code = 'en';
protected $default = 'en';
protected $langDir = MTTINC. 'lang/';
protected $strings;
public static function instance()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
public static function loadLang($code)
{
$lang = self::instance();
//check if new format (json)
if (file_exists("{$lang->langDir}{$code}.json")) {
$jsonString = file_get_contents("{$lang->langDir}{$code}.json");
$lang->loadJsonString($code, $jsonString);
}
else {
die("Language file not found ($code.json)");
}
}
function loadJsonString($code, $jsonString)
{
$this->code = $code;
$json = json_decode($jsonString, true);
//load default language
if ( $code != $this->default ) {
$defStr = file_get_contents("{$this->langDir}{$this->default}.json");
$default_json = json_decode($defStr, true);
$this->strings = array_replace($default_json, $json);
}
else {
$this->strings = $json;
}
}
function get($key)
{
if ( isset($this->strings[$key]) ) {
return $this->strings[$key];
}
return $key;
}
function rtl()
{
if ( isset($this->strings['_rtl']) ) {
return intval($this->strings['_rtl']);
}
return 0;
}
function makeJS($pretty = 0)
{
$a = array();
$a['daysMin'] = $this->get('days_min');
$a['daysLong'] = $this->get('days_long');
$a['monthsLong'] = $this->get('months_long');
$this->fillWithValues($a, [
'confirmDelete',
'confirmLeave',
'actionNoteSave',
'actionNoteCancel',
'error',
'denied',
'invalidpass',
'addList',
'addListDefault',
'renameList',
'deleteList',
'clearCompleted',
'settingsSaved',
'tags',
'tasks',
'f_past',
'f_today',
'f_soon'
]);
$opts = JSON_UNESCAPED_UNICODE;
if ($pretty) {
$opts |= JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES;
}
return json_encode($a, $opts);
}
protected function fillWithValues(array &$a, array $keys)
{
foreach ( $keys as $key ) {
$a[$key] = $this->get($key);
}
}
function langDir()
{
return $this->langDir;
}
}
?>

View file

@ -0,0 +1 @@
deny from all

169
src/includes/lang/en.json Normal file
View file

@ -0,0 +1,169 @@
{
"_header": {
"ver": "v1.6",
"date": "2020-09-04",
"language": "English",
"original_name": "English",
"author": "Max Pozdeev",
"author_url": "http://www.mytinytodo.net"
},
"My Tiny Todolist": "My Tiny Todolist",
"htab_newtask": "New task",
"htab_search": "Search",
"btn_add": "Add",
"btn_search": "Search",
"advanced_add": "Advanced",
"searching": "Searching for",
"tasks": "Tasks",
"taskdate_inline_created": "created at %s",
"taskdate_inline_completed": "Completed at %s",
"taskdate_inline_duedate": "Due %s",
"taskdate_created": "Created",
"taskdate_completed": "Completed",
"go_back": "&lt;&lt; Back",
"edit_task": "Edit Task",
"add_task": "New Task",
"priority": "Priority",
"task": "Task",
"note": "Note",
"tags": "Tags",
"save": "Save",
"cancel": "Cancel",
"password": "Password",
"btn_login": "Login",
"a_login": "Login",
"a_logout": "Logout",
"public_tasks": "Public Tasks",
"tagcloud": "Tags",
"tagfilter_cancel": "cancel filter",
"sortByHand": "Sort by hand",
"sortByPriority": "Sort by priority",
"sortByDueDate": "Sort by due date",
"sortByDateCreated": "Sort by date created",
"sortByDateModified": "Sort by date modified",
"due": "Due",
"daysago": "%d days ago",
"indays": "in %d days",
"months_short": [
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
],
"months_long": [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
],
"days_min": [
"Su",
"Mo",
"Tu",
"We",
"Th",
"Fr",
"Sa"
],
"days_long": [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday"
],
"today": "today",
"yesterday": "yesterday",
"tomorrow": "tomorrow",
"f_past": "Overdue",
"f_today": "Today and tomorrow",
"f_soon": "Soon",
"action_edit": "Edit",
"action_note": "Edit Note",
"action_delete": "Delete",
"action_priority": "Priority",
"action_move": "Move to",
"notes": "Notes:",
"notes_show": "Show",
"notes_hide": "Hide",
"list_new": "New list",
"list_rename": "Rename list",
"list_delete": "Delete list",
"list_publish": "Publish list",
"list_showcompleted": "Show completed tasks",
"list_clearcompleted": "Clear completed tasks",
"list_select": "Select list",
"list_export": "Export",
"list_export_csv": "CSV",
"list_export_ical": "iCalendar",
"list_rssfeed": "RSS Feed",
"alltags": "All tags:",
"alltags_show": "Show all",
"alltags_hide": "Hide all",
"a_settings": "Settings",
"rss_feed": "RSS Feed",
"feed_title": "%s",
"feed_completed_tasks": "Completed tasks",
"feed_modified_tasks": "Modified tasks",
"feed_new_tasks": "New tasks",
"alltasks": "All tasks",
"set_header": "Settings",
"set_title": "Title",
"set_title_descr": "(specify if you want to change default title)",
"set_language": "Language",
"set_protection": "Password protection",
"set_enabled": "Enabled",
"set_disabled": "Disabled",
"set_newpass": "New password",
"set_newpass_descr": "(leave blank if won't change current password)",
"set_smartsyntax": "Smart syntax",
"set_smartsyntax_descr": "(/priority/ task /tags/)",
"set_timezone": "Time zone",
"set_autotag": "Autotagging",
"set_autotag_descr": "(automatically adds tag of current tag filter to newly created task)",
"set_sessions": "Session handling mechanism",
"set_sessions_php": "PHP",
"set_sessions_files": "Files",
"set_firstdayofweek": "First day of week",
"set_custom": "Custom",
"set_date": "Date format",
"set_date2": "Short Date format",
"set_shortdate": "Short Date (current year)",
"set_clock": "Clock format",
"set_12hour": "12-hour",
"set_24hour": "24-hour",
"set_submit": "Submit changes",
"set_cancel": "Cancel",
"set_showdate": "Show task date in list",
"confirmDelete": "Are you sure you want to delete the task?",
"confirmLeave": "There can be unsaved data. Do you really want to leave?",
"actionNoteSave": "save",
"actionNoteCancel": "cancel",
"error": "Some error occurred (click for details)",
"denied": "Access denied",
"invalidpass": "Wrong password",
"addList": "Create new list",
"addListDefault": "Todo",
"renameList": "Rename list",
"deleteList": "This will delete current list with all tasks in it.\\nAre you sure?",
"clearCompleted": "This will delete all completed tasks in the list.\\nAre you sure?",
"settingsSaved": "Settings saved. Reloading..."
}

169
src/includes/lang/ru.json Normal file
View file

@ -0,0 +1,169 @@
{
"_header": {
"ver": "v1.6",
"date": "2020-09-04",
"language": "Russian",
"original_name": "Русский",
"author": "Max Pozdeev",
"author_url": "http://www.mytinytodo.net"
},
"My Tiny Todolist": "My Tiny Todolist",
"htab_newtask": "Новая задача",
"htab_search": "Поиск",
"btn_add": "Добавить",
"btn_search": "Искать",
"advanced_add": "Расширенная форма",
"searching": "Поиск",
"tasks": "Задачи",
"taskdate_inline_created": "добавлена %s",
"taskdate_inline_completed": "Завершена %s",
"taskdate_inline_duedate": "В срок %s",
"taskdate_created": "Дата создания",
"taskdate_completed": "Дата завершения",
"go_back": "&lt;&lt; Назад",
"edit_task": "Редактирование задачи",
"add_task": "Новая задача",
"priority": "Приоритет",
"task": "Задача",
"note": "Заметка",
"tags": "Теги",
"save": "Сохранить",
"cancel": "Отмена",
"password": "Пароль",
"btn_login": "Войти",
"a_login": "Вход",
"a_logout": "Выйти",
"public_tasks": "Опубликованные задачи",
"tagcloud": "Теги",
"tagfilter_cancel": "отменить фильтр по тегу",
"sortByHand": "Сортировка вручную",
"sortByPriority": "Сортировка по приоритету",
"sortByDueDate": "Сортировка по сроку",
"sortByDateCreated": "Сортировка по дате добавления",
"sortByDateModified": "Сортировка по дате изменения",
"due": "Срок",
"daysago": "%d дн. назад",
"indays": "через %d дн.",
"months_short": [
"Янв",
"Фев",
"Мар",
"Апр",
"Май",
"Июн",
"Июл",
"Авг",
"Сен",
"Окт",
"Ноя",
"Дек"
],
"months_long": [
"Январь",
"Февраль",
"Март",
"Апрель",
"Май",
"Июнь",
"Июль",
"Август",
"Сентябрь",
"Октябрь",
"Ноябрь",
"Декабрь"
],
"days_min": [
"Вс",
"Пн",
"Вт",
"Ср",
"Чт",
"Пт",
"Сб"
],
"days_long": [
"Воскресенье",
"Понедельник",
"Вторник",
"Среда",
"Четверг",
"Пятница",
"Суббота"
],
"today": "сегодня",
"yesterday": "вчера",
"tomorrow": "завтра",
"f_past": "Просроченные",
"f_today": "Сегодня и завтра",
"f_soon": "Скоро",
"action_edit": "Редактировать",
"action_note": "Заметка",
"action_delete": "Удалить",
"action_priority": "Приоритет",
"action_move": "Переместить в",
"notes": "Заметки:",
"notes_show": "Показать",
"notes_hide": "Скрыть",
"list_new": "Новый список",
"list_rename": "Переименовать список",
"list_delete": "Удалить список",
"list_publish": "Опубликовать список",
"list_showcompleted": "Показать завершенные задачи",
"list_clearcompleted": "Удалить завершенные задачи",
"list_select": "Выбрать список",
"list_export": "Экспортировать",
"list_export_csv": "CSV",
"list_export_ical": "iCalendar",
"list_rssfeed": "RSS-лента",
"alltags": "Все теги:",
"alltags_show": "Показать все",
"alltags_hide": "Скрыть все",
"a_settings": "Настройки",
"rss_feed": "RSS-лента",
"feed_title": "%s",
"feed_completed_tasks": "Завершенные задачи",
"feed_modified_tasks": "Изменившиеся задачи",
"feed_new_tasks": "Новые задачи",
"alltasks": "Все задачи",
"set_header": "Настройки",
"set_title": "Заголовок страницы",
"set_title_descr": "(если поле не заполнено, будет использован заголовок по-умолчанию)",
"set_language": "Язык (Language)",
"set_protection": "Парольная защита",
"set_enabled": "Включено",
"set_disabled": "Выключено",
"set_newpass": "Новый пароль",
"set_newpass_descr": "(не заполняйте поле если не хотите менять текущий пароль)",
"set_smartsyntax": "Smart syntax",
"set_smartsyntax_descr": "(возможность использовать синтаксис: /приоритет/ задача /теги/)",
"set_timezone": "Часовой пояс",
"set_autotag": "Autotagging",
"set_autotag_descr": "(автодобавление текущего тега из фильтра в новую задачу)",
"set_sessions": "Хранилище сессий",
"set_sessions_php": "PHP",
"set_sessions_files": "Файлы",
"set_firstdayofweek": "Первый день недели",
"set_custom": "другой",
"set_date": "Формат даты",
"set_date2": "Формат короткой даты",
"set_shortdate": "Короткая дата (в текущем году)",
"set_clock": "Формат часов",
"set_12hour": "12-часовой",
"set_24hour": "24-часовой",
"set_submit": "Сохранить изменения",
"set_cancel": "Отмена",
"set_showdate": "Показывать дату создания задачи",
"confirmDelete": "Вы действительно хотите удалить задачу?",
"confirmLeave": "На странице могут быть несохраненные данные. Вы действительно хотите закрыть страницу?",
"actionNoteSave": "сохранить",
"actionNoteCancel": "отмена",
"error": "Ошибка",
"denied": "Доступ запрещен",
"invalidpass": "Неверный пароль",
"addList": "Новый список",
"addListDefault": "Todo",
"renameList": "Переименовать список",
"deleteList": "Вы действительно хотите удалить этот список со всеми задачами?",
"clearCompleted": "Удалить все выполненные задачи из списка?",
"settingsSaved": "Настройки сохранены. Перезагрузка..."
}

View file

@ -13,6 +13,7 @@ if (version_compare(PHP_VERSION, '5.4.0') < 0) {
}
if(!defined('MTTPATH')) define('MTTPATH', dirname(__FILE__) .'/');
if(!defined('MTTINC')) define('MTTINC', MTTPATH. 'includes/');
require_once(MTTPATH. 'common.php');
require_once(MTTPATH. 'db/config.php');
@ -57,8 +58,8 @@ if(isset($_COOKIE['lang']) && preg_match("/^[a-z-]+$/i", $_COOKIE['lang']) && fi
Config::set('lang', $_COOKIE['lang']);
}
require_once(MTTPATH. 'lang/class.default.php');
require_once(MTTPATH. 'lang/'.Config::get('lang').'.php');
require_once(MTTINC. 'class.lang.php');
Lang::loadLang(Config::get('lang'));
$_mttinfo = array();

View file

@ -186,7 +186,7 @@ class DefaultLang
return $this->rtl ? 1 : 0;
}
public static function instance()
public static function instance_deprecated()
{
if (!isset(self::$instance)) {
//$c = __CLASS__;
@ -195,6 +195,82 @@ class DefaultLang
}
return self::$instance;
}
public function json($langFile = '', $pretty = 0)
{
$a = array();
if ($langFile != '') {
$ah = $this->loadLangHeader($langFile);
$a['_header'] = $ah;
}
if ($this->rtl()) {
$a['_rtl'] = $this->rtl();
}
foreach ( $this->default_inc as $k=>$v ) {
if ( isset($this->inc[$k]) ) {
$v = $this->inc[$k];
}
$a[$k] = $v;
}
foreach ( $this->default_js as $k=>$v ) {
if ( isset($this->js[$k]) ) {
$v = $this->js[$k];
}
$a[$k] = $v;
}
$encOptions = JSON_UNESCAPED_UNICODE;;
if ($pretty) {
$encOptions |= JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES;
}
return json_encode($a, $encOptions);
}
function loadLangHeader($langFile)
{
if (!file_exists($langFile)) {
die("file does not exist: $langFile");
}
$contents = file_get_contents($langFile);
$a = array();
# parse head comment
if(preg_match("|/\\*\s*myTinyTodo language pack([\s\S]+?)\\*/|", $contents, $m))
{
$str = $m[1];
if(preg_match("|AppVersion\s*:\s*(.+)|i", $str, $m)) {
$a['ver'] = trim($m[1]);
}
if(preg_match("|Date\s*:\s*(.+)|i", $str, $m)) {
$a['date'] = trim($m[1]);
}
if(preg_match("|Language\s*:\s*(.+)|i", $str, $m)) {
$a['language'] = trim($m[1]);
}
if(preg_match("|Original name\s*:\s*(.+)|i", $str, $m)) {
$a['original_name'] = trim($m[1]);
}
if(preg_match("|Author\s*:\s*(.+)|i", $str, $m)) {
$a['author'] = trim($m[1]);
}
if(preg_match("|Author URL\s*:(.+)|i", $str, $m)) {
$a['author_url'] = trim($m[1]);
}
if(preg_match("|Author Email\s*:(.+)|i", $str, $m)) {
$a['author_email'] = trim($m[1]);
}
if(preg_match("|Modified by\s*:(.+)|i", $str, $m)) {
$a['modified_by'] = trim($m[1]);
}
}
return $a;
}
}
?>

View file

@ -1,12 +1,30 @@
<?php
// Deprecated! Will be removed in the next major version!
if(!defined('MTTPATH')) define('MTTPATH', dirname(__FILE__) .'/');
if(!defined('MTTINC')) define('MTTINC', MTTPATH. 'includes/');
require_once(MTTPATH. 'db/config.php');
require_once(MTTPATH. 'lang/class.default.php');
require_once(MTTPATH. 'lang/'. $config['lang']. '.php');
if(isset($_GET['lang']) && preg_match("/^[a-z-]+$/i", $_GET['lang']) && file_exists(MTTPATH. 'lang/'. $_GET['lang']. '.php')) {
$config['lang'] = $_GET['lang'];
}
if ( isset($_GET['json']) || isset($_GET['jsonfile']) ) {
require_once(MTTPATH. 'lang/class.default.php');
require_once(MTTPATH. 'lang/'. $config['lang']. '.php');
header('Content-type: application/json; charset=utf-8');
if ( isset($_GET['jsonfile']) ) {
header('Content-disposition: attachment; filename='. urlencode($config['lang']). '.json');
}
echo Lang::instance_deprecated()->json('lang/'. $config['lang']. '.php', 1);
exit;
}
require_once(MTTINC. 'class.lang.php');
Lang::loadLang($config['lang']);
header('Content-type: text/javascript; charset=utf-8');
echo "mytinytodo.lang.init(". Lang::instance()->makeJS() .");";
echo "mytinytodo.lang.init(". Lang::instance()->makeJS(1) .");";
?>

View file

@ -55,6 +55,9 @@ if(isset($_POST['save']))
jsonExit($t);
}
$oldLangs = getOldLangs(1);
if (is_array($oldLangs) && count($oldLangs) == 0) $oldLangs = 0;
function _c($key)
{
@ -62,6 +65,37 @@ function _c($key)
}
function getLangs($withContents = 0)
{
$langDir = Lang::instance()->langDir();
if ( ! $h = opendir($langDir) ) {
return false;
}
$a = array();
while ( false !== ($file = readdir($h)) )
{
if ( preg_match('/(.+)\.json$/', $file, $m) ) {
$jsonText = file_get_contents($langDir. $file);
if (false === $jsonText) {
die("false ");
continue;
}
$a[$m[1]] = $m[1];
$j = json_decode($jsonText, true);
if ( isset($j['_header']['language']) && isset($j['_header']['original_name']) ) {
$a[$m[1]]= [
'name' => $j['_header']['original_name'],
'title' => $j['_header']['language']
];
}
}
}
closedir($h);
return $a;
}
/* deprecated */
function getOldLangs($withContents = 0)
{
if (!$h = opendir(MTTPATH. 'lang')) return false;
$a = array();
@ -70,7 +104,7 @@ function getLangs($withContents = 0)
if(preg_match('/(.+)\.php$/', $file, $m) && $file != 'class.default.php') {
$a[$m[1]] = $m[1];
if($withContents) {
$a[$m[1]] = getLangDetails(MTTPATH. 'lang'. DIRECTORY_SEPARATOR. $file, $m[1]);
$a[$m[1]] = getOldLangDetails(MTTPATH. 'lang'. DIRECTORY_SEPARATOR. $file, $m[1]);
$a[$m[1]]['name'] = $a[$m[1]]['original_name'];
$a[$m[1]]['title'] = $a[$m[1]]['language'];
}
@ -80,7 +114,8 @@ function getLangs($withContents = 0)
return $a;
}
function getLangDetails($filename, $default)
/* deprecated */
function getOldLangDetails($filename, $default)
{
$contents = file_get_contents($filename);
$a = array('language'=>$default, 'original_name'=>$default);
@ -156,7 +191,21 @@ header('Content-type:text/html; charset=utf-8');
<tr>
<th><?php _e('set_language');?>:</th>
<td> <select name="lang"><?php echo selectOptionsA(getLangs(1), _c('lang')); ?></select> </td>
<td>
<select name="lang"><?php echo selectOptionsA(getLangs(), _c('lang')); ?></select>
<?php if ($oldLangs) { ?>
<br><br>
<b>Notice!</b> You can use old language files after downloading in the new format and copying to the <i>/includes/lang/</i> folder.<br>
<select id="mtt_old_langs"><?php echo selectOptionsA( $oldLangs, _c('lang'), 'en'); ?></select>
<a id="mtt_old_langs_link" href="<?php mttinfo('mtt_url')?>mytinytodo_lang.php?jsonfile">Download json file</a>
<script type="text/javascript">
$('#mtt_old_langs').on('change', function(){
$('#mtt_old_langs_link').attr('href', mytinytodo.mttUrl + 'mytinytodo_lang.php?jsonfile&lang=' + $(this).val());
});
$('#mtt_old_langs_link').attr('href', mytinytodo.mttUrl + 'mytinytodo_lang.php?jsonfile&lang=' + $('#mtt_old_langs').val());
</script>
<?php } ?>
</td>
</tr>
<tr>