Index: Makefile.classic ================================================================== --- Makefile.classic +++ Makefile.classic @@ -36,11 +36,11 @@ #TCC = gcc -O6 #TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage TCC = gcc -g -Os -Wall # To add support for HTTPS -TCC += -DFOSSIL_ENABLE_SSL +#TCC += -DFOSSIL_ENABLE_SSL #### Extra arguments for linking the finished binary. Fossil needs # to link against the Z-Lib compression library. There are no # other dependencies. We sometimes add the -static option here # so that we can build a static executable that will run in a @@ -47,11 +47,11 @@ # chroot jail. # LIB = -lz $(LDFLAGS) # If using HTTPS: -LIB += -lcrypto -lssl +#LIB += -lcrypto -lssl #### Tcl shell for use in running the fossil testsuite. If you do not # care about testing the end result, this can be blank. # TCLSH = tclsh Index: src/attach.c ================================================================== --- src/attach.c +++ src/attach.c @@ -49,19 +49,37 @@ " FROM attachment", -1 ); if( zPage ){ if( g.perm.RdWiki==0 ) login_needed(); - style_header("Attachments To %h", zPage); + style_header( +#ifdef LANG_RU + "Файлы к %h", +#elif LANG_EN + "Attachments To %h", +#endif + zPage); blob_appendf(&sql, " WHERE target=%Q", zPage); }else if( zTkt ){ if( g.perm.RdTkt==0 ) login_needed(); - style_header("Attachments To Ticket %.10s", zTkt); + style_header( +#ifdef LANG_RU + "Файлы к задаче %.10s", +#elif LANG_EN + "Attachments To Ticket %.10s", +#endif + zTkt); blob_appendf(&sql, " WHERE target GLOB '%q*'", zTkt); }else{ if( g.perm.RdTkt==0 && g.perm.RdWiki==0 ) login_needed(); - style_header("All Attachments"); + style_header( +#ifdef LANG_RU + "Все файлы" +#elif LANG_EN + "All Attachments" +#endif + ); } blob_appendf(&sql, " ORDER BY mtime DESC"); db_prepare(&q, "%s", blob_str(&sql)); @
    while( db_step(&q)==SQLITE_ROW ){ @@ -91,36 +109,72 @@ @ Attachment %z(href("%R/ainfo/%s",zUuid))%S(zUuid) if( moderation_pending(attachid) ){ @ *** Awaiting Moderator Approval *** } @
    %h(zFilename) - @ [download]
    + @ [ +#ifdef LANG_RU + @ скачать +#elif LANG_EN + @ download +#endif + @ ]
    if( zComment ) while( fossil_isspace(zComment[0]) ) zComment++; if( zComment && zComment[0] ){ @ %w(zComment)
    } if( zPage==0 && zTkt==0 ){ if( zSrc==0 || zSrc[0]==0 ){ +#ifdef LANG_RU + zSrc = "Удалён из"; +#elif LANG_EN zSrc = "Deleted from"; +#endif }else { +#ifdef LANG_RU + zSrc = "Добавлен к"; +#elif LANG_EN zSrc = "Added to"; +#endif } if( strlen(zTarget)==UUID_SIZE && validate16(zTarget, UUID_SIZE) ){ - @ %s(zSrc) ticket +#ifdef LANG_RU + @ %s(zSrc) задач%s(zSrc==0 || zSrc[0]==0 ? "и" : "е") +#elif LANG_EN + @ %s(zSrc) ticket +#endif + @ @ %S(zTarget) }else{ - @ %s(zSrc) wiki page +#ifdef LANG_RU + @ %s(zSrc) страниц%s(zSrc==0 || zSrc[0]==0 ? "ы" : "е") +#elif LANG_EN + @ %s(zSrc) wiki page +#endif + @ @ %h(zTarget) } }else{ if( zSrc==0 || zSrc[0]==0 ){ +#ifdef LANG_RU + @ Удалён +#elif LANG_EN @ Deleted +#endif }else { +#ifdef LANG_RU + @ Добавлен +#elif LANG_EN @ Added +#endif } } +#ifdef LANG_RU + @ пользователем %h(zDispUser) +#elif LANG_EN @ by %h(zDispUser) on +#endif hyperlink_to_date(zDate, "."); free(zUrlTail); } db_finalize(&q); @
@@ -173,17 +227,27 @@ " ORDER BY mtime DESC LIMIT 1", zTarget, zFile ); } if( zUUID==0 || zUUID[0]==0 ){ +#ifdef LANG_RU + style_header("Нет файлов"); + @ Нет файлов.... +#elif LANG_EN style_header("No Such Attachment"); @ No such attachment.... +#endif style_footer(); return; }else if( zUUID[0]=='x' ){ +#ifdef LANG_RU + style_header("Отсутствует"); + @ Файл был удален +#elif LANG_EN style_header("Missing"); @ Attachment has been deleted +#endif style_footer(); return; } g.perm.Read = 1; cgi_replace_parameter("name",zUUID); @@ -237,11 +301,12 @@ const char *zName = PD("f:filename","unknown"); const char *zTarget; const char *zTargetType; int szContent = atoi(PD("f:bytes","0")); int goodCaptcha = 1; - + const char *zComment = PD("comment", ""); + if( P("cancel") ) cgi_redirect(zFrom); if( zPage && zTkt ) fossil_redirect_home(); if( zPage==0 && zTkt==0 ) fossil_redirect_home(); login_check_credentials(); if( zPage ){ @@ -248,21 +313,33 @@ if( g.perm.ApndWiki==0 || g.perm.Attach==0 ) login_needed(); if( !db_exists("SELECT 1 FROM tag WHERE tagname='wiki-%q'", zPage) ){ fossil_redirect_home(); } zTarget = zPage; - zTargetType = mprintf("Wiki Page %h", - g.zTop, zPage, zPage); + zTargetType = mprintf( +#ifdef LANG_RU + "странице" +#elif LANG_EN + "Wiki Page" +#endif + " %h", + g.zTop, zPage, zPage); }else{ if( g.perm.ApndTkt==0 || g.perm.Attach==0 ) login_needed(); if( !db_exists("SELECT 1 FROM tag WHERE tagname='tkt-%q'", zTkt) ){ zTkt = db_text(0, "SELECT substr(tagname,5) FROM tag" " WHERE tagname GLOB 'tkt-%q*'", zTkt); if( zTkt==0 ) fossil_redirect_home(); } zTarget = zTkt; - zTargetType = mprintf("Ticket %S", + zTargetType = mprintf( +#ifdef LANG_RU + "задаче" +#elif LANG_EN + "Ticket" +#endif + " %S", g.zTop, zTkt, zTkt); } if( zFrom==0 ) zFrom = mprintf("%s/home", g.zTop); if( P("cancel") ){ cgi_redirect(zFrom); @@ -270,11 +347,10 @@ if( P("ok") && szContent>0 && (goodCaptcha = captcha_is_correct()) ){ Blob content; Blob manifest; Blob cksum; char *zUUID; - const char *zComment; char *zDate; int rid; int i, n; int addCompress = 0; Manifest *pManifest; @@ -300,11 +376,10 @@ } zName += n; if( zName[0]==0 ) zName = "unknown"; blob_appendf(&manifest, "A %F%s %F %s\n", zName, addCompress ? ".gz" : "", zTarget, zUUID); - zComment = PD("comment", ""); while( fossil_isspace(zComment[0]) ) zComment++; n = strlen(zComment); while( n>0 && fossil_isspace(zComment[n-1]) ){ n--; } if( n>0 ){ blob_appendf(&manifest, "C %F\n", zComment); @@ -317,29 +392,55 @@ attach_put(&manifest, rid, needModerator); assert( blob_is_reset(&manifest) ); db_end_transaction(0); cgi_redirect(zFrom); } +#ifdef LANG_RU + style_header("Добавить файл"); +#elif LANG_EN style_header("Add Attachment"); +#endif if( !goodCaptcha ){ +#ifdef LANG_RU + @

Ошибка: неверный код.

+#elif LANG_EN @

Error: Incorrect security code.

+#endif } +#ifdef LANG_RU + @

Добавление файла к %s(zTargetType)

+#elif LANG_EN @

Add Attachment To %s(zTargetType)

+#endif form_begin("enctype='multipart/form-data'", "%R/attachadd"); @
+ +#ifdef LANG_RU + @ Файл для добавления: +#elif LANG_EN @ File to Attach: - @
+#endif + @
+#ifdef LANG_RU + @ Описание:
+#elif LANG_EN @ Description:
- @
+#endif + @
if( zTkt ){ @ }else{ @ } @ +#ifdef LANG_RU + @ + @ +#elif LANG_EN @ @ +#endif @
captcha_generate(); @ style_footer(); } @@ -433,19 +534,28 @@ md5sum_blob(&manifest, &cksum); blob_appendf(&manifest, "Z %b\n", &cksum); rid = content_put(&manifest); manifest_crosslink(rid, &manifest); db_end_transaction(0); +#ifdef LANG_RU + @

Указанный файл будет удален.

+#elif LANG_EN @

The attachment below has been deleted.

+#endif } if( P("del") && ((zTktUuid && g.perm.WrTkt) || (zWikiName && g.perm.WrWiki)) ){ form_begin(0, "%R/ainfo/%s", zUuid); +#ifdef LANG_RU + @

Подтвердите удаление указанного файла. + @ +#elif LANG_EN @

Confirm you want to delete the attachment shown below. @ +#endif @ } isModerator = (zTktUuid && g.perm.ModTkt) || (zWikiName && g.perm.ModWiki); if( isModerator && (zModAction = P("modaction"))!=0 ){ @@ -460,64 +570,121 @@ } if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } +#ifdef LANG_RU + style_header("Информация о вложении"); + style_submenu_element("Как есть", "Как есть", "%R/artifact/%S", zUuid); + + @

Обзор
+ @

+ @ +#elif LANG_EN style_header("Attachment Details"); style_submenu_element("Raw", "Raw", "%R/artifact/%S", zUuid); @
Overview
@

ID артефакта:
@ +#endif @ +#elif LANG_EN @ +#endif @ } if( zWikiName ){ +#ifdef LANG_RU + @ +#elif LANG_EN @ +#endif @ } +#ifdef LANG_RU + @ "); free(zDate); +#ifdef LANG_RU + @ "); +#ifdef LANG_RU + @ +#elif LANG_EN @ +#endif @ +#elif LANG_EN @ +#endif zMime = mimetype_from_name(zName); if( g.perm.Setup ){ @ } +#ifdef LANG_RU + @ +#elif LANG_EN @ +#endif @
Artifact ID:%z(href("%R/artifact/%s",zUuid))%s(zUuid) if( g.perm.Setup ){ @ (%d(rid)) } modPending = moderation_pending(rid); if( modPending ){ +#ifdef LANG_RU + @ *** Ожидает утверждения модератором *** +#elif LANG_EN @ *** Awaiting Moderator Approval *** +#endif } if( zTktUuid ){ +#ifdef LANG_RU + @
Задача:
Ticket:%z(href("%R/tktview/%s",zTktUuid))%s(zTktUuid)
Вики-страница:
Wiki Page:%z(href("%R/wiki?name=%t",zWikiName))%h(zWikiName)
Дата: +#elif LANG_EN @
Date: +#endif hyperlink_to_date(zDate, "
Пользователь: +#elif LANG_EN @
User: +#endif hyperlink_to_user(pAttach->zUser, zDate, "
Артефакт :
Artifact Attached:%z(href("%R/artifact/%s",zSrc))%s(zSrc) if( g.perm.Setup ){ @ (%d(ridSrc)) } +#ifdef LANG_RU + @
Имя файла:%h(zName)
Filename:%h(zName)
MIME-Type:%h(zMime)
Описание:%h(zDesc)
Description:%h(zDesc)
if( isModerator && modPending ){ +#ifdef LANG_RU + @

Модерация
+#elif LANG_EN @
Moderation
+#endif @
form_begin(0, "%R/ainfo/%s", zUuid); @
+#elif LANG_EN @ Delete this change
+#endif @
+#elif LANG_EN @ Approve this change
+#endif @ @ @
} +#ifdef LANG_RU + @
Содержимое
+#elif LANG_EN @
Content Appended
+#endif @
blob_zero(&attach); if( zMime==0 || strncmp(zMime,"text/", 5)==0 ){ const char *z; const char *zLn = P("ln"); @@ -531,11 +698,11 @@ @ %h(z) @ } }else if( strncmp(zMime, "image/", 6)==0 ){ @ - style_submenu_element("Image", "Image", "%R/raw/%S?m=%s", zSrc, zMime); + style_submenu_element("Изображение", "Изображение", "%R/raw/%S?m=%s", zSrc, zMime); }else{ int sz = db_int(0, "SELECT size FROM blob WHERE rid=%d", ridSrc); @ (file is %d(sz) bytes of binary data) } @
@@ -572,16 +739,24 @@ @ %s(zHeader) } cnt++; @
  • @ %z(href("%R/artifact/%s",zSrc))%h(zFile) +#ifdef LANG_RU + @ добавлено %h(zDispUser) +#elif LANG_EN @ added by %h(zDispUser) on +#endif hyperlink_to_date(zDate, "."); +#ifdef LANG_RU + @ [%z(href("%R/ainfo/%s",zUuid))детали] +#elif LANG_EN @ [%z(href("%R/ainfo/%s",zUuid))details] +#endif @
  • } if( cnt ){ @ } db_finalize(&q); } Index: src/cgi.c ================================================================== --- src/cgi.c +++ src/cgi.c @@ -1242,10 +1242,12 @@ }else if( fossil_strcmp(zFieldName,"referer:")==0 ){ cgi_setenv("HTTP_REFERER", zVal); #endif }else if( fossil_strcmp(zFieldName,"user-agent:")==0 ){ cgi_setenv("HTTP_USER_AGENT", zVal); + }else if( fossil_strcmp(zFieldName,"x-real-ip:")==0 ){ + cgi_replace_parameter("REMOTE_ADDR", mprintf("%s",zVal)); } } cgi_init(); cgi_trace(0); } Index: src/checkin.c ================================================================== --- src/checkin.c +++ src/checkin.c @@ -652,11 +652,11 @@ ){ #ifndef FOSSIL_ALLOW_OUT_OF_ORDER_DATES int b; b = db_exists( "SELECT 1 FROM event" - " WHERE datetime(mtime)>=%Q" + " WHERE strftime('%%Y-%%m-%%dT%%H:%%M:%%f', mtime)>=strftime('%%Y-%%m-%%dT%%H:%%M:%%f', %Q)" " AND type='ci' AND objid=%d", zDate, rid ); if( b ){ fossil_fatal("ancestor check-in [%.10s] (%s) is not older (clock skew?)" Index: src/diff.c ================================================================== --- src/diff.c +++ src/diff.c @@ -45,10 +45,11 @@ /* ** These error messages are shared in multiple locations. They are defined ** here for consistency. */ + #define DIFF_CANNOT_COMPUTE_BINARY \ "cannot compute difference between binary files\n" #define DIFF_CANNOT_COMPUTE_SYMLINK \ "cannot compute difference between symlink and regular file\n" @@ -709,11 +710,11 @@ } } } if( c=='\t' ){ z[j++] = ' '; - while( (k&7)!=7 && kescHtml ){ memcpy(&z[j], "<", 4); j += 4; Index: src/info.c ================================================================== --- src/info.c +++ src/info.c @@ -85,11 +85,23 @@ db_prepare(&q, "SELECT uuid, pid, isprim FROM plink JOIN blob ON pid=rid " " WHERE cid=%d" " ORDER BY isprim DESC, mtime DESC /*sort*/", rid); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); - const char *zType = db_column_int(&q, 2) ? "parent:" : "merged-from:"; + const char *zType = db_column_int(&q, 2) ? +#ifdef LANG_RU + "родитель:" +#elif LANG_EN + "parent:" +#endif + : +#ifdef LANG_RU + "слито с:" +#elif LANG_EN + "merged-from:" +#endif + ; zDate = db_text("", "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", db_column_int(&q, 1) ); fossil_print("%-13s %s %s\n", zType, zUuid, zDate); @@ -99,11 +111,23 @@ db_prepare(&q, "SELECT uuid, cid, isprim FROM plink JOIN blob ON cid=rid " " WHERE pid=%d" " ORDER BY isprim DESC, mtime DESC /*sort*/", rid); while( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); - const char *zType = db_column_int(&q, 2) ? "child:" : "merged-into:"; + const char *zType = db_column_int(&q, 2) ? +#ifdef LANG_RU + "потомок:" +#elif LANG_EN + "child:" +#endif + : +#ifdef LANG_RU + "слито в:" +#elif LANG_EN + "merged-into:" +#endif + ; zDate = db_text("", "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", db_column_int(&q, 1) ); fossil_print("%-13s %s %s\n", zType, zUuid, zDate); @@ -111,15 +135,27 @@ } db_finalize(&q); } zTags = info_tags_of_checkin(rid, 0); if( zTags && zTags[0] ){ - fossil_print("tags: %s\n", zTags); + fossil_print( +#ifdef LANG_RU + "теги: %s\n", +#elif LANG_EN + "tags: %s\n", +#endif + zTags); } free(zTags); if( zComment ){ - fossil_print("comment: "); + fossil_print( +#ifdef LANG_RU + "комментарий: " +#elif LANG_EN + "comment: " +#endif + ); comment_print(zComment, 14, 79); free(zComment); } } @@ -461,12 +497,22 @@ login_check_credentials(); if( !g.perm.Read ){ login_needed(); return; } zName = P("name"); rid = name_to_rid_www("name"); if( rid==0 ){ - style_header("Check-in Information Error"); + style_header( +#ifdef LANG_RU + "Ошибка информации о фиксации" +#elif LANG_EN + "Check-in Information Error" +#endif + ); +#ifdef LANG_RU + @ Объект не найден: %h(g.argv[2]) +#elif LANG_EN @ No such object: %h(g.argv[2]) +#endif style_footer(); return; } zRe = P("regex"); if( zRe ) re_compile(&pRe, zRe, 0); @@ -486,11 +532,17 @@ rid, rid ); sideBySide = atoi(PD("sbs","1")); if( db_step(&q)==SQLITE_ROW ){ const char *zUuid = db_column_text(&q, 0); - char *zTitle = mprintf("Check-in [%.10s]", zUuid); + char *zTitle = mprintf( +#ifdef LANG_RU + "Фиксация [%.10s]", +#elif LANG_EN + "Check-in [%.10s]", +#endif + zUuid); char *zEUser, *zEComment; const char *zUser; const char *zComment; const char *zDate; const char *zOrigDate; @@ -506,37 +558,80 @@ TAG_COMMENT, rid); zUser = db_column_text(&q, 2); zComment = db_column_text(&q, 3); zDate = db_column_text(&q,1); zOrigDate = db_column_text(&q, 4); +#ifdef LANG_RU + @
    Обзор
    +#elif LANG_EN @
    Overview
    +#endif @ - @ - @ "); if( zOrigDate && fossil_strcmp(zDate, zOrigDate)!=0 ){ +#ifdef LANG_RU + @ "); } if( zEUser ){ +#ifdef LANG_RU + @ "); +#ifdef LANG_RU + @ "); }else{ +#ifdef LANG_RU + @ "); } if( zEComment ){ +#ifdef LANG_RU + @ + @ +#elif LANG_EN @ @ +#endif }else{ +#ifdef LANG_RU + @ +#elif LANG_EN @ +#endif } if( g.perm.Admin ){ db_prepare(&q, "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)" " FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)" @@ -546,17 +641,35 @@ if( db_step(&q)==SQLITE_ROW ){ const char *zIpAddr = db_column_text(&q, 0); const char *zUser = db_column_text(&q, 1); const char *zDate = db_column_text(&q, 2); if( zUser==0 || zUser[0]==0 ) zUser = "unknown"; +#ifdef LANG_RU + @ + @ +#elif LANG_EN @ @ +#endif } db_finalize(&q); } if( g.perm.Hyperlink ){ const char *zProjName = db_get("project-name", "unnamed"); +#ifdef LANG_RU + @ @ + @ +#ifdef LANG_RU + @ + @ @ @ } @
    SHA1 Hash:%s(zUuid) + @
    +#ifdef LANG_RU + @ SHA1 хэш: +#elif LANG_EN + @ SHA1 Hash: +#endif + @ %s(zUuid) if( g.perm.Setup ){ +#ifdef LANG_RU + @ (ID записи: %d(rid)) +#elif LANG_EN @ (Record ID: %d(rid)) +#endif } @
    Date: +#ifdef LANG_RU + @
    Дата: +#elif LANG_EN + @
    Date: +#endif hyperlink_to_date(zDate, "
    Оригинальная дата: +#elif LANG_EN @
    Original Date: +#endif hyperlink_to_date(zOrigDate, "
    Исправлявший пользователь: +#elif LANG_EN @
    Edited User: +#endif hyperlink_to_user(zEUser,zDate,"
    Первый пользователь: +#elif LANG_EN @
    Original User: +#endif hyperlink_to_user(zUser,zDate,"
    Пользователь: +#elif LANG_EN @
    User: +#endif hyperlink_to_user(zUser,zDate,"
    Исправленный комментарий:%w(zEComment)
    Первоначальный комментарий:%w(zComment)
    Edited Comment:%w(zEComment)
    Original Comment:%w(zComment)
    Comment:%w(zComment)
    Comment:%w(zComment)
    Получено от:%h(zUser) @ %h(zIpAddr) %s(zDate)
    Received From:%h(zUser) @ %h(zIpAddr) on %s(zDate)
    События: + @ %z(href("%R/timeline?f=%S",zUuid))ближние + if( zParent ){ + @ | %z(href("%R/timeline?p=%S",zUuid))родители + } + if( !isLeaf ){ + @ | %z(href("%R/timeline?d=%S",zUuid))потомки + } + if( zParent && !isLeaf ){ + @ | %z(href("%R/timeline?dp=%S",zUuid))обои + } +#elif LANG_EN @
    Timelines: @ %z(href("%R/timeline?f=%S",zUuid))family if( zParent ){ @ | %z(href("%R/timeline?p=%S",zUuid))ancestors } @@ -564,10 +677,11 @@ @ | %z(href("%R/timeline?d=%S",zUuid))descendants } if( zParent && !isLeaf ){ @ | %z(href("%R/timeline?dp=%S",zUuid))both } +#endif db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag " " WHERE rid=%d AND tagtype>0 " " AND tag.tagid=tagxref.tagid " " AND +tag.tagname GLOB 'sym-*'", rid); while( db_step(&q)==SQLITE_ROW ){ @@ -578,78 +692,151 @@ /* The Download: line */ if( g.perm.Zip ){ char *zUrl = mprintf("%R/tarball/%t-%S.tar.gz?uuid=%s", - zProjName, zUuid, zUuid); + zProjName, zUuid, zUuid); @
    Downloads: @ %z(href("%s",zUrl))Tarball @ | %z(href("%R/zip/%t-%S.zip?uuid=%s",zProjName,zUuid,zUuid)) +#ifdef LANG_RU + @ ZIP архив +#elif LANG_EN @ ZIP archive +#endif fossil_free(zUrl); } - @
    Другие ссылки: + @ %z(href("%R/dir?ci=%S",zUuid))файлы + @ | %z(href("%R/artifact/%S",zUuid))манифест +#elif LANG_EN @
    Other Links: @ %z(href("%R/dir?ci=%S",zUuid))files @ | %z(href("%R/fileage?name=%S",zUuid))file ages @ | %z(href("%R/artifact/%S",zUuid))manifest +#endif if( g.perm.Write ){ +#ifdef LANG_RU + @ | %z(href("%R/ci_edit?r=%S",zUuid))изменить +#elif LANG_EN @ | %z(href("%R/ci_edit?r=%S",zUuid))edit +#endif } @
    }else{ - style_header("Check-in Information"); + style_header( +#ifdef LANG_RU + "Информация о фиксации" +#elif LANG_EN + "Check-in Information" +#endif + ); login_anonymous_available(); } db_finalize(&q); showTags(rid, ""); if( zParent ){ +#ifdef LANG_RU + @
    Изменения
    +#elif LANG_EN @
    Changes
    +#endif @
    showDiff = g.zPath[0]!='c'; if( db_get_boolean("show-version-diffs", 0)==0 ){ showDiff = !showDiff; if( showDiff ){ @ %z(xhref("class='button'","%R/vinfo/%T",zName)) +#ifdef LANG_RU + @ спрятать различия +#elif LANG_EN @ hide diffs +#endif if( sideBySide ){ @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName)) +#ifdef LANG_RU + @ различия разом +#elif LANG_EN @ unified diffs +#endif }else{ @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName)) +#ifdef LANG_RU + @ различия бок-о-бок +#elif LANG_EN @ side-by-side diffs +#endif } }else{ @ %z(xhref("class='button'","%R/ci/%T?sbs=0",zName)) +#ifdef LANG_RU + @ показать различия разом +#elif LANG_EN @ show unified diffs +#endif @ %z(xhref("class='button'","%R/ci/%T?sbs=1",zName)) +#ifdef LANG_RU + @ показать различия бок-о-бок +#elif LANG_EN @ show side-by-side diffs +#endif } }else{ if( showDiff ){ - @ %z(xhref("class='button'","%R/ci/%T",zName))hide diffs + @ %z(xhref("class='button'","%R/ci/%T",zName)) +#ifdef LANG_RU + @ спрятать различия +#elif LANG_EN + @ hide diffs +#endif if( sideBySide ){ @ %z(xhref("class='button'","%R/info/%T?sbs=0",zName)) +#ifdef LANG_RU + @ различия разом +#elif LANG_EN @ unified diffs +#endif }else{ @ %z(xhref("class='button'","%R/info/%T?sbs=1",zName)) +#ifdef LANG_RU + @ различия бок-о-бок +#elif LANG_EN @ side-by-side diffs +#endif } }else{ @ %z(xhref("class='button'","%R/vinfo/%T?sbs=0",zName)) +#ifdef LANG_RU + @ показать различия разом +#elif LANG_EN @ show unified diffs +#endif @ %z(xhref("class='button'","%R/vinfo/%T?sbs=1",zName)) +#ifdef LANG_RU + @ показать различия бок-о-бок +#elif LANG_EN @ show side-by-side diffs +#endif } } + @    @ %z(xhref("class='button'","%R/vpatch?from=%S&to=%S",zParent,zUuid)) - @ patch
    +#ifdef LANG_RU + @ патч +#elif LANG_EN + @ patch +#endif + @ + if( pRe ){ @

    Only differences that match regular expression "%h(zRe)" @ are shown.

    } db_prepare(&q, @@ -696,12 +883,22 @@ login_check_credentials(); if( !g.perm.RdWiki ){ login_needed(); return; } rid = name_to_rid_www("name"); if( rid==0 || (pWiki = manifest_get(rid, CFTYPE_WIKI))==0 ){ - style_header("Wiki Page Information Error"); + style_header( +#ifdef LANG_RU + "Ошибка информации о странице" +#elif LANG_EN + "Wiki Page Information Error" +#endif + ); +#ifdef LANG_RU + @ Объект не найден: %h(g.argv[2]) +#elif LANG_EN @ No such object: %h(P("name")) +#endif style_footer(); return; } if( g.perm.ModWiki && (zModAction = P("modaction"))!=0 ){ if( strcmp(zModAction,"delete")==0 ){ @@ -711,62 +908,117 @@ } if( strcmp(zModAction,"approve")==0 ){ moderation_approve(rid); } } +#ifdef LANG_RU + style_header("Правка \"%h\"", pWiki->zWikiTitle); +#elif LANG_EN style_header("Update of \"%h\"", pWiki->zWikiTitle); +#endif zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); zDate = db_text(0, "SELECT datetime(%.17g)", pWiki->rDate); +#ifdef LANG_RU + style_submenu_element("Как есть", "Как есть", "artifact/%S", zUuid); + style_submenu_element("История", "История", "whistory?name=%t", + pWiki->zWikiTitle); + style_submenu_element("Страница", "Страница", "wiki?name=%t", + pWiki->zWikiTitle); +#elif LANG_EN style_submenu_element("Raw", "Raw", "artifact/%S", zUuid); style_submenu_element("History", "History", "whistory?name=%t", pWiki->zWikiTitle); style_submenu_element("Page", "Page", "wiki?name=%t", pWiki->zWikiTitle); +#endif login_anonymous_available(); +#ifdef LANG_RU + @
    Обзор
    +#elif LANG_EN @
    Overview
    +#endif @

    +#ifdef LANG_RU + @ +#elif LANG_EN @ +#endif @ +#ifdef LANG_RU + @ + @ "); + @ @ "); @ "); if( pWiki->nParent>0 ){ int i; +#ifdef LANG_RU + @ } @
    ID артефакта:
    Artifact ID:%z(href("%R/artifact/%s",zUuid))%s(zUuid) if( g.perm.Setup ){ @ (%d(rid)) } modPending = moderation_pending(rid); if( modPending ){ +#ifdef LANG_RU + @ *** Ожидает утверждения модератором *** +#elif LANG_EN @ *** Awaiting Moderator Approval *** +#endif } @
    Имя страницы:%h(pWiki->zWikiTitle)
    Дата: + hyperlink_to_date(zDate, "
    Создавший пользователь: +#elif LANG_EN @
    Page Name:%h(pWiki->zWikiTitle)
    Date: hyperlink_to_date(zDate, "
    Original User: +#endif hyperlink_to_user(pWiki->zUser, zDate, "
    Родител%s(pWiki->nParent==1?"ь":"и"): +#elif LANG_EN @
    Parent%s(pWiki->nParent==1?"":"s"): +#endif for(i=0; inParent; i++){ char *zParent = pWiki->azParent[i]; @ %z(href("info/%S",zParent))%s(zParent) } @
    if( g.perm.ModWiki && modPending ){ +#ifdef LANG_RU + @

    Модерация
    +#elif LANG_EN @
    Moderation
    +#endif @
    @
    @
    +#elif LANG_EN @ Delete this change
    +#endif @
    +#elif LANG_EN @ Approve this change
    +#endif +#ifdef LANG_RU + @ +#elif LANG_EN @ +#endif @
    @
    } +#ifdef LANG_RU + @
    Содержимое
    +#elif LANG_EN @
    Content
    +#endif blob_init(&wiki, pWiki->zWiki, -1); wiki_convert(&wiki, 0, 0); blob_reset(&wiki); manifest_destroy(pWiki); style_footer(); @@ -779,12 +1031,17 @@ va_list ap; const char *z; va_start(ap, zFormat); z = vmprintf(zFormat, ap); va_end(ap); +#ifdef LANG_RU + style_header("Ошибка URL"); + @

    Ошибка

    +#elif LANG_EN style_header("URL Error"); @

    Error

    +#endif @

    %h(z)

    style_footer(); } /* @@ -794,20 +1051,38 @@ static Manifest *vdiff_parse_manifest(const char *zParam, int *pRid){ int rid; *pRid = rid = name_to_rid_www(zParam); if( rid==0 ){ - const char *z = P(zParam); - if( z==0 || z[0]==0 ){ - webpage_error("Missing \"%s\" query parameter.", zParam); - }else{ - webpage_error("No such artifact: \"%s\"", z); - } - return 0; + const char *z = P(zParam); + if( z==0 || z[0]==0 ){ + webpage_error( +#ifdef LANG_RU + "Отсутствует параметр \"%s\" в запросе." +#elif LANG_EN + "Missing \"%s\" query parameter." +#endif + , zParam); + }else{ + webpage_error( +#ifdef LANG_RU + "Артефакт не найден: \"%s\"" +#elif LANG_EN + "No such artifact: \"%s\"" +#endif + , z); + } + return 0; } if( !is_a_version(rid) ){ - webpage_error("Artifact %s is not a checkin.", P(zParam)); + webpage_error( +#ifdef LANG_RU + "Артефакт не Фиксация.", +#elif LANG_EN + "Artifact %s is not a checkin.", +#endif + P(zParam)); return 0; } return manifest_get(rid, CFTYPE_MANIFEST); } @@ -840,11 +1115,15 @@ hyperlink_to_uuid(zUuid); blob_zero(&comment); db_column_blob(&q, 2, &comment); wiki_convert(&comment, 0, wikiFlags); blob_reset(&comment); +#ifdef LANG_RU + @ (пользователь: +#elif LANG_EN @ (user: +#endif hyperlink_to_user(zUser,zDate,","); if( zTagList && zTagList[0] && g.perm.Hyperlink ){ int i; const char *z = zTagList; Blob links; @@ -856,16 +1135,28 @@ href("%R/timeline?r=%#t&nd&c=%t",i,z,zDate), i,z, &z[i] ); if( z[i]==0 ) break; z += i+2; } +#ifdef LANG_RU + @ метка: %s(blob_str(&links)), +#elif LANG_EN @ tags: %s(blob_str(&links)), +#endif blob_reset(&links); }else{ - @ tags: %h(zTagList), +#ifdef LANG_RU + @ метка: %h(zTagList), +#elif LANG_EN + @ метка: %h(zTagList), +#endif } +#ifdef LANG_RU + @ дата: +#elif LANG_EN @ date: +#endif hyperlink_to_date(zDate, ")"); } db_finalize(&q); } @@ -917,25 +1208,47 @@ showDetail = atoi(PD("detail","0")); if( !showDetail && sideBySide ) showDetail = 1; zFrom = P("from"); zTo = P("to"); if( !sideBySide ){ - style_submenu_element("Side-by-side Diff", "sbsdiff", + style_submenu_element( +#ifdef LANG_RU + "Различия бок-о-бок", "sbsdiff", +#elif LANG_EN + "Side-by-side Diff", "sbsdiff", +#endif "%R/vdiff?from=%T&to=%T&detail=%d&sbs=1", zFrom, zTo, showDetail); }else{ - style_submenu_element("Unified Diff", "udiff", + style_submenu_element( +#ifdef LANG_RU + "Различия разом", "udiff", +#elif LANG_EN + "Unified Diff", "udiff", +#endif "%R/vdiff?from=%T&to=%T&detail=%d&sbs=0", zFrom, zTo, showDetail); } style_submenu_element("Invert", "invert", "%R/vdiff?from=%T&to=%T&detail=%d&sbs=%d", zTo, zFrom, showDetail, sideBySide); +#ifdef LANG_RU + style_header("Различия в фиксации"); + @

    Различия между:

    + checkin_description(ridFrom); +#elif LANG_EN style_header("Check-in Differences"); @

    Difference From:

    checkin_description(ridFrom); - @

    To:

    +#endif + @

    +#ifdef LANG_RU + @ и: +#elif LANG_EN + @ To: +#endif + @

    checkin_description(ridTo); @
    if( pRe ){ @

    Only differences that match regular expression "%h(zRe)" @ are shown.

    @@ -1273,32 +1586,71 @@ content_get(v2, &c2); text_diff(&c1, &c2, pOut, pRe, diffFlags); blob_reset(&c1); blob_reset(&c2); if( !isPatch ){ +#ifdef LANG_RU + style_header("Различия"); +#elif LANG_EN style_header("Diff"); - style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", +#endif + style_submenu_element( +#ifdef LANG_RU + "Патч", "Патч", +#elif LANG_EN + "Patch", "Patch", +#endif + "%s/fdiff?v1=%T&v2=%T&patch", g.zTop, P("v1"), P("v2")); if( !sideBySide ){ - style_submenu_element("Side-by-side Diff", "sbsdiff", + style_submenu_element( +#ifdef LANG_RU + "Различия бок-о-бок", "sbsdiff", +#elif LANG_EN + "Side-by-side Diff", "sbsdiff", +#endif "%s/fdiff?v1=%T&v2=%T&sbs=1", g.zTop, P("v1"), P("v2")); }else{ - style_submenu_element("Unified Diff", "udiff", + style_submenu_element( +#ifdef LANG_RU + "Различия разом", "udiff", +#elif LANG_EN + "Unified Diff", "udiff", +#endif "%s/fdiff?v1=%T&v2=%T&sbs=0", g.zTop, P("v1"), P("v2")); } if( P("smhdr")!=0 ){ +#ifdef LANG_RU + @

    Различия между артефактом +#elif LANG_EN @

    Differences From Artifact - @ %z(href("%R/artifact/%S",zV1))[%S(zV1)] To +#endif + @ %z(href("%R/artifact/%S",zV1))[%S(zV1)] +#ifdef LANG_RU + @ и +#elif LANG_EN + @ To +#endif @ %z(href("%R/artifact/%S",zV2))[%S(zV2)].

    }else{ - @

    Differences From - @ Artifact %z(href("%R/artifact/%S",zV1))[%S(zV1)]:

    +#ifdef LANG_RU + @

    Различия между артефактом +#elif LANG_EN + @

    Differences From Artifact +#endif + @ %z(href("%R/artifact/%S",zV1))[%S(zV1)]:

    object_description(v1, 0, 0); - @

    To Artifact %z(href("%R/artifact/%S",zV2))[%S(zV2)]:

    + @

    +#ifdef LANG_RU + @ и артефактом +#elif LANG_EN + @ To Artifact +#endif + @ %z(href("%R/artifact/%S",zV2))[%S(zV2)]:

    object_description(v2, 0, 0); } if( pRe ){ @ Only differences that match regular expression "%h(zRe)" @ are shown. @@ -1416,27 +1768,55 @@ if( !g.perm.Read ){ login_needed(); return; } if( rid==0 ) fossil_redirect_home(); if( g.perm.Admin ){ const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid); if( db_exists("SELECT 1 FROM shun WHERE uuid='%s'", zUuid) ){ - style_submenu_element("Unshun","Unshun", "%s/shun?uuid=%s&sub=1", + style_submenu_element( +#ifdef LANG_RU + "Восстановить","Восстановить", +#elif LANG_EN + "Unshun","Unshun", +#endif + "%s/shun?uuid=%s&sub=1", g.zTop, zUuid); }else{ - style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun", + style_submenu_element( +#ifdef LANG_RU + "Стереть","Стереть", +#elif LANG_EN + "Shun","Shun", +#endif + "%s/shun?shun=%s#addshun", g.zTop, zUuid); } } - style_header("Hex Artifact Content"); + style_header( +#ifdef LANG_RU + "Содержимое бинарного артефакта" +#elif LANG_EN + "Hex Artifact Content" +#endif + ); zUuid = db_text("?","SELECT uuid FROM blob WHERE rid=%d", rid); if( g.perm.Setup ){ +#ifdef LANG_RU + @

    Артефакт %s(zUuid) (%d(rid)):

    + }else{ + @

    Artifact %s(zUuid):

    +#elif LANG_EN @

    Artifact %s(zUuid) (%d(rid)):

    }else{ @

    Artifact %s(zUuid):

    +#endif } blob_zero(&downloadName); object_description(rid, 0, &downloadName); +#ifdef LANG_RU + style_submenu_element("Скачать", "Скачать", +#elif LANG_EN style_submenu_element("Download", "Download", +#endif "%s/raw/%T?name=%s", g.zTop, blob_str(&downloadName), zUuid); @
    content_get(rid, &content); @
       hexdump(&content);
    @@ -1573,23 +1953,42 @@
         }else{
           style_submenu_element("Shun","Shun", "%s/shun?shun=%s#addshun",
                 g.zTop, zUuid);
         }
       }
    +#ifdef LANG_RU
    +  style_header("Содержимое артефакта");
    +#elif LANG_EN
       style_header("Artifact Content");
    +#endif
       zUuid = db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid);
       if( g.perm.Setup ){
    +#ifdef LANG_RU
    +    @ 

    Артефакт %s(zUuid) (%d(rid)):

    + }else{ + @

    Артефакт %s(zUuid):

    +#elif LANG_EN @

    Artifact %s(zUuid) (%d(rid)):

    }else{ @

    Artifact %s(zUuid):

    +#endif } + @

    blob_zero(&downloadName); objType = object_description(rid, 0, &downloadName); +#ifdef LANG_RU + style_submenu_element("Скачать", "Скачать", +#elif LANG_EN style_submenu_element("Download", "Download", +#endif "%R/raw/%T?name=%s", blob_str(&downloadName), zUuid); if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){ +#ifdef LANG_RU + style_submenu_element("Используется в фиксациях", "Используется в фиксациях", +#elif LANG_EN style_submenu_element("Checkins Using", "Checkins Using", +#endif "%R/timeline?uf=%s&n=200",zUuid); } asText = P("txt")!=0; zMime = mimetype_from_name(blob_str(&downloadName)); if( zMime ){ @@ -1597,20 +1996,35 @@ if( asText ){ style_submenu_element("Html", "Html", "%s/artifact/%s", g.zTop, zUuid); }else{ renderAsHtml = 1; - style_submenu_element("Text", "Text", + style_submenu_element( +#ifdef LANG_RU + "Текст", "Показать как текст", +#elif LANG_EN + "Text", "Text", +#endif "%s/artifact/%s?txt=1", g.zTop, zUuid); } }else if( fossil_strcmp(zMime, "application/x-fossil-wiki")==0 ){ if( asText ){ - style_submenu_element("Wiki", "Wiki", + style_submenu_element( +#ifdef LANG_RU + "Вики", "Показать как вики", +#elif LANG_EN + "Wiki", "Wiki", +#endif "%s/artifact/%s", g.zTop, zUuid); }else{ renderAsWiki = 1; - style_submenu_element("Text", "Text", + style_submenu_element( +#ifdef LANG_RU + "Текст", "Показать как текст", +#elif LANG_EN + "Text", "Text", +#endif "%s/artifact/%s?txt=1", g.zTop, zUuid); } } } if( (objType & (OBJTYPE_WIKI|OBJTYPE_TICKET))!=0 ){ @@ -1644,11 +2058,15 @@ }else if( strncmp(zMime, "image/", 6)==0 ){ @ style_submenu_element("Image", "Image", "%R/raw/%S?m=%s", zUuid, zMime); }else{ +#ifdef LANG_RU + @ (бинарный файл, байт: %d(blob_size(&content))) +#elif LANG_EN @ (file is %d(blob_size(&content)) bytes of binary data) +#endif } @

    } style_footer(); } Index: src/login.c ================================================================== --- src/login.c +++ src/login.c @@ -493,22 +493,38 @@ " WHERE uid=%d" " AND (constant_time_cmp(pw,%Q)=0" " OR constant_time_cmp(pw,%Q)=0)", g.userUid, zSha1Pw, zPasswd) ){ sleep(1); +#ifdef LANG_RU + zErrMsg = + @

    + @ Вы ввели неверный старый пароль. + @ Ваш пароль не изменен. + @

    +#elif LANG_EN zErrMsg = - @

    - @ You entered an incorrect old password while attempting to change - @ your password. Your password is unchanged. - @

    + @

    + @ You entered an incorrect old password while attempting to change + @ your password. Your password is unchanged. + @

    +#endif ; }else if( fossil_strcmp(zNew1,zNew2)!=0 ){ +#ifdef LANG_RU + zErrMsg = + @

    + @ Два введенных новых пароля не совпадают. + @ Ваш пароль не изменен. + @

    +#elif LANG_EN zErrMsg = - @

    - @ The two copies of your new passwords do not match. - @ Your password is unchanged. - @

    + @

    + @ The two copies of your new passwords do not match. + @ Your password is unchanged. + @

    +#endif ; }else{ char *zNewPw = sha1_shared_secret(zNew1, g.zLogin, 0); char *zChngPw; char *zErr; @@ -543,14 +559,21 @@ /* Attempting to log in as a user other than anonymous. */ uid = login_search_uid(zUsername, zPasswd); if( uid<=0 ){ sleep(1); +#ifdef LANG_RU zErrMsg = @

    + @ Вы ввели неверный пароль или имя несущестующего пользователя. + @

    +#elif LANG_EN + zErrMsg = + @

    @ You entered an unknown user or an incorrect password. @

    +#endif ; record_login_attempt(zUsername, zIpAddr, 0); }else{ /* Non-anonymous login is successful. Set a cookie of the form: ** @@ -561,11 +584,17 @@ */ login_set_user_cookie(zUsername, uid, NULL); redirect_to_g(); } } - style_header("Login/Logout"); + style_header( +#ifdef LANG_RU + "Вход/Выход" +#elif LANG_EN + "Login/Logout" +#endif + ); @ %s(zErrMsg) if( zGoto && P("anon")==0 ){ @

    A login is required for %h(zGoto).

    } form_begin(0, "%R/login"); @@ -572,29 +601,45 @@ if( zGoto ){ @ } @ @ - @ + @ if( anonFlag ){ @ }else{ @ } @ @ - @ + @ @ @ if( g.zLogin==0 ){ zAnonPw = db_text(0, "SELECT pw FROM user" " WHERE login='anonymous'" " AND cap!=''"); } @ @ +#ifdef LANG_RU + @ @ @ @ - if( g.zLogin==0 ){ - @

    Enter - }else{ - @

    You are currently logged in as %h(g.zLogin)

    - @

    To change your login to a different user, enter - } - @ your user-id and password at the left and press the - @ "Login" button. Your user name will be stored in a browser cookie. - @ You must configure your web browser to accept cookies in order for - @ the login to take.

    +#ifdef LANG_RU + if( g.zLogin==0 ){ + @

    Укажите + }else{ + @

    Вы вошли как %h(g.zLogin)

    + @

    Чтобы войти под другим именем, укажите + } + @ имя пользователя и пароль, и нажмите кнопку "Вход". + @ Введенное имя будет сохранено в куках браузера. + @ Вы должны разрешить браузеру сохранять куки для возможности входа + @ на сайт.

    +#elif LANG_EN + if( g.zLogin==0 ){ + @

    Enter + }else{ + @

    You are currently logged in as %h(g.zLogin)

    + @

    To change your login to a different user, enter + } + @ your user-id and password at the left and press the + @ "Login" button. Your user name will be stored in a browser cookie. + @ You must configure your web browser to accept cookies in order for + @ the login to take.

    +#endif + if( db_get_boolean("self-register", 0) ){ +#ifdef LANG_RU + @

    Если у вас нет аккаунта, вы можете + @ зарегистрироваться. +#elif LANG_EN @

    If you do not have an account, you can @ create one. +#endif } + if( zAnonPw ){ unsigned int uSeed = captcha_seed(); char const *zDecoded = captcha_decode(uSeed); int bAutoCaptcha = db_get_boolean("auto-captcha", 0); char *zCaptcha = captcha_render(zDecoded); @

    +#ifdef LANG_RU + @ Гости могут указать anonymous как имя пользователя + @ и ввести 8-символьный пароль, указанный ниже:

    +#elif LANG_EN @ Visitors may enter anonymous as the user-ID with @ the 8-character hexadecimal password shown below:

    +#endif @
         @ %h(zCaptcha)
         @ 
    if( bAutoCaptcha ) { - @ } @
    free(zCaptcha); } if( g.zLogin ){ @
    +#ifdef LANG_RU + @

    Для выхода + @ нажмите эту кнопку:
    + @

    +#elif LANG_EN @

    To log off the system (and delete your login cookie) @ press the following button:
    @

    +#endif } @ if( g.perm.Password ){ @
    +#ifdef LANG_RU + @

    Для смены своего пароля введите текущий пароль и два раза + @ новый, после чего нажмите кнопку "Изменить пароль".

    + @
    + @ + @ + @ + @ + @ + @ + @ + @ + @ +#elif LANG_EN @

    To change your password, enter your old password and your @ new password twice below then press the "Change Password" @ button.

    form_begin(0, "%R/login"); @
    @@ -663,10 +757,11 @@ @ @ @ @ @ +#endif @
    @
    } style_footer(); } @@ -1145,13 +1240,19 @@ if( !g.perm.Hyperlink && db_exists("SELECT 1 FROM user" " WHERE login='anonymous'" " AND cap LIKE '%%h%%'") ){ const char *zUrl = PD("REQUEST_URI", "index"); +#ifdef LANG_RU + @

    Многие ссылки отключены.
    + @ Используйте анонимный вход + @ для включения ссылок.

    +#elif LANG_EN @

    Many hyperlinks are disabled.
    @ Use anonymous login @ to enable hyperlinks.

    +#endif } } /* ** While rendering a form, call this routine to add the Anti-CSRF token Index: src/main.mk ================================================================== --- src/main.mk +++ src/main.mk @@ -8,11 +8,11 @@ # to regenerate this file. # # This file is included by primary Makefile. # -XTCC = $(TCC) $(CFLAGS) -I. -I$(SRCDIR) -I$(OBJDIR) +XTCC = $(TCC) $(CFLAGS) -DFOSSIL_ENABLE_JSON -DLANG_RU -I. -I$(SRCDIR) -I$(OBJDIR) SRC = \ $(SRCDIR)/add.c \ $(SRCDIR)/allrepo.c \ Index: src/manifest.c ================================================================== --- src/manifest.c +++ src/manifest.c @@ -1552,40 +1552,71 @@ if( fossil_strcmp(pManifest->aField[i].zName, zStatusColumn)==0 ){ zNewStatus = pManifest->aField[i].zValue; } } if( zNewStatus ){ +#ifdef LANG_RU + blob_appendf(&comment, "%h задача [%.10s]: %h", +#elif LANG_EN blob_appendf(&comment, "%h ticket [%.10s]: %h", +#endif zNewStatus, pManifest->zTicketUuid, zTitle ); if( pManifest->nField>1 ){ +#ifdef LANG_RU + blob_appendf(&comment, " плюс еще изменений %d", +#elif LANG_EN blob_appendf(&comment, " plus %d other change%s", +#endif pManifest->nField-1, pManifest->nField==2 ? "" : "s"); } +#ifdef LANG_RU + blob_appendf(&brief, "%h задача [%.10s].", +#elif LANG_EN blob_appendf(&brief, "%h ticket [%.10s].", +#endif zNewStatus, pManifest->zTicketUuid); }else{ zNewStatus = db_text("unknown", "SELECT %s FROM ticket WHERE tkt_uuid='%s'", zStatusColumn, pManifest->zTicketUuid ); +#ifdef LANG_RU + blob_appendf(&comment, "Задача [%.10s] %h статус остался %h с " + "%d изменением", + pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField +#elif LANG_EN blob_appendf(&comment, "Ticket [%.10s] %h status still %h with " "%d other change%s", - pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField, - pManifest->nField==1 ? "" : "s" + pManifest->zTicketUuid, zTitle, zNewStatus, pManifest->nField, + pManifest->nField==1 ? "" : "s" +#endif ); free(zNewStatus); +#ifdef LANG_RU + blob_appendf(&brief, "Задача [%.10s]: %d изменение", + pManifest->zTicketUuid, pManifest->nField +#elif LANG_EN blob_appendf(&brief, "Ticket [%.10s]: %d change%s", pManifest->zTicketUuid, pManifest->nField, pManifest->nField==1 ? "" : "s" +#endif ); } }else{ +#ifdef LANG_RU + blob_appendf(&comment, "Новая задача [%.10s] %h.", +#elif LANG_EN blob_appendf(&comment, "New ticket [%.10s] %h.", +#endif pManifest->zTicketUuid, zTitle ); +#ifdef LANG_RU + blob_appendf(&brief, "Новая задача [%.10s].", pManifest->zTicketUuid); +#elif LANG_EN blob_appendf(&brief, "New ticket [%.10s].", pManifest->zTicketUuid); +#endif } free(zTitle); db_multi_exec( "REPLACE INTO event(type,tagid,mtime,objid,user,comment,brief)" "VALUES('t',%d,%.17g,%d,%Q,%Q,%Q)", @@ -1771,13 +1802,21 @@ ); if( prior ){ content_deltify(prior, rid, 0); } if( nWiki>0 ){ +#ifdef LANG_RU + zComment = mprintf("Правка страницы [%h]", p->zWikiTitle); +#elif LANG_EN zComment = mprintf("Changes to wiki page [%h]", p->zWikiTitle); +#endif }else{ +#ifdef LANG_RU + zComment = mprintf("Удаление страницы [%h]", p->zWikiTitle); +#elif LANG_EN zComment = mprintf("Deleted wiki page [%h]", p->zWikiTitle); +#endif } db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment," " bgcolor,euser,ecomment)" "VALUES('w',%.17g,%d,%Q,%Q," @@ -1869,14 +1908,23 @@ || !validate16(p->zAttachTarget, UUID_SIZE) ){ char *zComment; if( p->zAttachSrc && p->zAttachSrc[0] ){ zComment = mprintf( +#ifdef LANG_RU + "Добавить вложение [%R/artifact/%S|%h] к вики-странице [%h]", +#elif LANG_EN "Add attachment [%R/artifact/%S|%h] to wiki page [%h]", +#endif p->zAttachSrc, p->zAttachName, p->zAttachTarget); }else{ - zComment = mprintf("Delete attachment \"%h\" from wiki page [%h]", + zComment = mprintf( +#ifdef LANG_RU + "Удален файл \"%h\" из страницы[%h]", +#elif LANG_EN + "Delete attachment \"%h\" from wiki page [%h]", +#endif p->zAttachName, p->zAttachTarget); } db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('w',%.17g,%d,%Q,%Q)", @@ -1885,14 +1933,23 @@ free(zComment); }else{ char *zComment; if( p->zAttachSrc && p->zAttachSrc[0] ){ zComment = mprintf( +#ifdef LANG_RU + "Добавить вложение [%R/artifact/%S|%h] к задаче [%S]", +#elif LANG_EN "Add attachment [%R/artifact/%S|%h] to ticket [%S]", +#endif p->zAttachSrc, p->zAttachName, p->zAttachTarget); }else{ - zComment = mprintf("Delete attachment \"%h\" from ticket [%.10s]", + zComment = mprintf( +#ifdef LANG_RU + "Удален файл \"%h\" из задачи [%.10s]", +#elif LANG_EN + "Delete attachment \"%h\" from ticket [%.10s]", +#endif p->zAttachName, p->zAttachTarget); } db_multi_exec( "REPLACE INTO event(type,mtime,objid,user,comment)" "VALUES('t',%.17g,%d,%Q,%Q)", Index: src/report.c ================================================================== --- src/report.c +++ src/report.c @@ -35,11 +35,17 @@ int rn = 0; int cnt = 0; login_check_credentials(); if( !g.perm.RdTkt && !g.perm.NewTkt ){ login_needed(); return; } - style_header("Ticket Main Menu"); + style_header( +#ifdef LANG_RU + "Задачи: основное меню" +#elif LANG_EN + "Ticket Main Menu" +#endif + ); if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST
    \n", -1); zScript = ticket_reportlist_code(); if( g.thTrace ) Th_Trace("BEGIN_REPORTLIST_SCRIPT
    \n", -1); blob_zero(&ril); @@ -996,10 +1002,11 @@ char *zClrKey; int tabs; Stmt q; char *zErr1 = 0; char *zErr2 = 0; + Blob bSql = empty_blob; login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(); return; } rn = atoi(PD("rn","0")); if( rn==0 ){ @@ -1017,10 +1024,12 @@ zTitle = db_column_malloc(&q, 0); zSql = db_column_malloc(&q, 1); zOwner = db_column_malloc(&q, 2); zClrKey = db_column_malloc(&q, 3); db_finalize(&q); + + if( P("order_by") ){ /* ** If the user wants to do a column sort, wrap the query into a sub ** query and then sort the results. This is a whole lot easier than @@ -1032,27 +1041,48 @@ const char* zDir = PD("order_dir",""); zDir = !strcmp("ASC",zDir) ? "ASC" : "DESC"; zSql = mprintf("SELECT * FROM (%s) ORDER BY %d %s", zSql, nField, zDir); } } + Th_FossilInit(0, 0); + Th_Store("login", g.zLogin); + Th_Store("date", db_text(0, "SELECT datetime('now')")); + Th_RenderToBlob(zSql, &bSql); + zSql = bSql.aData; count = 0; if( !tabs ){ struct GenerateHTML sState; db_multi_exec("PRAGMA empty_result_callbacks=ON"); - style_submenu_element("Raw", "Raw", + style_submenu_element( +#ifdef LANG_RU + "Текстом", "Текстом", +#elif LANG_EN + "Raw", "Raw", +#endif "rptview?tablist=1&%h", PD("QUERY_STRING","")); if( g.perm.Admin || (g.perm.TktFmt && g.zLogin && fossil_strcmp(g.zLogin,zOwner)==0) ){ - style_submenu_element("Edit", "Edit", "rptedit?rn=%d", rn); + style_submenu_element( +#ifdef LANG_RU + "Изменить", "Изменить", +#elif LANG_EN + "Edit", "Edit", +#endif + "rptedit?rn=%d", rn); } if( g.perm.TktFmt ){ style_submenu_element("SQL", "SQL", "rptsql?rn=%d",rn); } if( g.perm.NewTkt ){ - style_submenu_element("New Ticket", "Create a new ticket", + style_submenu_element( +#ifdef LANG_RU + "Новая задача", "Создать новую задачу", +#elif LANG_EN + "New Ticket", "Create a new ticket", +#endif "%s/tktnew", g.zTop); } style_header(zTitle); output_color_key(zClrKey, 1, "border=\"0\" cellpadding=\"3\" cellspacing=\"0\" class=\"report\""); Index: src/sqlite3.c ================================================================== --- src/sqlite3.c +++ src/sqlite3.c @@ -14083,12 +14083,13 @@ zDate++; neg = 1; }else{ neg = 0; } - if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 ){ - return 1; + if( getDigits(zDate,4,0,9999,'-',&Y,2,1,12,'-',&M,2,1,31,0,&D)!=3 && + getDigits(zDate,2,1,31,'.',&D,2,1,12,'.',&M,4,0,9999,0,&Y)!=3 ){ + return 1; } zDate += 10; while( sqlite3Isspace(*zDate) || 'T'==*(u8*)zDate ){ zDate++; } if( parseHhMmSs(zDate, p)==0 ){ /* We got the time */ @@ -14631,12 +14632,12 @@ ){ DateTime x; if( isDate(context, argc, argv, &x)==0 ){ char zBuf[100]; computeYMD_HMS(&x); - sqlite3_snprintf(sizeof(zBuf), zBuf, "%04d-%02d-%02d %02d:%02d:%02d", - x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%02d.%02d.%04d %02d:%02d:%02d", + x.D, x.M, x.Y, x.h, x.m, (int)(x.s)); sqlite3_result_text(context, zBuf, -1, SQLITE_TRANSIENT); } } /* Index: src/th_main.c ================================================================== --- src/th_main.c +++ src/th_main.c @@ -102,10 +102,12 @@ } } return zRc; } +static Blob* pOutBlob = NULL; + /* ** Send text to the appropriate output: Either to the console ** or to the CGI reply buffer. Escape all characters with special ** meaning to HTML if the encode parameter is true. */ @@ -114,11 +116,13 @@ if( n<0 ) n = strlen(z); if( encode ){ z = htmlize(z, n); n = strlen(z); } - if( g.cgiOutput ){ + if(pOutBlob) + blob_append(pOutBlob, z, n); + else if( g.cgiOutput ){ cgi_append_content(z, n); }else{ fwrite(z, 1, n, stdout); fflush(stdout); } @@ -918,10 +922,18 @@ }else{ sendText(z, i, 0); } return rc; } + +int Th_RenderToBlob(const char *z, Blob *pBlob){ + int result; + pOutBlob = pBlob; + result = Th_Render(z); + pOutBlob = NULL; + return result; +} /* ** COMMAND: test-th-render */ void test_th_render(void){ Index: src/timeline.c ================================================================== --- src/timeline.c +++ src/timeline.c @@ -820,11 +820,11 @@ static char *zBase = 0; static const char zBaseSql[] = @ SELECT @ blob.rid AS blobRid, @ uuid AS uuid, - @ datetime(event.mtime,'localtime') AS timestamp, + @ datetime(event.mtime, 'localtime') AS timestamp, @ coalesce(ecomment, comment) AS comment, @ coalesce(euser, user) AS user, @ blob.rid IN leaf AS leaf, @ bgcolor AS bgColor, @ event.type AS eventType, @@ -921,16 +921,32 @@ blob_zero(&out); while( db_step(&q)==SQLITE_ROW ){ const char *zFN = db_column_text(&q, 0); blob_appendf(&out, "%s%z%h", zSep, href("%R/finfo?name=%t", zFN), zFN); +#ifdef LANG_RU + zSep = " или "; +#elif LANG_EN zSep = " or "; +#endif } db_finalize(&q); return blob_str(&out); } +#ifdef LANG_RU +const char* numberSuffix(int number, const char* s1, const char* s24, const char* s590){ + int lastDigit = number % 10; + if(lastDigit == 1 && number != 11) + return s1; + if(lastDigit >= 2 && lastDigit <= 4 && (number < 12 || number > 14)) + return s24; + return s590; +} +#elif LANG_EN +#define numberSuffix(n) (n==1?"":"s") +#endif /* ** WEBPAGE: timeline ** ** Query parameters: @@ -1045,11 +1061,17 @@ }else{ zUses = 0; } } - style_header("Timeline"); + style_header( +#ifdef LANG_RU + "События" +#elif LANG_EN + "Timeline" +#endif + ); login_anonymous_available(); timeline_temp_table(); blob_zero(&sql); blob_zero(&desc); blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1); @@ -1082,13 +1104,25 @@ blob_appendf(&sql, ",%d", p->rid); p = p->u.pTo; } blob_append(&sql, ")", -1); path_reset(); - blob_append(&desc, "All nodes on the path from ", -1); + blob_append(&desc, +#ifdef LANG_RU + "Все узлы с путём от ", +#elif LANG_EN + "All nodes on the path from ", +#endif + -1); blob_appendf(&desc, "%z%h", href("%R/info/%h", zFrom), zFrom); - blob_append(&desc, " and ", -1); + blob_append(&desc, +#ifdef LANG_RU + " до " +#elif LANG_EN + " and " +#endif + , -1); blob_appendf(&desc, "%z[%h]", href("%R/info/%h",zTo), zTo); tmFlags |= TIMELINE_DISJOINT; db_multi_exec("%s", blob_str(&sql)); }else if( (p_rid || d_rid) && g.perm.Read ){ /* If p= or d= is present, ignore all other parameters other than n= */ @@ -1108,26 +1142,48 @@ nd = 0; if( d_rid ){ compute_descendants(d_rid, nEntry+1); nd = db_int(0, "SELECT count(*)-1 FROM ok"); if( nd>=0 ) db_multi_exec("%s", blob_str(&sql)); - if( nd>0 ) blob_appendf(&desc, "%d descendant%s", nd,(1==nd)?"":"s"); + if( nd>0 ) + blob_appendf(&desc, +#ifdef LANG_RU + "%d потом%s", nd, numberSuffix(nd, "ок", "ка", "ков")); +#elif LANG_EN + "%d descendant%s", nd, numberSuffix(nd)); +#endif if( useDividers ) timeline_add_dividers(0, d_rid); db_multi_exec("DELETE FROM ok"); } if( p_rid ){ compute_ancestors(p_rid, nEntry+1, 0); np = db_int(0, "SELECT count(*)-1 FROM ok"); if( np>0 ){ - if( nd>0 ) blob_appendf(&desc, " and "); - blob_appendf(&desc, "%d ancestors", np); + if( nd>0 ) blob_appendf(&desc, +#ifdef LANG_RU + " и " +#elif LANG_EN + " and " +#endif + ); + blob_appendf(&desc, +#ifdef LANG_RU + "%d пред%s", np, numberSuffix(np, "ок", "ка", "ков")); +#elif LANG_EN + "%d ancestor%s", numberSuffix(np)); +#endif db_multi_exec("%s", blob_str(&sql)); } if( d_rid==0 && useDividers ) timeline_add_dividers(0, p_rid); } - blob_appendf(&desc, " of %z[%.10s]", - href("%R/info/%s", zUuid), zUuid); + blob_appendf(&desc, +#ifdef LANG_RU + " %z[%.10s]", +#elif LANG_EN + " of %z[%.10s]", +#endif + href("%R/info/%s", zUuid), zUuid); }else if( f_rid && g.perm.Read ){ /* If f= is present, ignore all other parameters other than n= */ char *zUuid; db_multi_exec( "CREATE TEMP TABLE IF NOT EXISTS ok(rid INTEGER PRIMARY KEY);" @@ -1137,18 +1193,29 @@ f_rid, f_rid, f_rid ); blob_appendf(&sql, " AND event.objid IN ok"); db_multi_exec("%s", blob_str(&sql)); if( useDividers ) timeline_add_dividers(0, f_rid); - blob_appendf(&desc, "Parents and children of check-in "); + blob_appendf(&desc, +#ifdef LANG_RU + "Предки и потомки фиксации " +#elif LANG_EN + "Parents and children of check-in " +#endif + ); zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", f_rid); blob_appendf(&desc, "%z[%.10s]", href("%R/info/%s", zUuid), zUuid); tmFlags |= TIMELINE_DISJOINT; }else{ /* Otherwise, a timeline based on a span of time */ int n; - const char *zEType = "timeline item"; + const char *zEType = +#ifdef LANG_RU + "событие"; +#elif LANG_EN + "timeline item"; +#endif char *zDate; char *zNEntry = mprintf("%d", nEntry); url_add_parameter(&url, "n", zNEntry); if( zUses ){ blob_appendf(&sql, " AND event.objid IN usesfile "); @@ -1281,88 +1348,204 @@ } blob_appendf(&sql, " LIMIT %d", nEntry); db_multi_exec("%s", blob_str(&sql)); n = db_int(0, "SELECT count(*) FROM timeline WHERE etype!='div' /*scan*/"); - if( zAfter==0 && zBefore==0 && zCirca==0 ){ - blob_appendf(&desc, "%d most recent %ss", n, zEType); - }else{ - blob_appendf(&desc, "%d %ss", n, zEType); + { +#ifdef LANG_RU + const char* rZEtype; + const char* rSuffix; + const char* rLastTitleSuffix = numberSuffix(n, "яя", "ие", "их"); + switch(zEType[0]){ + case 'c': /*check-in*/ + rZEtype = "фиксаци"; + rSuffix = numberSuffix(n, "я", "и", "й"); + break; + case 'w': /*wiki-edit*/ + rZEtype = "вики-прав"; + rSuffix = numberSuffix(n, "ка", "ки", "ок"); + break; + case 't': /*tiket-change*/ + rZEtype = "задач"; + rSuffix = numberSuffix(n, "а", "и", ""); + break; + case 'e': /*events*/ + rZEtype = "новост"; + rSuffix = numberSuffix(n, "ь", "и", "ей"); + break; + default: + rZEtype = "событи"; + rSuffix = numberSuffix(n, "е", "я", "й"); + rLastTitleSuffix = numberSuffix(n, "ее", "их", "их"); + } +#endif + if( zAfter==0 && zBefore==0 && zCirca==0 ){ + #ifdef LANG_RU + blob_appendf(&desc, "%d последн%s %s%s", n, rLastTitleSuffix, rZEtype, rSuffix); +#elif LANG_EN + blob_appendf(&desc, "%d most recent %ss", n, zEType); +#endif + }else{ +#ifdef LANG_RU + blob_appendf(&desc, "%d %s%s", n, rZEtype, rSuffix); +#elif LANG_EN + blob_appendf(&desc, "%d %ss", n, zEType); +#endif + } } if( zUses ){ char *zFilenames = names_of_file(zUses); blob_appendf(&desc, " using file %s version %z%S", zFilenames, href("%R/artifact/%S",zUses), zUses); tmFlags |= TIMELINE_DISJOINT; } if( zUser ){ +#ifdef LANG_RU + blob_appendf(&desc, " пользователя %h", zUser); +#elif LANG_EN blob_appendf(&desc, " by user %h", zUser); +#endif tmFlags |= TIMELINE_DISJOINT; } if( zTagName ){ +#ifdef LANG_RU + blob_appendf(&desc, " с тэгом \"%h\"", zTagName); +#elif LANG_EN blob_appendf(&desc, " tagged with \"%h\"", zTagName); +#endif tmFlags |= TIMELINE_DISJOINT; }else if( zBrName ){ +#ifdef LANG_RU + blob_appendf(&desc, " ветки \"%h\"", zBrName); +#elif LANG_EN blob_appendf(&desc, " related to \"%h\"", zBrName); +#endif tmFlags |= TIMELINE_DISJOINT; } if( rAfter>0.0 ){ if( rBefore>0.0 ){ - blob_appendf(&desc, " occurring between %h and %h.
    ", - zAfter, zBefore); + blob_appendf(&desc, +#ifdef LANG_RU + " между %h and %h.
    " +#elif LANG_EN + " occurring between %h and %h.
    " +#endif + , zAfter, zBefore); }else{ - blob_appendf(&desc, " occurring on or after %h.
    ", zAfter); + blob_appendf(&desc, +#ifdef LANG_RU + " после %h.
    " +#elif LANG_EN + " occurring on or after %h.
    " +#endif + , zAfter); } }else if( rBefore>0.0 ){ +#ifdef LANG_RU + blob_appendf(&desc, " до %h.
    ", zBefore); +#elif LANG_EN blob_appendf(&desc, " occurring on or before %h.
    ", zBefore); +#endif }else if( rCirca>0.0 ){ +#ifdef LANG_RU + blob_appendf(&desc, " около %h.
    ", zCirca); +#elif LANG_EN blob_appendf(&desc, " occurring around %h.
    ", zCirca); +#endif } if( zSearch ){ +#ifdef LANG_RU + blob_appendf(&desc, " похожие на \"%h\"", zSearch); +#elif LANG_EN blob_appendf(&desc, " matching \"%h\"", zSearch); +#endif } if( g.perm.Hyperlink ){ if( zAfter || n==nEntry ){ zDate = db_text(0, "SELECT min(timestamp) FROM timeline /*scan*/"); +#ifdef LANG_RU + timeline_submenu(&url, "Ранее", "b", zDate, "a"); +#elif LANG_EN timeline_submenu(&url, "Older", "b", zDate, "a"); +#endif free(zDate); } if( zBefore || (zAfter && n==nEntry) ){ zDate = db_text(0, "SELECT max(timestamp) FROM timeline /*scan*/"); +#ifdef LANG_RU + timeline_submenu(&url, "Новее", "a", zDate, "b"); +#elif LANG_EN timeline_submenu(&url, "Newer", "a", zDate, "b"); +#endif free(zDate); }else if( tagid==0 ){ if( zType[0]!='a' ){ +#ifdef LANG_RU + timeline_submenu(&url, "Все типы", "y", "all", 0); +#elif LANG_EN timeline_submenu(&url, "All Types", "y", "all", 0); +#endif } if( zType[0]!='w' && g.perm.RdWiki ){ +#ifdef LANG_RU + timeline_submenu(&url, "Только вики-правки", "y", "w", 0); +#elif LANG_EN timeline_submenu(&url, "Wiki Only", "y", "w", 0); +#endif } if( zType[0]!='c' && g.perm.Read ){ +#ifdef LANG_RU + timeline_submenu(&url, "Только фиксации", "y", "ci", 0); +#elif LANG_EN timeline_submenu(&url, "Checkins Only", "y", "ci", 0); +#endif } if( zType[0]!='t' && g.perm.RdTkt ){ +#ifdef LANG_RU + timeline_submenu(&url, "Только задачи", "y", "t", 0); +#elif LANG_EN timeline_submenu(&url, "Tickets Only", "y", "t", 0); +#endif } if( zType[0]!='e' && g.perm.RdWiki ){ +#ifdef LANG_RU + timeline_submenu(&url, "Только новости", "y", "e", 0); +#elif LANG_EN timeline_submenu(&url, "Events Only", "y", "e", 0); +#endif } if( zType[0]!='g' && g.perm.Read ){ timeline_submenu(&url, "Tags Only", "y", "g", 0); } } if( nEntry>20 ){ +#ifdef LANG_RU + timeline_submenu(&url, "20 событий", "n", "20", 0); +#elif LANG_EN timeline_submenu(&url, "20 Entries", "n", "20", 0); +#endif } if( nEntry<200 ){ +#ifdef LANG_RU + timeline_submenu(&url, "200 событий", "n", "200", 0); +#elif LANG_EN timeline_submenu(&url, "200 Entries", "n", "200", 0); +#endif } if( zType[0]=='a' || zType[0]=='c' ){ if( tmFlags & TIMELINE_FCHANGES ){ +#ifdef LANG_RU + timeline_submenu(&url, "Не показывать файлы", "fc", 0, 0); +#elif LANG_EN timeline_submenu(&url, "Hide Files", "fc", 0, 0); +#endif }else{ +#ifdef LANG_RU + timeline_submenu(&url, "Показывать файлы", "fc", "", 0); +#elif LANG_EN timeline_submenu(&url, "Show Files", "fc", "", 0); +#endif } } } } if( P("showsql") ){ Index: src/tkt.c ================================================================== --- src/tkt.c +++ src/tkt.c @@ -422,37 +422,82 @@ const char *zUuid = PD("name",""); login_check_credentials(); if( !g.perm.RdTkt ){ login_needed(); return; } if( g.perm.WrTkt || g.perm.ApndTkt ){ - style_submenu_element("Edit", "Edit The Ticket", "%s/tktedit?name=%T", + style_submenu_element( +#ifdef LANG_RU + "Правка", "Изменить задачу", +#elif LANG_EN + "Edit", "Edit The Ticket", +#endif + "%s/tktedit?name=%T", g.zTop, PD("name","")); } if( g.perm.Hyperlink ){ - style_submenu_element("History", "History Of This Ticket", + style_submenu_element( +#ifdef LANG_RU + "История", "Исория задачи", +#elif LANG_EN + "History", "History Of This Ticket", +#endif "%s/tkthistory/%T", g.zTop, zUuid); - style_submenu_element("Timeline", "Timeline Of This Ticket", + style_submenu_element( +#ifdef LANG_RU + "События", "События по этой задаче", +#elif LANG_EN + "Timeline", "Timeline Of This Ticket", +#endif "%s/tkttimeline/%T", g.zTop, zUuid); - style_submenu_element("Check-ins", "Check-ins Of This Ticket", + style_submenu_element( +#ifdef LANG_RU + "Фиксации", "Фиксации по этой задаче", +#elif LANG_EN + "Check-ins", "Check-ins Of This Ticket", +#endif "%s/tkttimeline/%T?y=ci", g.zTop, zUuid); } if( g.perm.NewTkt ){ - style_submenu_element("New Ticket", "Create a new ticket", + style_submenu_element( +#ifdef LANG_RU + "Новая задача", "Создать новую задачу", +#elif LANG_EN + "New Ticket", "Create a new ticket", +#endif "%s/tktnew", g.zTop); } if( g.perm.ApndTkt && g.perm.Attach ){ - style_submenu_element("Attach", "Add An Attachment", + style_submenu_element( +#ifdef LANG_RU + "Добавить файл", "Добавить файл к задаче", +#elif LANG_EN + "Attach", "Add An Attachment", +#endif "%s/attachadd?tkt=%T&from=%s/tktview/%t", g.zTop, zUuid, g.zTop, zUuid); } if( P("plaintext") ){ +#ifdef LANG_RU + style_submenu_element("Форматировано", "Форматировано", "%R/tktview/%S", zUuid); +#elif LANG_EN style_submenu_element("Formatted", "Formatted", "%R/tktview/%S", zUuid); +#endif }else{ +#ifdef LANG_RU + style_submenu_element("Текстом", "Текстом", +#elif LANG_EN style_submenu_element("Plaintext", "Plaintext", +#endif "%R/tktview/%S?plaintext", zUuid); } - style_header("View Ticket"); + style_header( +#ifdef LANG_RU + "Просмотр задачи" +#elif LANG_EN + "View Ticket" +#endif + ); if( g.thTrace ) Th_Trace("BEGIN_TKTVIEW
    \n", -1); ticket_init(); initializeVariablesFromCGI(); getAllTicketFields(); initializeVariablesFromDb(); @@ -464,11 +509,15 @@ zFullName = db_text(0, "SELECT tkt_uuid FROM ticket" " WHERE tkt_uuid GLOB '%q*'", zUuid); if( zFullName ){ +#ifdef LANG_RU + attachment_list(zFullName, "

    Вложения: